]> git.itanic.dy.fi Git - linux-stable/commitdiff
xhci: prevent bus_suspend if SS port resuming in phase 1
authorZhuang Jin Can <jin.can.zhuang@intel.com>
Tue, 21 Jul 2015 14:20:30 +0000 (17:20 +0300)
committerZefan Li <lizefan@huawei.com>
Mon, 21 Mar 2016 01:17:47 +0000 (09:17 +0800)
commit fac4271d1126c45ceaceb7f4a336317b771eb121 upstream.

When the link is just waken, it's in Resume state, and driver sets PLS to
U0. This refers to Phase 1. Phase 2 refers to when the link has completed
the transition from Resume state to U0.

With the fix of xhci: report U3 when link is in resume state, it also
exposes an issue that usb3 roothub and controller can suspend right
after phase 1, and this causes a hard hang in controller.

To fix the issue, we need to prevent usb3 bus suspend if any port is
resuming in phase 1.

[merge separate USB2 and USB3 port resume checking to one -Mathias]
Signed-off-by: Zhuang Jin Can <jin.can.zhuang@intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Zefan Li <lizefan@huawei.com>
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h

index 9be0c290f0d00d011721cc751eea65fe61ad7063..fbbb11d0f9bbf67aecfe29b76d5e76f49f706089 100644 (file)
@@ -1011,10 +1011,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
        spin_lock_irqsave(&xhci->lock, flags);
 
        if (hcd->self.root_hub->do_remote_wakeup) {
-               if (bus_state->resuming_ports) {
+               if (bus_state->resuming_ports ||        /* USB2 */
+                   bus_state->port_remote_wakeup) {    /* USB3 */
                        spin_unlock_irqrestore(&xhci->lock, flags);
-                       xhci_dbg(xhci, "suspend failed because "
-                                               "a port is resuming\n");
+                       xhci_dbg(xhci, "suspend failed because a port is resuming\n");
                        return -EBUSY;
                }
        }
index 5e93425424f6ada1926d96f57f2a60eeded68c79..b2afcb889b45d415fcebd77e58408055e8163c75 100644 (file)
@@ -1667,6 +1667,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
                usb_hcd_resume_root_hub(hcd);
        }
 
+       if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
+               bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
+
        if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
                xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 
index 855f084a9a32a6243a48e1b08fe9fb074648dc98..f4116fcd1cd8bfe0049629a6f9bf708026eb6761 100644 (file)
@@ -280,6 +280,7 @@ struct xhci_op_regs {
 #define XDEV_U0                (0x0 << 5)
 #define XDEV_U2                (0x2 << 5)
 #define XDEV_U3                (0x3 << 5)
+#define XDEV_INACTIVE  (0x6 << 5)
 #define XDEV_RESUME    (0xf << 5)
 /* true: port has power (see HCC_PPC) */
 #define PORT_POWER     (1 << 9)