diff options
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 99911e727e0b..932f99938481 100644 --- a/drivers/usb/host/xhci-hcd.c +++ b/drivers/usb/host/xhci-hcd.c | |||
@@ -335,6 +335,12 @@ void xhci_event_ring_work(unsigned long arg) | |||
335 | spin_lock_irqsave(&xhci->lock, flags); | 335 | spin_lock_irqsave(&xhci->lock, flags); |
336 | temp = xhci_readl(xhci, &xhci->op_regs->status); | 336 | temp = xhci_readl(xhci, &xhci->op_regs->status); |
337 | xhci_dbg(xhci, "op reg status = 0x%x\n", temp); | 337 | xhci_dbg(xhci, "op reg status = 0x%x\n", temp); |
338 | if (temp == 0xffffffff) { | ||
339 | xhci_dbg(xhci, "HW died, polling stopped.\n"); | ||
340 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
341 | return; | ||
342 | } | ||
343 | |||
338 | temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); | 344 | temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); |
339 | xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); | 345 | xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); |
340 | xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled); | 346 | xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled); |
@@ -776,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
776 | { | 782 | { |
777 | unsigned long flags; | 783 | unsigned long flags; |
778 | int ret; | 784 | int ret; |
785 | u32 temp; | ||
779 | struct xhci_hcd *xhci; | 786 | struct xhci_hcd *xhci; |
780 | struct xhci_td *td; | 787 | struct xhci_td *td; |
781 | unsigned int ep_index; | 788 | unsigned int ep_index; |
@@ -788,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | |||
788 | ret = usb_hcd_check_unlink_urb(hcd, urb, status); | 795 | ret = usb_hcd_check_unlink_urb(hcd, urb, status); |
789 | if (ret || !urb->hcpriv) | 796 | if (ret || !urb->hcpriv) |
790 | 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 | } | ||
791 | 809 | ||
792 | xhci_dbg(xhci, "Cancel URB %p\n", urb); | 810 | xhci_dbg(xhci, "Cancel URB %p\n", urb); |
793 | xhci_dbg(xhci, "Event ring:\n"); | 811 | xhci_dbg(xhci, "Event ring:\n"); |
@@ -877,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
877 | ctrl_ctx->drop_flags |= drop_flag; | 895 | ctrl_ctx->drop_flags |= drop_flag; |
878 | new_drop_flags = ctrl_ctx->drop_flags; | 896 | new_drop_flags = ctrl_ctx->drop_flags; |
879 | 897 | ||
880 | ctrl_ctx->add_flags = ~drop_flag; | 898 | ctrl_ctx->add_flags &= ~drop_flag; |
881 | new_add_flags = ctrl_ctx->add_flags; | 899 | new_add_flags = ctrl_ctx->add_flags; |
882 | 900 | ||
883 | last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); | 901 | last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags); |
@@ -1410,11 +1428,20 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) | |||
1410 | { | 1428 | { |
1411 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 1429 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
1412 | unsigned long flags; | 1430 | unsigned long flags; |
1431 | u32 state; | ||
1413 | 1432 | ||
1414 | if (udev->slot_id == 0) | 1433 | if (udev->slot_id == 0) |
1415 | return; | 1434 | return; |
1416 | 1435 | ||
1417 | spin_lock_irqsave(&xhci->lock, flags); | 1436 | spin_lock_irqsave(&xhci->lock, flags); |
1437 | /* Don't disable the slot if the host controller is dead. */ | ||
1438 | state = xhci_readl(xhci, &xhci->op_regs->status); | ||
1439 | if (state == 0xffffffff) { | ||
1440 | xhci_free_virt_device(xhci, udev->slot_id); | ||
1441 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
1442 | return; | ||
1443 | } | ||
1444 | |||
1418 | if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { | 1445 | if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { |
1419 | spin_unlock_irqrestore(&xhci->lock, flags); | 1446 | spin_unlock_irqrestore(&xhci->lock, flags); |
1420 | xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); | 1447 | xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); |