From cad00a0fa00bd2c90a9f59af08675a7bdd97df05 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Tue, 2 Jun 2026 15:56:44 +0200 Subject: [PATCH] fix(secubox-mesh): cold-reset chip before mt76x2u bind in rebind helper (ref #458) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #459 added the udev rule + simple unbind-btusb / bind-mt76x2u helper. Live testing on gk2 after reboot showed the simple sequence is insufficient — at boot the chip's hardware ROM-patch semaphore is already deadlocked from the first probe attempt, and subsequent bind attempts continue to fail with -110 ETIMEDOUT. Solution : cold-reset the chip via `authorized` 0 → 1 cycle on the parent USB device BEFORE attempting the bind. This re-enumerates the device and clears the semaphore state at the chip-firmware boundary without requiring physical replug. Anti-loop discipline : a `/run/secubox/mt76x2u/.done` marker flips this helper between two modes : - First invocation per device per boot : cold-reset, set marker, exit. (The `authorize 1` re-enumeration triggers a fresh `add` event, which fires this helper again with the marker present.) - Second invocation (re-entrant) : marker present → skip cold-reset, proceed with unbind-btusb / bind-mt76x2u. The chip is now clean. If after cold-reset the kernel's natural driver-match auto-bound the device to mt76x2u (winning the race fresh), the script exits silently (logs "already bound to mt76x2u (auto-bind after cold-reset)"). Marker lives in /run (tmpfs) so reboot naturally resets state. Tested on gk2 v3secubox + 2× MT7632U : after this helper lands, both phyN devices come up automatically at boot without operator action. Follow-up to PR #459 / #458. --- .../secubox-mesh/sbin/secubox-mt76x2u-rebind | 81 ++++++++++++++++--- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/packages/secubox-mesh/sbin/secubox-mt76x2u-rebind b/packages/secubox-mesh/sbin/secubox-mt76x2u-rebind index edb4f32a..fad7fb94 100755 --- a/packages/secubox-mesh/sbin/secubox-mt76x2u-rebind +++ b/packages/secubox-mesh/sbin/secubox-mt76x2u-rebind @@ -6,32 +6,93 @@ # # Called from /etc/udev/rules.d/80-secubox-mt76x2u-priority.rules on # usb_interface add events for the WiFi half (:1.2) of MediaTek MT7632U -# combo BT+WiFi chips. +# combo BT+WiFi chips (0e8d:7632). # -# btusb otherwise claims all 3 interfaces of the combo, deadlocking -# the WiFi half's ROM-patch semaphore. This helper unbinds btusb from -# the WiFi interface and binds mt76x2u — letting it own the hardware -# semaphore cleanly. +# At boot, mt76x2u's FIRST probe attempt typically times out on the +# chip's hardware ROM-patch semaphore (held by an earlier bootloader +# touch or by btusb's concurrent claim). The chip refuses every +# subsequent bind with -110 ETIMEDOUT until cold-reset. +# +# Strategy : USB-device-level `authorized` 0 → 1 cycle COLD-resets the +# chip without physical replug. A `/run/secubox/mt76x2u/.done` +# marker prevents an infinite udev loop : the authorize cycle below +# triggers another `add` event that fires this script again — the +# marker tells the second invocation to skip the cold-reset and just +# do the bind sequence. set -eu KERNEL_DEV="${1:-}" -[ -n "$KERNEL_DEV" ] || exit 0 # no device specified, silent no-op +[ -n "$KERNEL_DEV" ] || exit 0 LOG_TAG="secubox-mt76x2u-rebind" +MARKER_DIR="/run/secubox/mt76x2u" +mkdir -p "$MARKER_DIR" 2>/dev/null || true -# Silent if btusb wasn't claiming this interface (rule still ran on a -# fresh enumeration where btusb hadn't bound yet). +# Resolve parent USB device (strip ":1.2" from interface kdev). +USB_DEV="${KERNEL_DEV%:*}" +USB_DEV_DIR="/sys/bus/usb/devices/$USB_DEV" + +# Sanity : a usb_interface always has a parent usb_device with `authorized`. +[ -e "$USB_DEV_DIR/authorized" ] || { + logger -t "$LOG_TAG" "skip $KERNEL_DEV: no parent usb_device at $USB_DEV_DIR" + exit 0 +} + +# Marker key — use sanitized USB_DEV (turn '/' into '_' to keep it flat). +MARKER="$MARKER_DIR/$(echo "$USB_DEV" | tr '/' '_').done" + +cold_reset=0 +if [ ! -e "$MARKER" ]; then + # First time we see this USB device this boot — cold-reset the chip. + cold_reset=1 +fi + +if [ "$cold_reset" -eq 1 ]; then + logger -t "$LOG_TAG" "cold-resetting $USB_DEV (authorized 0 -> 1)" + # Set marker BEFORE the cycle so the re-entrant invocation triggered + # by `authorized 1` does NOT loop into another cold-reset. + touch "$MARKER" + + echo 0 > "$USB_DEV_DIR/authorized" 2>/dev/null || true + # 2 s : USB stack quiesce + chip semaphore clear. + sleep 2 + echo 1 > "$USB_DEV_DIR/authorized" 2>/dev/null || true + + # 5 s : USB re-enumeration + driver claim race. + # The re-enumeration will trigger this script again via udev with + # the marker present, so we exit here and let the second invocation + # do the bind sequence on a chip that just received a clean cold-boot. + sleep 5 + logger -t "$LOG_TAG" "cold-reset done for $USB_DEV, leaving rebind to re-entrant invocation" + exit 0 +fi + +# Marker present → this is the re-entrant invocation post cold-reset. +# Or it's a hot-plug after first one (which is also fine — the chip +# coming in fresh from a physical plug doesn't need our cold-reset). + +# Unbind btusb if it claimed the WiFi interface. if echo "$KERNEL_DEV" > /sys/bus/usb/drivers/btusb/unbind 2>/dev/null; then logger -t "$LOG_TAG" "unbound btusb from $KERNEL_DEV" fi -# Small delay so the kernel resettles before mt76x2u takes over. +# 1 s : kernel resettles after unbind. sleep 1 +# Check current driver before attempting bind. +DRV=$(readlink "/sys/bus/usb/devices/$KERNEL_DEV/driver" 2>/dev/null | xargs basename 2>/dev/null || echo none) + +if [ "$DRV" = "mt76x2u" ]; then + # Already bound (the auto-bind after cold-reset re-enumeration hit + # mt76x2u first this time). Nothing to do. + logger -t "$LOG_TAG" "$KERNEL_DEV already bound to mt76x2u (auto-bind after cold-reset)" + exit 0 +fi + if echo "$KERNEL_DEV" > /sys/bus/usb/drivers/mt76x2u/bind 2>/dev/null; then logger -t "$LOG_TAG" "bound mt76x2u to $KERNEL_DEV" else - logger -t "$LOG_TAG" "WARN: mt76x2u bind failed on $KERNEL_DEV" + logger -t "$LOG_TAG" "WARN: mt76x2u bind failed on $KERNEL_DEV (currently=$DRV)" exit 1 fi