diff options
| author | Zhuang Jin Can <jin.can.zhuang@intel.com> | 2015-07-21 17:20:30 +0300 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2016-08-26 19:58:50 +0200 |
| commit | d3c102c1077e25b4d2965b2f38c55967c7a4205d (patch) | |
| tree | 3051b5d1c22aaee26cd10d77e0bbd98947ec0db1 | |
| parent | 194e2907e1cb76ce8a1d6a0721c37d9d8967530b (diff) | |
| download | android_kernel_m2note-d3c102c1077e25b4d2965b2f38c55967c7a4205d.tar.gz | |
xhci: prevent bus_suspend if SS port resuming in phase 1
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: Stefan Guendhoer <stefan@guendhoer.com>
| -rw-r--r-- | drivers/usb/host/xhci-hub.c | 6 | ||||
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 3 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 1 |
3 files changed, 7 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index ea853e3da..0f71c3a22 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1048,10 +1048,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; } } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 41b0d4855..11e6e52c0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1679,6 +1679,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); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 4c820b096..6d5839213 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -281,6 +281,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) |
