linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Rob Weber <rob@gnarbox.com>
To: felipe.balbi@linux.intel.com
Cc: linux-usb@vger.kernel.org
Subject: dwc3 Disable Compliance Mode
Date: Wed, 10 Jul 2019 16:01:10 -0700	[thread overview]
Message-ID: <20190710230110.GA3188@coops> (raw)

[-- Attachment #1: Type: text/plain, Size: 1863 bytes --]

Hi Felipe,

I hope you are doing well. My team and I are frequently experiencing an
issue with the dwc3 in our CherryTrail SoC where we encounter an LFPS
Polling timeout while our device is being enumerated.

We configured the dwc3 as an ethernet gadget using configfs and the ecm
and RNDIS functions. The dwc3 transitions to U3 after configuration as
expected. Only once we connect our device to a USB host do we see the
link state transition to Polling. We are assuming LFPS Polling times
out because the link_state file in debugfs shows the link has
transitioned to compliance mode only after entering LFPS.Polling, and we
recently learned that compliance mode is triggered by a timeout during
LFPS.Polling.

This issue is not 100% reproducible, but is occuring rather frequently
at the moment. We're unsure of the root cause of the issue as well. One
culprit might be the USB SuperSpeed Redriver we use in our design.

We would like to disable compliance mode in the meantime to allow other
team members to continue developing and testing USB device mode features
while we dig into the root cause of the issue. Is there a proper way to
disable compliance mode entirely?

If not, is there some mechanism we could implement to reset the
dwc3 when we enter compliance mode? I attempted some sort of mechanism
to reset the link state, but it does not seem to help the issue. I've
attached my patch and the trace events for my attempted workaround to
this email. My initial approach was to transition the link from
Compliance -> SS.Disabled -> Rx.Detect when we detect we've entered
compliance mode. The traces show that the dwc3 just enters LFPS.Polling
and subsequently enters compliance mode, despite the link being reset.

Do you have any ideas on how we might work around compliance mode in the
meantime?

Thanks in advance for your input!

Cheers,
Rob Weber

[-- Attachment #2: dwc3-compliance-recovery.patch --]
[-- Type: text/x-diff, Size: 4087 bytes --]

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 53b26e9..07d8412 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -48,6 +48,91 @@
 #include "debug.h"
 
 #define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */
+#define COMP_MODE_RECOVERY_MSECS 2000
+
+static void compliance_mode_recovery(unsigned long arg)
+{
+	struct dwc3 *dwc3;
+	int state;
+	unsigned long flags;
+
+	dwc3 = (struct dwc3 *) arg;
+
+	dwc3_trace(trace_dwc3_core, "Tick! Checking for compliance mode\n");
+
+	// Read link state
+
+	spin_lock_irqsave(&dwc3->lock, flags);
+	state = dwc3_gadget_get_link_state(dwc3);
+
+	// if in compliance mode or loopback mode, we need to revert the link to normal operation
+	// Couple options for resetting link state
+	// * setting link state to RESET - NOT WORKING
+	// * setting linsk state to SS disabled or RX detect
+	// * try a hard reset (we're afraid we will have to reconfigure the gadget with this method)
+	if (state == DWC3_LINK_STATE_CMPLY || state == DWC3_LINK_STATE_LPBK) {
+		dwc3_trace(trace_dwc3_core, "Compliance Mode detected. Attempting recovery routine\n");
+		printk("dwc3 compliance mode detected. Attempting recovery\n");
+
+		state = dwc3_gadget_set_link_state(dwc3, DWC3_LINK_STATE_SS_DIS);
+		if (state < 0) {
+			dwc3_trace(trace_dwc3_core, "Compliance -> SS.Disabled transition failed: %d (Timed out?)\n", state);
+			printk("Compliance -> SS.Disabled transition failed: %d (Timed out?)\n", state);
+
+		}
+
+		udelay(1000);
+		state = dwc3_gadget_set_link_state(dwc3, DWC3_LINK_STATE_RX_DET);
+		if (state < 0) {
+			dwc3_trace(trace_dwc3_core, "SS.Disabled -> Rx.Detect transition failed: %d (Timed out?)\n", state);
+			printk("SS.Disabled -> Rx.Detect transition failed: %d (Timed out?)\n", state);
+		}
+	}
+
+	spin_unlock_irqrestore(&dwc3->lock, flags);
+/*
+	struct *xhci;
+	struct usb_hcd *hcd;
+	u32 temp;
+	int i;
+
+	xhci = (struct xhci_hcd *)arg;
+
+	for (i = 0; i < xhci->num_usb3_ports; i++) {
+		temp = xhci_readl(xhci, xhci->usb3_ports[i]);
+		if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {
+			xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n",
+					i + 1);
+			xhci_dbg(xhci, "Attempting Recovery routine!\n");
+			hcd = xhci->shared_hcd;
+
+			if (hcd->state == HC_STATE_SUSPENDED)
+				usb_hcd_resume_root_hub(hcd);
+
+			usb_hcd_poll_rh_status(hcd);
+		}
+	}
+
+	if (xhci->port_status_u0 != ((1 << xhci->num_usb3_ports)-1))
+		mod_timer(&xhci->comp_mode_recovery_timer,
+			jiffies + msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
+*/
+	/* TODO: figure out when we don't need to keep re-enabling this timer anymore */
+	mod_timer(&dwc3->comp_mode_recovery_timer,
+		jiffies + msecs_to_jiffies(COMP_MODE_RECOVERY_MSECS));
+}
+
+static void compliance_mode_recovery_timer_init(struct dwc3 *dwc3)
+{
+	setup_timer(&dwc3->comp_mode_recovery_timer,
+		compliance_mode_recovery, (unsigned long)dwc3);
+
+	dwc3->comp_mode_recovery_timer.expires = jiffies +
+			msecs_to_jiffies(COMP_MODE_RECOVERY_MSECS);
+
+	add_timer(&dwc3->comp_mode_recovery_timer);
+	dwc3_trace(trace_dwc3_core, "Compliance Mode Recovery Timer Initialized.\n");
+}
 
 /**
  * dwc3_get_dr_mode - Validates and sets dr_mode
@@ -612,6 +697,8 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 	usb_phy_set_suspend(dwc->usb3_phy, 1);
 	phy_power_off(dwc->usb2_generic_phy);
 	phy_power_off(dwc->usb3_generic_phy);
+
+	del_timer_sync(&dwc->comp_mode_recovery_timer);
 }
 
 /**
@@ -786,6 +873,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
 		dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
 	}
 
+	/* Enable timer to check for and recover from entering compliance mode */
+	compliance_mode_recovery_timer_init(dwc);
+
 	return 0;
 
 err4:
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index affb3d7..c2c9077 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -979,6 +979,8 @@ struct dwc3 {
 
 	unsigned		tx_de_emphasis_quirk:1;
 	unsigned		tx_de_emphasis:2;
+
+	struct timer_list	comp_mode_recovery_timer;
 };
 
 /* -------------------------------------------------------------------------- */

[-- Attachment #3: dwc3-compliance-workaround.trace.txt --]
[-- Type: text/plain, Size: 2189 bytes --]

# tracer: nop
#
# entries-in-buffer/entries-written: 220/220   #P:4
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
          <idle>-0     [003] ..s1   178.444339: dwc3_core: Tick! Checking for compliance mode

          <idle>-0     [003] d.s2   178.444352: dwc3_core: Compliance Mode detected. Attempting recovery routine

     irq/23-dwc3-1115  [002] d..1   178.445380: dwc3_event: event (00140301): Link Change [SS.Disabled]
     irq/23-dwc3-1115  [002] d..1   178.445826: dwc3_event: event (00150301): Link Change [RX.Detect]
     irq/23-dwc3-1115  [002] d..1   178.445832: dwc3_event: event (00170301): Link Change [Polling]
          <idle>-0     [003] ..s1   180.492293: dwc3_core: Tick! Checking for compliance mode

          <idle>-0     [003] d.s2   180.492306: dwc3_core: Compliance Mode detected. Attempting recovery routine

     irq/23-dwc3-1115  [002] d..1   180.493333: dwc3_event: event (00140301): Link Change [SS.Disabled]
     irq/23-dwc3-1115  [002] d..1   180.493636: dwc3_event: event (00150301): Link Change [RX.Detect]
     irq/23-dwc3-1115  [002] d..1   180.493641: dwc3_event: event (00170301): Link Change [Polling]
          <idle>-0     [003] ..s1   182.540350: dwc3_core: Tick! Checking for compliance mode

          <idle>-0     [003] d.s2   182.540362: dwc3_core: Compliance Mode detected. Attempting recovery routine

     irq/23-dwc3-1115  [002] d..1   182.541392: dwc3_event: event (00140301): Link Change [SS.Disabled]
     irq/23-dwc3-1115  [002] d..1   182.541976: dwc3_event: event (00150301): Link Change [RX.Detect]
     irq/23-dwc3-1115  [002] d..1   182.541982: dwc3_event: event (00170301): Link Change [Polling]
          <idle>-0     [003] .Ns1   184.588211: dwc3_core: Tick! Checking for compliance mode

          <idle>-0     [003] dNs2   184.588232: dwc3_core: Compliance Mode detected. Attempting recovery routine

             reply	other threads:[~2019-07-10 23:01 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-10 23:01 Rob Weber [this message]
2019-07-11  7:37 ` dwc3 Disable Compliance Mode Felipe Balbi
2019-07-12  5:01   ` Rob Weber
2019-07-12  7:15     ` Felipe Balbi
     [not found]       ` <20190715060336.GB30262@coops>
2019-07-15  6:50         ` Felipe Balbi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190710230110.GA3188@coops \
    --to=rob@gnarbox.com \
    --cc=felipe.balbi@linux.intel.com \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).