aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r--drivers/usb/host/xhci.c43
1 files changed, 25 insertions, 18 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 50aee8b7718b..953fd8f62df0 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1477,6 +1477,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1477 struct xhci_ring *ep_ring; 1477 struct xhci_ring *ep_ring;
1478 struct xhci_virt_ep *ep; 1478 struct xhci_virt_ep *ep;
1479 struct xhci_command *command; 1479 struct xhci_command *command;
1480 struct xhci_virt_device *vdev;
1480 1481
1481 xhci = hcd_to_xhci(hcd); 1482 xhci = hcd_to_xhci(hcd);
1482 spin_lock_irqsave(&xhci->lock, flags); 1483 spin_lock_irqsave(&xhci->lock, flags);
@@ -1485,15 +1486,27 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1485 1486
1486 /* Make sure the URB hasn't completed or been unlinked already */ 1487 /* Make sure the URB hasn't completed or been unlinked already */
1487 ret = usb_hcd_check_unlink_urb(hcd, urb, status); 1488 ret = usb_hcd_check_unlink_urb(hcd, urb, status);
1488 if (ret || !urb->hcpriv) 1489 if (ret)
1489 goto done; 1490 goto done;
1491
1492 /* give back URB now if we can't queue it for cancel */
1493 vdev = xhci->devs[urb->dev->slot_id];
1494 urb_priv = urb->hcpriv;
1495 if (!vdev || !urb_priv)
1496 goto err_giveback;
1497
1498 ep_index = xhci_get_endpoint_index(&urb->ep->desc);
1499 ep = &vdev->eps[ep_index];
1500 ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
1501 if (!ep || !ep_ring)
1502 goto err_giveback;
1503
1490 temp = readl(&xhci->op_regs->status); 1504 temp = readl(&xhci->op_regs->status);
1491 if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { 1505 if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
1492 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, 1506 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
1493 "HW died, freeing TD."); 1507 "HW died, freeing TD.");
1494 urb_priv = urb->hcpriv;
1495 for (i = urb_priv->num_tds_done; 1508 for (i = urb_priv->num_tds_done;
1496 i < urb_priv->num_tds && xhci->devs[urb->dev->slot_id]; 1509 i < urb_priv->num_tds;
1497 i++) { 1510 i++) {
1498 td = &urb_priv->td[i]; 1511 td = &urb_priv->td[i];
1499 if (!list_empty(&td->td_list)) 1512 if (!list_empty(&td->td_list))
@@ -1501,23 +1514,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1501 if (!list_empty(&td->cancelled_td_list)) 1514 if (!list_empty(&td->cancelled_td_list))
1502 list_del_init(&td->cancelled_td_list); 1515 list_del_init(&td->cancelled_td_list);
1503 } 1516 }
1504 1517 goto err_giveback;
1505 usb_hcd_unlink_urb_from_ep(hcd, urb);
1506 spin_unlock_irqrestore(&xhci->lock, flags);
1507 usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN);
1508 xhci_urb_free_priv(urb_priv);
1509 return ret;
1510 } 1518 }
1511 1519
1512 ep_index = xhci_get_endpoint_index(&urb->ep->desc);
1513 ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
1514 ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
1515 if (!ep_ring) {
1516 ret = -EINVAL;
1517 goto done;
1518 }
1519
1520 urb_priv = urb->hcpriv;
1521 i = urb_priv->num_tds_done; 1520 i = urb_priv->num_tds_done;
1522 if (i < urb_priv->num_tds) 1521 if (i < urb_priv->num_tds)
1523 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, 1522 xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
@@ -1554,6 +1553,14 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
1554done: 1553done:
1555 spin_unlock_irqrestore(&xhci->lock, flags); 1554 spin_unlock_irqrestore(&xhci->lock, flags);
1556 return ret; 1555 return ret;
1556
1557err_giveback:
1558 if (urb_priv)
1559 xhci_urb_free_priv(urb_priv);
1560 usb_hcd_unlink_urb_from_ep(hcd, urb);
1561 spin_unlock_irqrestore(&xhci->lock, flags);
1562 usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN);
1563 return ret;
1557} 1564}
1558 1565
1559/* Drop an endpoint from a new bandwidth configuration for this device. 1566/* Drop an endpoint from a new bandwidth configuration for this device.