This patch modifies the usb_hcd_giveback_urb() routine in usbcore to insure that interrupts will be disabled when an URB's completion handler is called, even if they were enabled initially. It also modifies ehci-hcd to enable interrupts when giving back URBs, if possible. Unfortunately it isn't always possible, because there are pathways that can give back URBs in hardirq context (during the I/O watchdog hrtimer routine, for example). Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> --- drivers/usb/core/hcd.c | 4 ++++ drivers/usb/host/ehci-q.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) Index: usb-3.11/drivers/usb/core/hcd.c =================================================================== --- usb-3.11.orig/drivers/usb/core/hcd.c +++ usb-3.11/drivers/usb/core/hcd.c @@ -1667,6 +1667,8 @@ int usb_hcd_unlink_urb (struct urb *urb, */ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { + unsigned long flags; + urb->hcpriv = NULL; if (unlikely(urb->unlinked)) status = urb->unlinked; @@ -1681,7 +1683,9 @@ void usb_hcd_giveback_urb(struct usb_hcd /* pass ownership to the completion handler */ urb->status = status; + local_irq_save(flags); urb->complete (urb); + local_irq_restore(flags); atomic_dec (&urb->use_count); if (unlikely(atomic_read(&urb->reject))) wake_up (&usb_kill_urb_queue); Index: usb-3.11/drivers/usb/host/ehci-q.c =================================================================== --- usb-3.11.orig/drivers/usb/host/ehci-q.c +++ usb-3.11/drivers/usb/host/ehci-q.c @@ -257,6 +257,8 @@ ehci_urb_done(struct ehci_hcd *ehci, str __releases(ehci->lock) __acquires(ehci->lock) { + bool enable_ints = !in_irq(); + if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { /* ... update hc-wide periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; @@ -283,9 +285,15 @@ __acquires(ehci->lock) /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - spin_unlock (&ehci->lock); + + /* This routine can be called from hardirq or softirq context */ + spin_unlock(&ehci->lock); + if (enable_ints) + local_irq_enable(); usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); - spin_lock (&ehci->lock); + if (enable_ints) + local_irq_disable(); + spin_lock(&ehci->lock); } static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html