Problem Summary: Problem has been observed generally with PM states where VBUS goes off during suspend. There are some SS USB devices which takes slightly longer time for link training compared to many others. Such devices fails to reconnect with same old address which was associated with it before suspend. When system resumes, at some point of time (dpm_run_callback-> usb_dev_resume->usb_resume->usb_resume_both->usb_resume_device-> usb_port_resume) SW reads hub status. If device is present, then it finishes port resume and re-enumerates device with same address. If device is not present, then SW thinks that device was removed during suspend and therefore does logical disconnection and removes all the resource allocated for this device. Now, if I put sufficient delay just before root hub status read in usb_resume_device then, SW sees always that device is present. In normal course(without any delay) SW sees that no device is present and then SW removes all resource associated with the device at this port. In the latter case, after sometime, device says that hey I am here, now host enumerates it, but with new address. Problem had been reproduced when I connect verbatim USB3.0 hard disc with my STiH407 XHCI host running with 3.10 kernel. I see that similar problem has been reported here. https://bugzilla.kernel.org/show_bug.cgi?id=53211 Reading above it seems that bug was not in 3.6.6 and was present in 3.8 and again it was not present for some in 3.12.6, while it was present for few others. I tested with 3.13-FC19 with i686 desktop, problem was still there. However, I was failed to reproduce it with 3.16-RC4 running at same i686 machine. I would say it is just a random observation. Problem for few devices is always there, as I am unable to find a proper fix for the issue. So, now question is what should be the amount of delay as per USB specification so that host is always able to recognize suspended device after resume. -- XHCI specs 4.19.4 says that when Link training is successful, port sets CSC bit to 1 (root hub controller says that device is present). So the delay should be the maximum amount of time from the moment when host enables VBUS to the moment it is able to perform Link Training. Unfortunately, I could not find any direct statement in USB specification for such timeout. Since path from VBUS on to U0 will follow, like this Rx.Detect.Quite->Rx.Detect.Active->Polling.LFPS-> Polling.ExEQ->Polling.Active->Polling.Configuration->Polling.Idle->U0, therefore we can set maximum delay as tRxDetectQuietTimeout (12 ms) + tPollingLFPSTimeout (360 ms) + tPollingActiveTimeout (12 ms) + tPollingConfigurationTimeout (12 ms) + tPollingIdleTimeout (2 ms) (398 =~ 400 ms). This patch implements above delay, but only for SS device and when persist is enabled. After every 10 ms SW reads port status and if it is enabled, SW exits delay loop. So, for the good device overhead is just the time to execute hub_port_status, while for the bad device penalty could be as long as 400 mS. Results: Verbatim USB SS hard disk connected with STiH407 USB host running 3.10 Kernel resumes in 461 msecs without this patch, but hard disk is assigned a new device address. Same system resumes in 790 msecs with this patch, but with old device address. Signed-off-by: Pratyush Anand <pratyush.anand@xxxxxx> --- drivers/usb/core/hub.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 21b99b4..93495b7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3245,6 +3245,39 @@ static int finish_port_resume(struct usb_device *udev) } /* + * There are some SS USB devices which takes longer time for link training. + * XHCI specs 4.19.4 says that when Link training is successful, port + * sets CSC bit to 1. So if SW reads port status before successful link + * training, then it will not find device to be present. + * Successful SS link training follows Rx.Detect.Quite->Rx.Detect.Active-> + * Polling.LFPS->Polling.ExEQ->Polling.Active->Polling.Configuration-> + * Polling.Idle->U0. + * Following routine waits for either till port is enable or a timeout + * of 400 ms whichever is earlier [tRxDetectQuietTimeout (12 ms) + + * tPollingLFPSTimeout (360 ms) + tPollingActiveTimeout (12 ms) + + * tPollingConfigurationTimeout (12 ms) + * tPollingIdleTimeout (2 ms)] + * + * This routine should only be called when persist is enabled for a SS + * device. + */ +static int wait_for_ss_port_enable(struct usb_device *udev, + struct usb_hub *hub, + int *port1, + u16 *portchange, + u16 *portstatus) +{ + int status, wait_count_20ms = 0; + + while (wait_count_20ms++ < 20) { + status = hub_port_status(hub, *port1, portstatus, portchange); + if (status || *portstatus & USB_PORT_STAT_CONNECTION) + return status; + msleep(20); + } + return hub_port_status(hub, *port1, portstatus, portchange); +} + +/* * usb_port_resume - re-activate a suspended usb device's upstream port * @udev: device to re-activate, not a root hub * Context: must be able to sleep; device not locked; pm locks held @@ -3340,6 +3373,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } } + if (udev->persist_enabled && hub_is_superspeed(hub->hdev)) + status = wait_for_ss_port_enable(udev, hub, &port1, &portchange, + &portstatus); + status = check_port_resume_type(udev, hub, port1, status, portchange, portstatus); if (status == 0) -- 1.8.3.1 -- 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