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