diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 8719a3f6851d..592e742c5f35 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c | |||
@@ -782,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
782 | { | 782 | { |
783 | unsigned long flags; | 783 | unsigned long flags; |
784 | int ret; | 784 | int ret; |
785 | u32 temp; | ||
785 | struct xhci_hcd *xhci; | 786 | struct xhci_hcd *xhci; |
786 | struct xhci_td *td; | 787 | struct xhci_td *td; |
787 | unsigned int ep_index; | 788 | unsigned int ep_index; |
@@ -794,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
794 | ret = usb_hcd_check_unlink_urb(hcd, urb, status); | 795 | ret = usb_hcd_check_unlink_urb(hcd, urb, status); |
795 | if (ret || !urb->hcpriv) | 796 | if (ret || !urb->hcpriv) |
796 | goto done; | 797 | goto done; |
798 | temp = xhci_readl(xhci, &xhci->op_regs->status); | ||
799 | if (temp == 0xffffffff) { | ||
800 | xhci_dbg(xhci, "HW died, freeing TD.\n"); | ||
801 | td = (struct xhci_td *) urb->hcpriv; | ||
802 | |||
803 | usb_hcd_unlink_urb_from_ep(hcd, urb); | ||
804 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
805 | usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); | ||
806 | kfree(td); | ||
807 | return ret; | ||
808 | } | ||
797 | 809 | ||
798 | xhci_dbg(xhci, "Cancel URB %p\n", urb); | 810 | xhci_dbg(xhci, "Cancel URB %p\n", urb); |
799 | xhci_dbg(xhci, "Event ring:\n"); | 811 | xhci_dbg(xhci, "Event ring:\n"); |