Re: [Bug 42472] USB 3.0 port does not detect disconnect

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

 



On Wed, Sep 14, 2011 at 11:05:53AM +0200, Harald Brennich wrote:
> Hello Sarah,
> The device may well be buggy. I do not know of it being a prototype,
> it's being sold in Germany. But the manufacturer (LogiLink) does not
> seem to take the trouble to register with USB org, or even define a
> serious product id.

Oh, that's frustrating.  Well, if it's on the market and not some random
prototype, we'll need to make it work.

> However, one thing makes me think that it is primarily a hub issue:
> When I test the device with the hack of clearing the change flags,
> on unplugging the device hub_events calls hub_port_reset for a warm
> reset. In this reset, the hub signals a connect although it just
> signaled the disconnect. The connect only goes away when the reset
> is finished. See entries starting with offset 96.813380 in the
> appended messages. I looks as if the hub toggles the connection
> state when a reset is called.

Ok, I've looked at the xHCI port state diagram, and if you want to
follow along, the spec is here:
	http://www.intel.com/technology/usb/xhcispec.htm

In your last log, after the first hot port reset completes, the port
status register reports:

Sep 13 20:57:24 HATOSH kernel: [   81.797959] xhci_hcd 0000:08:00.0: get port status, actual port 0 status  = 0x6202c0

That decodes to:
 - device disconnected
 - port disabled
 - port reset done
 - link in inactive state
 - port powered
 - connect status change
 - port reset change
 - port link state change

In Figure 35, the only way we can get the port link state to be
"Inactive" is if a serious error occurred on the port, and we go into
the "Error" port state.  The spec says that is caused by some sort of
link layer error, which really could be either on the host side or the
device side.

The Error state description says that the port link state change flag
will be set.  It also says that if a disconnect is reported, the port
will go to the disconnected state.  Since the connect status bit reports
the device is disconnected, that's probably the state the port register
is in.  I'm not sure why it's reporting an Inactive link state rather
than an RxDetect link state though.

That's why I believe the device did disconnect when the hot port reset
failed.  Issuing a warm port reset did seem to help, so I guess we just
need to fix the issue with the connect status change bit not being
cleared.  I notice that it's set after the first hot reset, and I'm not
sure if it will also be set after the warm port reset.

Can you remove the patch that issues the warm port reset and replace it
with the attached one?  Please send me the dmesg with the replaced
patch.

Sarah Sharp
>From 39d660bcd9a50507cd9c4ed71239a122bdb25ab1 Mon Sep 17 00:00:00 2001
From: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Date: Tue, 6 Sep 2011 09:53:01 -0700
Subject: [PATCH] USB: When hot reset for USB3 fails, try warm reset.

When a hot reset (standard USB port reset) fails on a USB 3.0 port, the
host controller is supposed to automatically try a warm port reset.
During this transition, the device will be reported as disconnected, and
the link state will be reported as "Inactive".  If we find a device on a
USB 3.0 hub is disconnected in hub_port_wait_reset (which does the hot
reset), then we should wait for the warm port reset to complete if the
link state is inactive.

This may fix https://bugzilla.kernel.org/show_bug.cgi?id=41752

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Cc: Harald Brennich <harald.brennich@xxxxxx>
---
 drivers/usb/core/hub.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 43 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 96c079d..29b446f 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2034,6 +2034,17 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
 #define HUB_LONG_RESET_TIME	200
 #define HUB_RESET_TIMEOUT	500
 
+static int hub_port_reset(struct usb_hub *hub, int port1,
+			struct usb_device *udev, unsigned int delay, bool warm);
+
+/* Is a USB 3.0 port in the Inactive state? */
+static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus)
+{
+	return hub_is_superspeed(hub->hdev) &&
+		(portstatus & USB_PORT_STAT_LINK_STATE) ==
+		USB_SS_PORT_LS_SS_INACTIVE;
+}
+
 static int hub_port_wait_reset(struct usb_hub *hub, int port1,
 			struct usb_device *udev, unsigned int delay, bool warm)
 {
@@ -2057,6 +2068,38 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
 		 * when the port appears not to be connected.
 		 */
 		if (!warm) {
+			/*
+			 * Some buggy devices can cause an NEC host controller
+			 * to transition to the "Error" state after a hot port
+			 * reset.  This will show up as the port state in
+			 * "Inactive", and the port may also report a
+			 * disconnect.  Forcing a warm port reset seems to make
+			 * the device work.
+			 *
+			 * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
+			 */
+			if (hub_port_inactive(hub, portstatus)) {
+				int ret;
+
+				if ((portchange & USB_PORT_STAT_C_CONNECTION))
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_CONNECTION);
+				if (portchange & USB_PORT_STAT_C_LINK_STATE)
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_PORT_LINK_STATE);
+				if (portchange & USB_PORT_STAT_C_RESET)
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_RESET);
+				dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
+						port1);
+				ret = hub_port_reset(hub, port1,
+						udev, HUB_BH_RESET_TIME,
+						true);
+				if ((portchange & USB_PORT_STAT_C_CONNECTION))
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_CONNECTION);
+				return ret;
+			}
 			/* Device went away? */
 			if (!(portstatus & USB_PORT_STAT_CONNECTION))
 				return -ENOTCONN;
-- 
1.7.4.1


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

  Powered by Linux