aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/xhci-hcd.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-10-11 11:24:25 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2009-10-11 11:24:25 -0700
commitc6c599272374a358b4171d50ffd605e6cf7b481c (patch)
tree8ce918c724c39e88e96d7abf243955718e71da9a /drivers/usb/host/xhci-hcd.c
parentff945afb10bc9d81f395da474fa2aa88ee620e48 (diff)
parent40d28582316d8dcb535c359a14b71cb910ad6e73 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (32 commits) USB: serial: no unnecessary GFP_ATOMIC in oti6858 USB: serial: fix race between unthrottle and completion handler in visor USB: serial: fix assumption that throttle/unthrottle cannot sleep USB: serial: fix race between unthrottle and completion handler in symbolserial USB: serial: fix race between unthrottle and completion handler in opticon USB: ehci: Fix isoc scheduling boundary checking. USB: storage: When a device returns no sense data, call it a Hardware Error USB: small fix in error case of suspend in generic usbserial code USB: visor: fix trivial accounting bug in visor driver USB: Fix throttling in generic usbserial driver USB: cp210x: Add support for the DW700 UART USB: ipaq: fix oops when device is plugged in USB: isp1362: fix build warnings on 64-bit systems USB: gadget: imx_udc: Use resource size USB: storage: iRiver P7 UNUSUAL_DEV patch USB: musb: make HAVE_CLK support optional USB: xhci: Fix dropping endpoints from the xHC schedule. USB: xhci: Don't wait for a disable slot cmd when HC dies. USB: xhci: Handle canceled URBs when HC dies. USB: xhci: Stop debugging polling loop when HC dies. ...
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r--drivers/usb/host/xhci-hcd.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 99911e727e0..932f9993848 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)
spin_lock_irqsave(&xhci->lock, flags);
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
+ if (temp == 0xffffffff) {
+ xhci_dbg(xhci, "HW died, polling stopped.\n");
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return;
+ }
+
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
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)
{
unsigned long flags;
int ret;
+ u32 temp;
struct xhci_hcd *xhci;
struct xhci_td *td;
unsigned int ep_index;
@@ -788,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
if (ret || !urb->hcpriv)
goto done;
+ temp = xhci_readl(xhci, &xhci->op_regs->status);
+ if (temp == 0xffffffff) {
+ xhci_dbg(xhci, "HW died, freeing TD.\n");
+ td = (struct xhci_td *) urb->hcpriv;
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN);
+ kfree(td);
+ return ret;
+ }
xhci_dbg(xhci, "Cancel URB %p\n", urb);
xhci_dbg(xhci, "Event ring:\n");
@@ -877,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
ctrl_ctx->drop_flags |= drop_flag;
new_drop_flags = ctrl_ctx->drop_flags;
- ctrl_ctx->add_flags = ~drop_flag;
+ ctrl_ctx->add_flags &= ~drop_flag;
new_add_flags = ctrl_ctx->add_flags;
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)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;
+ u32 state;
if (udev->slot_id == 0)
return;
spin_lock_irqsave(&xhci->lock, flags);
+ /* Don't disable the slot if the host controller is dead. */
+ state = xhci_readl(xhci, &xhci->op_regs->status);
+ if (state == 0xffffffff) {
+ xhci_free_virt_device(xhci, udev->slot_id);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return;
+ }
+
if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");