summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-11-14 17:51:39 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-03 09:19:01 -0800
commita5c55d20f4251bcc22ce82ff82add9839027e818 (patch)
tree2fd64b5d52999b90c07b0d56f06cf34f5b7b849c
parent6a1d0b0af0dcb47bab73e4aa95b4b6afaee4a75c (diff)
xhci: Fix USB 3.0 device restart on resume.
commit d0cd5d482b8a6dc92c6c69a5387baf72ea84f23a upstream. The xHCI hub port code gets passed a zero-based port number by the USB core. It then adds one to in order to find a device slot by port number and device speed by calling xhci_find_slot_id_by_port. That function clearly states it requires a one-based port number. The xHCI port status change event handler was using a zero-based port number that it got from find_faked_portnum_from_hw_portnum, not a one-based port number. This lead to the doorbells never being rung for a device after a resume, or worse, a different device with the same speed having its doorbell rung (which could lead to bad power management in the xHCI host controller). This patch should be backported to kernels as old as 2.6.39. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Acked-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci-ring.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c0c5d6c7cb69..8784ab010419 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1218,6 +1218,7 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
*
* Returns a zero-based port number, which is suitable for indexing into each of
* the split roothubs' port arrays and bus state arrays.
+ * Add one to it in order to call xhci_find_slot_id_by_port.
*/
static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
struct xhci_hcd *xhci, u32 port_id)
@@ -1340,7 +1341,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
temp |= PORT_LINK_STROBE | XDEV_U0;
xhci_writel(xhci, temp, port_array[faked_port_index]);
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- faked_port_index);
+ faked_port_index + 1);
if (!slot_id) {
xhci_dbg(xhci, "slot_id is zero\n");
goto cleanup;