* [PATCH AUTOSEL 5.6 70/73] xhci: Ensure link state is U3 after setting USB_SS_PORT_LS_U3
[not found] <20200418134815.6519-1-sashal@kernel.org>
@ 2020-04-18 13:48 ` Sasha Levin
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 71/73] xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0 Sasha Levin
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 72/73] xhci: Finetune host initiated USB3 rootport link suspend and resume Sasha Levin
2 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2020-04-18 13:48 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Kai-Heng Feng, Mathias Nyman, Greg Kroah-Hartman, Sasha Levin,
linux-usb
From: Kai-Heng Feng <kai.heng.feng@canonical.com>
[ Upstream commit eb002726fac7cefb98ff39ddb89e150a1c24fe85 ]
The xHCI spec doesn't specify the upper bound of U3 transition time. For
some devices 20ms is not enough, so we need to make sure the link state
is in U3 before further actions.
I've tried to use U3 Entry Capability by setting U3 Entry Enable in
config register, however the port change event for U3 transition
interrupts the system suspend process.
For now let's use the less ideal method by polling PLS.
[use usleep_range(), and shorten the delay time while polling -Mathias]
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20200312144517.1593-7-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/host/xhci-hub.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index af92b2576fe91..712cd44f05ace 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1322,7 +1322,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_set_link_state(xhci, ports[wIndex], link_state);
spin_unlock_irqrestore(&xhci->lock, flags);
- msleep(20); /* wait device to enter */
+ if (link_state == USB_SS_PORT_LS_U3) {
+ int retries = 16;
+
+ while (retries--) {
+ usleep_range(4000, 8000);
+ temp = readl(ports[wIndex]->addr);
+ if ((temp & PORT_PLS_MASK) == XDEV_U3)
+ break;
+ }
+ }
spin_lock_irqsave(&xhci->lock, flags);
temp = readl(ports[wIndex]->addr);
--
2.20.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH AUTOSEL 5.6 71/73] xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0
[not found] <20200418134815.6519-1-sashal@kernel.org>
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 70/73] xhci: Ensure link state is U3 after setting USB_SS_PORT_LS_U3 Sasha Levin
@ 2020-04-18 13:48 ` Sasha Levin
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 72/73] xhci: Finetune host initiated USB3 rootport link suspend and resume Sasha Levin
2 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2020-04-18 13:48 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Kai-Heng Feng, Mathias Nyman, Greg Kroah-Hartman, Sasha Levin,
linux-usb
From: Kai-Heng Feng <kai.heng.feng@canonical.com>
[ Upstream commit 0200b9f790b0fc9e9a42f685f5ad54b23fe959f4 ]
Like U3 case, xHCI spec doesn't specify the upper bound of U0 transition
time. The 20ms is not enough for some devices.
Intead of polling PLS or PLC, we can facilitate the port change event to
know that the link transits to U0 is completed.
While at it, also separate U0 and U3 case to make the code cleaner.
[variable rename to u3exit, and skip completion for usb2 ports -Mathias ]
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20200312144517.1593-8-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/host/xhci-hub.c | 44 +++++++++++++++++++++++++-----------
drivers/usb/host/xhci-mem.c | 1 +
drivers/usb/host/xhci-ring.c | 1 +
drivers/usb/host/xhci.h | 1 +
4 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 712cd44f05ace..02f52d4f74df8 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1306,7 +1306,33 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
wIndex, link_state);
goto error;
}
+
+ if (link_state == USB_SS_PORT_LS_U0) {
+ if ((temp & PORT_PLS_MASK) == XDEV_U0)
+ break;
+
+ if (!((temp & PORT_PLS_MASK) == XDEV_U1 ||
+ (temp & PORT_PLS_MASK) == XDEV_U2 ||
+ (temp & PORT_PLS_MASK) == XDEV_U3)) {
+ xhci_warn(xhci, "Can only set port %d to U0 from U state\n",
+ wIndex);
+ goto error;
+ }
+ reinit_completion(&bus_state->u3exit_done[wIndex]);
+ xhci_set_link_state(xhci, ports[wIndex],
+ USB_SS_PORT_LS_U0);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ if (!wait_for_completion_timeout(&bus_state->u3exit_done[wIndex],
+ msecs_to_jiffies(100)))
+ xhci_dbg(xhci, "missing U0 port change event for port %d\n",
+ wIndex);
+ spin_lock_irqsave(&xhci->lock, flags);
+ temp = readl(ports[wIndex]->addr);
+ break;
+ }
+
if (link_state == USB_SS_PORT_LS_U3) {
+ int retries = 16;
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
wIndex + 1);
if (slot_id) {
@@ -1317,26 +1343,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_stop_device(xhci, slot_id, 1);
spin_lock_irqsave(&xhci->lock, flags);
}
- }
-
- xhci_set_link_state(xhci, ports[wIndex], link_state);
-
- spin_unlock_irqrestore(&xhci->lock, flags);
- if (link_state == USB_SS_PORT_LS_U3) {
- int retries = 16;
-
+ xhci_set_link_state(xhci, ports[wIndex], USB_SS_PORT_LS_U3);
+ spin_unlock_irqrestore(&xhci->lock, flags);
while (retries--) {
usleep_range(4000, 8000);
temp = readl(ports[wIndex]->addr);
if ((temp & PORT_PLS_MASK) == XDEV_U3)
break;
}
- }
- spin_lock_irqsave(&xhci->lock, flags);
-
- temp = readl(ports[wIndex]->addr);
- if (link_state == USB_SS_PORT_LS_U3)
+ spin_lock_irqsave(&xhci->lock, flags);
+ temp = readl(ports[wIndex]->addr);
bus_state->suspended_ports |= 1 << wIndex;
+ }
break;
case USB_PORT_FEAT_POWER:
/*
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 884c601bfa15f..9764122c9cdf2 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -2552,6 +2552,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci->usb3_rhub.bus_state.resume_done[i] = 0;
/* Only the USB 2.0 completions will ever be used. */
init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]);
+ init_completion(&xhci->usb3_rhub.bus_state.u3exit_done[i]);
}
if (scratchpad_alloc(xhci, flags))
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d23f7408c81f1..c1e63af88356c 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1677,6 +1677,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
(portsc & PORT_PLS_MASK) == XDEV_U1 ||
(portsc & PORT_PLS_MASK) == XDEV_U2)) {
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
+ complete(&bus_state->u3exit_done[hcd_portnum]);
/* We've just brought the device into U0/1/2 through either the
* Resume state after a device remote wakeup, or through the
* U3Exit state after a host-initiated resume. If it's a device
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3ecee10fdcdc7..fb1ab63b5fe25 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1694,6 +1694,7 @@ struct xhci_bus_state {
/* Which ports are waiting on RExit to U0 transition. */
unsigned long rexit_ports;
struct completion rexit_done[USB_MAXCHILDREN];
+ struct completion u3exit_done[USB_MAXCHILDREN];
};
--
2.20.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH AUTOSEL 5.6 72/73] xhci: Finetune host initiated USB3 rootport link suspend and resume
[not found] <20200418134815.6519-1-sashal@kernel.org>
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 70/73] xhci: Ensure link state is U3 after setting USB_SS_PORT_LS_U3 Sasha Levin
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 71/73] xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0 Sasha Levin
@ 2020-04-18 13:48 ` Sasha Levin
2 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2020-04-18 13:48 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Mathias Nyman, Greg Kroah-Hartman, Sasha Levin, linux-usb
From: Mathias Nyman <mathias.nyman@linux.intel.com>
[ Upstream commit ceca49382ac20e06ce04c21279c7f2868c4ec1d4 ]
Depending on the current link state the steps to resume the link to U0
varies. The normal case when a port is suspended (U3) we set the link
to U0 and wait for a port event when U3exit completed and port moved to
U0.
If the port is in U1/U2, then no event is issued, just set link to U0
If port is in Resume or Recovery state then the device has already
initiated resume, and this host initiated resume is racing against it.
Port event handler for device initiated resume will set link to U0,
just wait for the port to reach U0 before returning.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20200312144517.1593-9-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/host/xhci-hub.c | 36 +++++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 02f52d4f74df8..a9c87eb8951e8 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1307,20 +1307,34 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
goto error;
}
+ /*
+ * set link to U0, steps depend on current link state.
+ * U3: set link to U0 and wait for u3exit completion.
+ * U1/U2: no PLC complete event, only set link to U0.
+ * Resume/Recovery: device initiated U0, only wait for
+ * completion
+ */
if (link_state == USB_SS_PORT_LS_U0) {
- if ((temp & PORT_PLS_MASK) == XDEV_U0)
- break;
+ u32 pls = temp & PORT_PLS_MASK;
+ bool wait_u0 = false;
- if (!((temp & PORT_PLS_MASK) == XDEV_U1 ||
- (temp & PORT_PLS_MASK) == XDEV_U2 ||
- (temp & PORT_PLS_MASK) == XDEV_U3)) {
- xhci_warn(xhci, "Can only set port %d to U0 from U state\n",
- wIndex);
- goto error;
+ /* already in U0 */
+ if (pls == XDEV_U0)
+ break;
+ if (pls == XDEV_U3 ||
+ pls == XDEV_RESUME ||
+ pls == XDEV_RECOVERY) {
+ wait_u0 = true;
+ reinit_completion(&bus_state->u3exit_done[wIndex]);
+ }
+ if (pls <= XDEV_U3) /* U1, U2, U3 */
+ xhci_set_link_state(xhci, ports[wIndex],
+ USB_SS_PORT_LS_U0);
+ if (!wait_u0) {
+ if (pls > XDEV_U3)
+ goto error;
+ break;
}
- reinit_completion(&bus_state->u3exit_done[wIndex]);
- xhci_set_link_state(xhci, ports[wIndex],
- USB_SS_PORT_LS_U0);
spin_unlock_irqrestore(&xhci->lock, flags);
if (!wait_for_completion_timeout(&bus_state->u3exit_done[wIndex],
msecs_to_jiffies(100)))
--
2.20.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-04-18 13:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20200418134815.6519-1-sashal@kernel.org>
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 70/73] xhci: Ensure link state is U3 after setting USB_SS_PORT_LS_U3 Sasha Levin
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 71/73] xhci: Wait until link state trainsits to U0 after setting USB_SS_PORT_LS_U0 Sasha Levin
2020-04-18 13:48 ` [PATCH AUTOSEL 5.6 72/73] xhci: Finetune host initiated USB3 rootport link suspend and resume Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).