mctp-controller-init-v3: Adds MCTP init for a new platform

Inherits from mctp-controller-init-v2 with modifications specific
to the new platform bringup.
This should be consolidated with v2. v3 was introduced to reduce
testing scope at the early phase.

Tested: Verified working on the new platform.
fusion2: N/A
Google-Bug-Id: 487277222
Change-Id: Ieeb7ec0d3063d558b966e2bff74ccbc7eb1fa17c
Signed-off-by: Luka Strizic <lstrz@google.com>
diff --git a/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3.bb b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3.bb
new file mode 100644
index 0000000..e57a3f8
--- /dev/null
+++ b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3.bb
@@ -0,0 +1,42 @@
+SUMMARY = "MCTP Controller Init Service V2"
+DESCRIPTION = "Provides a service that brings up local MCTP EID for all MCTP interfaces"
+PR = "r1"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
+
+S = "${WORKDIR}"
+
+inherit systemd
+
+SRC_URI =  " \
+    file://mctpusb-rename.sh \
+    file://mctp-controller-init.sh \
+    file://mctp-controller-init.service \
+    file://81-mctp-link-up.rules \
+    file://restart-mctp-controller-init.service \
+"
+
+DEPENDS += "systemd"
+RDEPENDS:${PN} += " \
+    bash \
+    mctp \
+    udev \
+"
+
+do_install() {
+    install -d ${D}${bindir}
+    install -m 0755 ${WORKDIR}/mctpusb-rename.sh ${D}${bindir}/
+    install -m 0755 ${WORKDIR}/mctp-controller-init.sh ${D}${bindir}/
+
+    install -d ${D}${systemd_system_unitdir}
+    install -m 0644 ${WORKDIR}/mctp-controller-init.service ${D}${systemd_system_unitdir}/
+    install -m 0644 ${WORKDIR}/restart-mctp-controller-init.service ${D}${systemd_system_unitdir}/
+
+
+    install -d ${D}${sysconfdir}/udev/rules.d
+    install -m 0644 ${WORKDIR}/81-mctp-link-up.rules ${D}${sysconfdir}/udev/rules.d
+}
+
+SYSTEMD_PACKAGES = "${PN}"
+
+SYSTEMD_SERVICE:${PN} = " mctp-controller-init.service restart-mctp-controller-init.service"
diff --git a/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/81-mctp-link-up.rules b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/81-mctp-link-up.rules
new file mode 100644
index 0000000..dc6ecf6
--- /dev/null
+++ b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/81-mctp-link-up.rules
@@ -0,0 +1,20 @@
+ACTION=="add", \
+SUBSYSTEM=="net", \
+KERNEL=="mctpusb*", \
+ENV{ID_PATH}=="?*", \
+PROGRAM="/usr/bin/mctpusb-rename.sh $env{ID_PATH}", \
+NAME="mctpusb1_%c", \
+TAG+="systemd", \
+RUN+="/usr/bin/systemctl restart --no-block mctp-controller-init.service"
+
+ACTION=="add", \
+SUBSYSTEM=="net", \
+KERNEL=="mctpi2c*", \
+NAME="%E{INTERFACE}", \
+RUN+="/bin/sh -c ' /usr/bin/mctp link set $env{INTERFACE} up; /usr/bin/mctp addr add 100 dev $env{INTERFACE}; /usr/bin/mctp link set $env{INTERFACE} mtu 68'"
+
+ACTION=="add", \
+SUBSYSTEM=="net", \
+KERNEL=="mctpspi*", \
+NAME="%E{INTERFACE}", \
+RUN+="/bin/sh -c ' /usr/bin/mctp link set $env{INTERFACE} up;  /usr/bin/mctp addr add 30 dev $env{INTERFACE}; /usr/sbin/modprobe /usr/lib/modules/*/kernel/drivers/spi/fmc_spi.ko '"
diff --git a/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctp-controller-init.service b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctp-controller-init.service
new file mode 100644
index 0000000..086ec1c
--- /dev/null
+++ b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctp-controller-init.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Initialize mctp controller for all MCTP interfaces
+Before=mctpd.service
+StartLimitBurst=3
+StartLimitIntervalSec=4
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/mctp-controller-init.sh
+TimeoutStartSec=60
+
+[Install]
+WantedBy=mctp.target
diff --git a/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctp-controller-init.sh b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctp-controller-init.sh
new file mode 100644
index 0000000..bce7372
--- /dev/null
+++ b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctp-controller-init.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+# This script will bring up all MCTP link (i2c, i3c, USB), and assign local MCTP address (from 254 to lower EID) for them.
+
+# Use single MCTP network ID 1 by default
+readonly USE_SINGLE_NETWORK_ID='true'
+
+get_next_net()
+{
+    existing=$(mctp link | awk '{print $8}')
+    net=1
+    while true; do
+        if echo "$existing" | grep -E "^${net}$" >/dev/null; then
+            net=$((net + 1))
+        else
+            echo ${net}
+            return
+        fi
+    done
+}
+
+# Search unused EID from 254 to lower addresses
+get_next_eid()
+{
+    if [ $# -ne 1 ]; then
+      echo "Error: missing network ID parameter."
+      exit 1
+    fi
+
+    net="$1"
+    existing=$(mctp addr | grep "net $net" | awk '{print $2}')
+
+    # Valid EID range: [8-254]
+    eid=254
+    while [ "$eid" -ge 8 ]; do
+        if echo "$existing" | grep -E "^${eid}$" >/dev/null; then
+            eid=$((eid - 1))
+        else
+            echo $eid
+            return
+        fi
+    done
+
+    echo "Error: all EID range [8-254] of net ${net} are already assigned"
+    exit 1
+}
+
+# Wait 1 second for udevd to fully release the interface rename lock
+sleep 1
+
+mctp_ifname_lines=$(mctp link | grep -v 'dev lo')
+
+while IFS= read -r line; do
+  if [[ $line =~ ^dev\ (mctp[a-z0-9]+)\ index ]]; then
+    ifname="${BASH_REMATCH[1]}"
+
+    # Bring up MCTP link if it is down
+    if [[ "$line" == *"down" ]]; then
+      if ${USE_SINGLE_NETWORK_ID}; then
+        net=1
+      else
+        net=$(get_next_net)
+      fi
+
+      echo "mctp link set ${ifname} up network $net"
+      mctp link set "${ifname}" up network "${net}"
+    fi
+
+    # Assign local MCTP EID if it has no address yet
+    mctp_addr_line=$(mctp addr show "${ifname}" )
+    if [[ ${mctp_addr_line} != *"eid "* ]]; then
+      eid=$(get_next_eid "${net}")
+      echo "mctp addr add ${eid} dev ${ifname}"
+      mctp addr add "${eid}" dev "${ifname}"
+    fi
+  fi
+
+done <<< "${mctp_ifname_lines}"
+
diff --git a/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctpusb-rename.sh b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctpusb-rename.sh
new file mode 100644
index 0000000..30b9652
--- /dev/null
+++ b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/mctpusb-rename.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Safely extracts the USB topology string for udev.
+# Input Example: platform-1e6a3000.usb-usb-0:1.2.2.1:1.0
+# Output Example: 1_2_2_1
+
+if [ -z "$1" ]; then
+    exit 1
+fi
+
+echo "$1" | cut -d: -f2 | tr '.' '_'
diff --git a/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/restart-mctp-controller-init.service b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/restart-mctp-controller-init.service
new file mode 100644
index 0000000..a04bd48
--- /dev/null
+++ b/recipes-connectivity/mctp-controller-init/mctp-controller-init-v3/restart-mctp-controller-init.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=A helper service to restart mctp-controller-init.service
+
+[Service]
+# 'oneshot' means it runs the command and then exits
+Type=oneshot
+# The actual command you want to run
+ExecStart=/usr/bin/systemctl restart mctp-controller-init.service