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