usb: Add connected retry on resume for non SS devices

Currently usb_port_resume waits for up to 2 seconds for CONNECT
status for SS devices only. This change will do the same thing for
non-SS devices even though the reason is a little different. This
will fix an issue where VBUS is turned off during system wide
"suspend to ram" and some 2.0 devices take greater than the current
max of 100ms to show connected after VBUS is enabled. This is most
commonly seen on hard drive based devices and USB3.0 devices plugged
into a 2.0 only port.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Al Cooper 2015-12-02 14:55:07 -05:00 committed by Greg Kroah-Hartman
parent 498378d9d2
commit 6b82b1223e
1 changed files with 10 additions and 6 deletions

View File

@ -3304,7 +3304,7 @@ static int finish_port_resume(struct usb_device *udev)
/*
* There are some SS USB devices which take 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
* sets CCS bit to 1. So if SW reads port status before successful link
* training, then it will not find device to be present.
* USB Analyzer log with such buggy devices show that in some cases
* device switch on the RX termination after long delay of host enabling
@ -3315,14 +3315,17 @@ static int finish_port_resume(struct usb_device *udev)
* routine implements a 2000 ms timeout for link training. If in a case
* link trains before timeout, loop will exit earlier.
*
* There are also some 2.0 hard drive based devices and 3.0 thumb
* drives that, when plugged into a 2.0 only port, take a long
* time to set CCS after VBUS enable.
*
* FIXME: If a device was connected before suspend, but was removed
* while system was asleep, then the loop in the following routine will
* only exit at timeout.
*
* This routine should only be called when persist is enabled for a SS
* device.
* This routine should only be called when persist is enabled.
*/
static int wait_for_ss_port_enable(struct usb_device *udev,
static int wait_for_connected(struct usb_device *udev,
struct usb_hub *hub, int *port1,
u16 *portchange, u16 *portstatus)
{
@ -3335,6 +3338,7 @@ static int wait_for_ss_port_enable(struct usb_device *udev,
delay_ms += 20;
status = hub_port_status(hub, *port1, portstatus, portchange);
}
dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms);
return status;
}
@ -3434,8 +3438,8 @@ 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,
if (udev->persist_enabled)
status = wait_for_connected(udev, hub, &port1, &portchange,
&portstatus);
status = check_port_resume_type(udev,