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