Greg:

This patch fixes a tiny SMP-type hole in root-hub synchronization.  
Although the HCD glue layer properly unlinks root-hub status URBs
synchronously, it doesn't do so for URBs sent to endpoint 0.  This patch
copies some code from usb_kill_urb, to make such unlinks wait until the
host controller driver has finished handling the URB.  This behavior is
required for hcd_endpoint_disable to work correctly.

The patch also renames usb_rh_status_dequeue to usb_rh_urb_dequeue (to 
better describe its updated function) and declares the routine static.

Please apply.

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

===== hcd.c 1.161 vs edited =====
--- 1.161/drivers/usb/core/hcd.c        2004-10-20 12:38:07 -04:00
+++ edited/hcd.c        2004-10-27 12:50:47 -04:00
@@ -572,18 +572,34 @@
 
 /*-------------------------------------------------------------------------*/
 
-int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
        unsigned long   flags;
 
        /* note:  always a synchronous unlink */
-       del_timer_sync (&hcd->rh_timer);
-       hcd->rh_timer.data = 0;
+       if ((unsigned long) urb == hcd->rh_timer.data) {
+               del_timer_sync (&hcd->rh_timer);
+               hcd->rh_timer.data = 0;
+
+               local_irq_save (flags);
+               urb->hcpriv = NULL;
+               usb_hcd_giveback_urb (hcd, urb, NULL);
+               local_irq_restore (flags);
+
+       } else if (usb_pipeendpoint(urb->pipe) == 0) {
+               spin_lock_irq(&urb->lock);      /* from usb_kill_urb */
+               ++urb->reject;
+               spin_unlock_irq(&urb->lock);
+
+               wait_event(usb_kill_urb_queue,
+                               atomic_read(&urb->use_count) == 0);
+
+               spin_lock_irq(&urb->lock);
+               --urb->reject;
+               spin_unlock_irq(&urb->lock);
+       } else
+               return -EINVAL;
 
-       local_irq_save (flags);
-       urb->hcpriv = NULL;
-       usb_hcd_giveback_urb (hcd, urb, NULL);
-       local_irq_restore (flags);
        return 0;
 }
 
@@ -1175,8 +1191,8 @@
 {
        int             value;
 
-       if (urb == (struct urb *) hcd->rh_timer.data)
-               value = usb_rh_status_dequeue (hcd, urb);
+       if (urb->dev == hcd->self.root_hub)
+               value = usb_rh_urb_dequeue (hcd, urb);
        else {
 
                /* The only reason an HCD might fail this call is if
@@ -1264,7 +1280,7 @@
         * never get completion IRQs ... maybe even the ones we need to
         * finish unlinking the initial failed usb_set_address().
         */
-       if (!hcd->saw_irq && hcd->rh_timer.data != (unsigned long) urb) {
+       if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) {
                dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
                        "Different ACPI or APIC settings may help."
                        "\n");
===== hcd.h 1.91 vs edited =====
--- 1.91/drivers/usb/core/hcd.h 2004-10-20 12:53:13 -04:00
+++ edited/hcd.h        2004-10-27 12:15:33 -04:00
@@ -215,7 +215,6 @@
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct 
pt_regs *regs);
 extern void usb_bus_init (struct usb_bus *bus);
-extern int usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
 
 #ifdef CONFIG_PCI
 struct pci_dev;



-------------------------------------------------------
This SF.Net email is sponsored by:
Sybase ASE Linux Express Edition - download now for FREE
LinuxWorld Reader's Choice Award Winner for best database on Linux.
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to