summaryrefslogtreecommitdiffstats
path: root/include/linux/usb
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2015-12-11 14:38:06 +0200
committerLuis Henriques <luis.henriques@canonical.com>2016-01-18 22:27:27 +0000
commit30f8b51181b97a688978aa95569f7456e1ac224f (patch)
treef052bbdc45e96d03135b752cbaaf5b101e77ccc0 /include/linux/usb
parentccebddfbea646b3b00ae53e4c74d258e1d31434a (diff)
downloadlinux-stable-30f8b51181b97a688978aa95569f7456e1ac224f.tar.gz
linux-stable-30f8b51181b97a688978aa95569f7456e1ac224f.tar.bz2
linux-stable-30f8b51181b97a688978aa95569f7456e1ac224f.zip
xhci: fix usb2 resume timing and races.
commit f69115fdbc1ac0718e7d19ad3caa3da2ecfe1c96 upstream. According to USB 2 specs ports need to signal resume for at least 20ms, in practice even longer, before moving to U0 state. Both host and devices can initiate resume. On device initiated resume, a port status interrupt with the port in resume state in issued. The interrupt handler tags a resume_done[port] timestamp with current time + USB_RESUME_TIMEOUT, and kick roothub timer. Root hub timer requests for port status, finds the port in resume state, checks if resume_done[port] timestamp passed, and set port to U0 state. On host initiated resume, current code sets the port to resume state, sleep 20ms, and finally sets the port to U0 state. This should also be changed to work in a similar way as the device initiated resume, with timestamp tagging, but that is not yet tested and will be a separate fix later. There are a few issues with this approach 1. A host initiated resume will also generate a resume event. The event handler will find the port in resume state, believe it's a device initiated resume, and act accordingly. 2. A port status request might cut the resume signalling short if a get_port_status request is handled during the host resume signalling. The port will be found in resume state. The timestamp is not set leading to time_after_eq(jiffies, timestamp) returning true, as timestamp = 0. get_port_status will proceed with moving the port to U0. 3. If an error, or anything else happens to the port during device initiated resume signalling it will leave all the device resume parameters hanging uncleared, preventing further suspend, returning -EBUSY, and cause the pm thread to busyloop trying to enter suspend. Fix this by using the existing resuming_ports bitfield to indicate that resume signalling timing is taken care of. Check if the resume_done[port] is set before using it for timestamp comparison, and also clear out any resume signalling related variables if port is not in U0 or Resume state This issue was discovered when a PM thread busylooped, trying to runtime suspend the xhci USB 2 roothub on a Dell XPS Reported-by: Daniel J Blueman <daniel@quora.org> Tested-by: Daniel J Blueman <daniel@quora.org> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
Diffstat (limited to 'include/linux/usb')
0 files changed, 0 insertions, 0 deletions