[RFC] xhci: Workaround NEC resume issue with SS ports.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The xHCI 0.96 spec (Figure 32) shows that a USB 3.0 roothub port shall
transition to the disconnect state when HCRESET is set.  This state causes
the host controller to enable SuperSpeed terminations and start polling for
USB 3.0 device attach.

However, with some NEC hosts, after system resume when the registers fail to
be restored and the host is reset, USB 3.0 devices do not show up as
connected.  The hypothesis is the state machine never transitioned from
the disabled state to the disconnect state on HCRESET.  Force the host into
the disconnect state by pushing USB 3.0 ports into the RxDetect state.

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Reported-by: Don Zickus <dzickus@xxxxxxxxxx>
---

Don,

Your logs show that the device didn't migrate over to the SuperSpeed
ports, even after the SS port wasn't disabled and the USB 2.0 device was
reset.  So either the device is broken, there's a driver issue
(unlikely, since Andiry and I can get USB 3.0 devices to suspend
properly), or there's a host-side issue.

This is just a hunch, can you try this patch on top of the other
ones I've sent you?  Also, does your USB 3.0 device work after you
unplug and replug it in without the patch (on any port, after making
sure to power cycle it via any external power supplies it has)?  If it
does work, can you check lsusb -v to see if it's working at SuperSpeed?

Working on the assumption that the device does indeed work (and it
should, since it also survives autosuspend), I'm wondering if there's a
host-side bug.  Andiry and I have different (newer) firmware than you,
so it's possible there's an issue with suspend in the old firmware.
Please don't try to update the firmware on the host, as most people have
the 30.21 firmware, and I want to track down this issue, if it is a
firmware issue.

Sarah

 drivers/usb/host/xhci-hub.c |   32 ++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci.c     |    1 +
 drivers/usb/host/xhci.h     |    2 ++
 3 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5d963e3..fea0a9a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -134,6 +134,38 @@ u32 xhci_port_state_to_neutral(u32 state)
 }
 
 /*
+ * The xHCI 0.96 spec (Figure 32) shows that a USB 3.0 roothub port shall
+ * transition to the disconnect state when HCRESET is set.  This state causes
+ * the host controller to enable SuperSpeed terminations and start polling for
+ * USB 3.0 device attach.
+ *
+ * However, with some NEC hosts, after system resume when the registers fail to
+ * be restored and the host is reset, USB 3.0 devices do not show up as
+ * connected.  The hypothesis is the state machine never transitioned from
+ * the disabled state to the disconnect state on HCRESET.  Force the host into
+ * the disconnect state by pushing USB 3.0 ports into the RxDetect state.
+ */
+void xhci_nec_resume_usb3_port_workaround(struct xhci_hcd *xhci)
+{
+	unsigned int i;
+	u32 portsc;
+
+	/* FIXME: Figure out which firmware is broken! */
+	if (!(xhci->quirks & XHCI_NEC_HOST))
+		return;
+
+	for (i = 0; i < xhci->num_usb3_ports; i++) {
+		portsc = xhci_readl(xhci, xhci->usb3_ports[i]);
+		if (portsc & PORT_CONNECT)
+			continue;
+
+		portsc = xhci_port_state_to_neutral(portsc);
+		xhci_writel(xhci, portsc | PORT_LINK_STROBE | GOTO_RXDETECT,
+				xhci->usb3_ports[i]);
+	}
+}
+
+/*
  * find slot id based on port number.
  */
 int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 06fca08..fb8e840 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -762,6 +762,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 		if (!retval)
 			set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 		hcd->state = HC_STATE_SUSPENDED;
+		xhci_nec_resume_usb3_port_workaround(xhci);
 		return retval;
 	}
 
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index e83edc2..bdf1b29 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -273,6 +273,7 @@ struct xhci_op_regs {
 #define XDEV_U0		(0x0 << 5)
 #define XDEV_U3		(0x3 << 5)
 #define XDEV_RESUME	(0xf << 5)
+#define	GOTO_RXDETECT	(0x5 << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER	(1 << 9)
 /* bits 10:13 indicate device speed:
@@ -1514,6 +1515,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
 		char *buf, u16 wLength);
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+void xhci_nec_resume_usb3_port_workaround(struct xhci_hcd *xhci);
 
 #ifdef CONFIG_PM
 int xhci_bus_suspend(struct usb_hcd *hcd);
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux