aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhuang Jin Can <jin.can.zhuang@intel.com>2015-07-21 10:20:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-22 17:19:37 -0400
commitfac4271d1126c45ceaceb7f4a336317b771eb121 (patch)
tree7ea059fe9f19fe19b0e262aaf316eb147cee14a5
parent243292a2ad3dc365849b820a64868927168894ac (diff)
xhci: prevent bus_suspend if SS port resuming in phase 1
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] Cc: <stable@vger.kernel.org> 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>
-rw-r--r--drivers/usb/host/xhci-hub.c6
-rw-r--r--drivers/usb/host/xhci-ring.c3
-rw-r--r--drivers/usb/host/xhci.h1
3 files changed, 7 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 7df8878cc37b..fdca8edc5836 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1123,10 +1123,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
1123 spin_lock_irqsave(&xhci->lock, flags); 1123 spin_lock_irqsave(&xhci->lock, flags);
1124 1124
1125 if (hcd->self.root_hub->do_remote_wakeup) { 1125 if (hcd->self.root_hub->do_remote_wakeup) {
1126 if (bus_state->resuming_ports) { 1126 if (bus_state->resuming_ports || /* USB2 */
1127 bus_state->port_remote_wakeup) { /* USB3 */
1127 spin_unlock_irqrestore(&xhci->lock, flags); 1128 spin_unlock_irqrestore(&xhci->lock, flags);
1128 xhci_dbg(xhci, "suspend failed because " 1129 xhci_dbg(xhci, "suspend failed because a port is resuming\n");
1129 "a port is resuming\n");
1130 return -EBUSY; 1130 return -EBUSY;
1131 } 1131 }
1132 } 1132 }
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 94416ff70810..6a8fc52aed58 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1546,6 +1546,9 @@ static void handle_port_status(struct xhci_hcd *xhci,
1546 usb_hcd_resume_root_hub(hcd); 1546 usb_hcd_resume_root_hub(hcd);
1547 } 1547 }
1548 1548
1549 if (hcd->speed == HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE)
1550 bus_state->port_remote_wakeup &= ~(1 << faked_port_index);
1551
1549 if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { 1552 if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
1550 xhci_dbg(xhci, "port resume event for port %d\n", port_id); 1553 xhci_dbg(xhci, "port resume event for port %d\n", port_id);
1551 1554
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 31e46cc55807..ed2ebf647c38 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -285,6 +285,7 @@ struct xhci_op_regs {
285#define XDEV_U0 (0x0 << 5) 285#define XDEV_U0 (0x0 << 5)
286#define XDEV_U2 (0x2 << 5) 286#define XDEV_U2 (0x2 << 5)
287#define XDEV_U3 (0x3 << 5) 287#define XDEV_U3 (0x3 << 5)
288#define XDEV_INACTIVE (0x6 << 5)
288#define XDEV_RESUME (0xf << 5) 289#define XDEV_RESUME (0xf << 5)
289/* true: port has power (see HCC_PPC) */ 290/* true: port has power (see HCC_PPC) */
290#define PORT_POWER (1 << 9) 291#define PORT_POWER (1 << 9)