aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShyam Sundar S K <Shyam-sundar.S-k@amd.com>2017-07-20 07:48:28 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-07-20 08:40:35 -0400
commit28a2369f7d72ece55089f33e7d7b9c1223673cc3 (patch)
tree34e00572fdfc4047b883b1ea49dacacb9257f164
parent9da5a1092b13468839b1a864b126cacfb72ad016 (diff)
usb: xhci: Issue stop EP command only when the EP state is running
on AMD platforms with SNPS 3.1 USB controller if stop endpoint command is issued the controller does not respond, when the EP is not in running state. HW completes the command execution and reports "Context State Error" completion code. This is as per the spec. However HW on receiving the second command additionally marks EP to Flow control state in HW which is RTL bug. This bug causes the HW not to respond to any further doorbells that are rung by the driver. This makes the EP to not functional anymore and causes gross functional failures. As a workaround, not to hit this problem, it's better to check the EP state and issue a stop EP command only when the EP is in running state. As a sidenote, even with this patch there is still a possibility of triggering the RTL bug if the context state races with the stop endpoint command as described in xHCI spec 4.6.9 [code simplification and reworded sidenote in commit message -Mathias] Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> Signed-off-by: Nehal Shah <Nehal-bakulchandra.Shah@amd.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.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 1adae9eab831..364f60275043 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -398,14 +398,21 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
398 spin_lock_irqsave(&xhci->lock, flags); 398 spin_lock_irqsave(&xhci->lock, flags);
399 for (i = LAST_EP_INDEX; i > 0; i--) { 399 for (i = LAST_EP_INDEX; i > 0; i--) {
400 if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { 400 if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
401 struct xhci_ep_ctx *ep_ctx;
401 struct xhci_command *command; 402 struct xhci_command *command;
403
404 ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->out_ctx, i);
405
406 /* Check ep is running, required by AMD SNPS 3.1 xHC */
407 if (GET_EP_CTX_STATE(ep_ctx) != EP_STATE_RUNNING)
408 continue;
409
402 command = xhci_alloc_command(xhci, false, false, 410 command = xhci_alloc_command(xhci, false, false,
403 GFP_NOWAIT); 411 GFP_NOWAIT);
404 if (!command) { 412 if (!command) {
405 spin_unlock_irqrestore(&xhci->lock, flags); 413 spin_unlock_irqrestore(&xhci->lock, flags);
406 xhci_free_command(xhci, cmd); 414 xhci_free_command(xhci, cmd);
407 return -ENOMEM; 415 return -ENOMEM;
408
409 } 416 }
410 xhci_queue_stop_endpoint(xhci, command, slot_id, i, 417 xhci_queue_stop_endpoint(xhci, command, slot_id, i,
411 suspend); 418 suspend);