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 <st...@rowland.harvard.edu>

---


 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to