diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
| -rw-r--r-- | drivers/usb/host/xhci.c | 43 |
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) | |||
| 1554 | done: | 1553 | done: |
| 1555 | spin_unlock_irqrestore(&xhci->lock, flags); | 1554 | spin_unlock_irqrestore(&xhci->lock, flags); |
| 1556 | return ret; | 1555 | return ret; |
| 1556 | |||
| 1557 | err_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. |
