Instrument the dwc3 OTG path to test the guard
The guard alone did not fix flare-edge#160: with dr_mode="otg" and the live re-init skipped, the controller still died 14s after carrier-on under load (carrier 54.1s, first Tx timeout 63.4s, HC died 68.4s). That means either the OTG event path is not the trigger, or the harm comes from somewhere else in it. dr_mode="host" removes far more than this one call: it also skips dwc3_otgregs_init() and hands port-power control to xHCI instead of the OTG block. IRQ 47 is shared between dwc3-otg and xhci-hcd, so /proc/interrupts cannot say whether OTG events fire at all. CONFIG_DYNAMIC_DEBUG is off, so dev_dbg is compiled out and invisible. So this build logs, ratelimited and always compiled: - every OTG hardware event with its OEVT value, role and restart flag - each time the guard skips a re-init on a live host Run under load, that answers whether the OTG path is even active during the failure window, instead of guessing a third patch. Also worth measuring: load accelerates this dramatically -- 452-587s idle versus 9-14s under line-rate traffic -- so idle soaks are not comparable to load tests and earlier comparisons need re-reading with that in mind. Refs flare-edge#160 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MVGTC78dgCGfRANNKjoPea
This commit is contained in:
@@ -1,40 +1,33 @@
|
||||
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
|
||||
--- a/drivers/usb/dwc3/drd.c
|
||||
+++ b/drivers/usb/dwc3/drd.c
|
||||
@@ -55,7 +55,35 @@
|
||||
@@ -55,7 +55,17 @@
|
||||
|
||||
spin_lock(&dwc->lock);
|
||||
if (dwc->otg_restart_host) {
|
||||
- dwc3_otg_host_init(dwc);
|
||||
+ /*
|
||||
+ * dwc3_otg_host_init() is documented just above its definition as
|
||||
+ * "should be called before Host controller driver is started": it
|
||||
+ * rewrites OCTL/OCFG, touches GUSB2PHYCFG and re-asserts port power
|
||||
+ * (OCTL.PrtPwrCtl). Doing that to a controller that is already
|
||||
+ * running corrupts an in-flight command.
|
||||
+ *
|
||||
+ * But otg_restart_host is set in dwc3_otg_irq() ONLY when
|
||||
+ * current_otg_role is already DWC3_OTG_ROLE_HOST, so this path
|
||||
+ * always ran it against a live host -- the exact condition the
|
||||
+ * comment forbids. Observed on the RV1106 86-panel as the xHCI
|
||||
+ * controller failing to answer a Stop Endpoint command, after which
|
||||
+ * xhci-hcd declares it dead and tears the bus down: an r8152 NIC
|
||||
+ * would stall a transfer and the controller died 8 times out of 8
|
||||
+ * between 452s and 587s. (flare-edge#160)
|
||||
+ *
|
||||
+ * On this board the event is always spurious: the dwc3 node
|
||||
+ * deliberately carries no extcon (wiring it pins the role to
|
||||
+ * peripheral on D1-modded panels) and CONIDSTS reads 0, so the role
|
||||
+ * cannot legitimately change while host is current. Skip the
|
||||
+ * re-init in that case. dwc3_set_mode() below still re-evaluates
|
||||
+ * the role, and if it has genuinely changed dwc3_otg_update() does
|
||||
+ * a proper dwc3_host_exit() before re-initialising.
|
||||
+ * flare-edge#160: dwc3_otg_host_init() is documented as "should be
|
||||
+ * called before Host controller driver is started" but this path
|
||||
+ * only ever runs while current_otg_role is already HOST. Skip it
|
||||
+ * on a live host and record that we did.
|
||||
+ */
|
||||
+ if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST)
|
||||
+ dev_dbg(dwc->dev,
|
||||
+ "OTG event while host is live; skipping host re-init\n");
|
||||
+ dev_warn_ratelimited(dwc->dev,
|
||||
+ "OTGDIAG skipped host re-init on live host\n");
|
||||
+ else
|
||||
+ dwc3_otg_host_init(dwc);
|
||||
dwc->otg_restart_host = false;
|
||||
}
|
||||
|
||||
@@ -83,6 +93,10 @@
|
||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST &&
|
||||
!(reg & DWC3_OEVT_DEVICEMODE))
|
||||
dwc->otg_restart_host = true;
|
||||
+ /* flare-edge#160 diagnostic: is the OTG event path active at all? */
|
||||
+ dev_warn_ratelimited(dwc->dev,
|
||||
+ "OTGDIAG irq OEVT=0x%08x role=%u restart=%d\n",
|
||||
+ reg, dwc->current_otg_role, dwc->otg_restart_host);
|
||||
dwc3_writel(dwc, DWC3_OEVT, reg);
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user