aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2017-01-11 10:10:34 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-11 10:52:13 -0500
commitd6169d04097fd9ddf811e63eae4e5cd71e6666e2 (patch)
tree544b563a2888386ab960793ab83dbc41ccafbfe5
parent7b6c1b4c0e1e44544aa18161dba6a741c080a7ef (diff)
xhci: fix deadlock at host remove by running watchdog correctly
If a URB is killed while the host is removed we can end up in a situation where the hub thread takes the roothub device lock, and waits for the URB to be given back by xhci-hcd, blocking the host remove code. xhci-hcd tries to stop the endpoint and give back the urb, but can't as the host is removed from PCI bus at the same time, preventing the normal way of giving back urb. Instead we need to rely on the stop command timeout function to give back the urb. This xhci_stop_endpoint_command_watchdog() timeout function used a XHCI_STATE_DYING flag to indicate if the timeout function is already running, but later this flag has been taking into use in other places to mark that xhci is dying. Remove checks for XHCI_STATE_DYING in xhci_urb_dequeue. We are still checking that reading from pci state does not return 0xffffffff or that host is not halted before trying to stop the endpoint. This whole area of stopping endpoints, giving back URBs, and the wathdog timeout need rework, this fix focuses on solving a specific deadlock issue that we can then send to stable before any major rework. Cc: <stable@vger.kernel.org> 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-ring.c11
-rw-r--r--drivers/usb/host/xhci.c13
2 files changed, 0 insertions, 24 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 25f522b09dd9..e32029a31ca4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -913,17 +913,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
913 spin_lock_irqsave(&xhci->lock, flags); 913 spin_lock_irqsave(&xhci->lock, flags);
914 914
915 ep->stop_cmds_pending--; 915 ep->stop_cmds_pending--;
916 if (xhci->xhc_state & XHCI_STATE_REMOVING) {
917 spin_unlock_irqrestore(&xhci->lock, flags);
918 return;
919 }
920 if (xhci->xhc_state & XHCI_STATE_DYING) {
921 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
922 "Stop EP timer ran, but another timer marked "
923 "xHCI as DYING, exiting.");
924 spin_unlock_irqrestore(&xhci->lock, flags);
925 return;
926 }
927 if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { 916 if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
928 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, 917 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
929 "Stop EP timer ran, but no command pending, " 918 "Stop EP timer ran, but no command pending, "
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0c8deb9ed42d..9a0ec116654a 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1534,19 +1534,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1534 xhci_urb_free_priv(urb_priv); 1534 xhci_urb_free_priv(urb_priv);
1535 return ret; 1535 return ret;
1536 } 1536 }
1537 if ((xhci->xhc_state & XHCI_STATE_DYING) ||
1538 (xhci->xhc_state & XHCI_STATE_HALTED)) {
1539 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
1540 "Ep 0x%x: URB %p to be canceled on "
1541 "non-responsive xHCI host.",
1542 urb->ep->desc.bEndpointAddress, urb);
1543 /* Let the stop endpoint command watchdog timer (which set this
1544 * state) finish cleaning up the endpoint TD lists. We must
1545 * have caught it in the middle of dropping a lock and giving
1546 * back an URB.
1547 */
1548 goto done;
1549 }
1550 1537
1551 ep_index = xhci_get_endpoint_index(&urb->ep->desc); 1538 ep_index = xhci_get_endpoint_index(&urb->ep->desc);
1552 ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index]; 1539 ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];