diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 09a53e7..400433c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -45,6 +45,14 @@ #include "hcd.h" #include "hub.h" +#ifdef DEBUG +const char *_urb_list_holder = "NONE"; +#define URB_LIST_HOLDER(n) _urb_list_holder = #n; +#define URB_LIST_RELEASE _urb_list_holder = "FREE"; +#else +#define URB_LIST_HOLDER(n) +#define URB_LIST_RELEASE +#endif /*-------------------------------------------------------------------------*/ @@ -1001,7 +1009,12 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) { int rc = 0; +#ifdef DEBUG + if (!raw_irqs_disabled()) dump_stack(); +#endif + spin_lock(&hcd_urb_list_lock); + URB_LIST_HOLDER(usb_hcd_link_urb_to_ep) /* Check that the URB isn't being killed */ if (unlikely(urb->reject)) { @@ -1034,6 +1047,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) goto done; } done: + URB_LIST_RELEASE spin_unlock(&hcd_urb_list_lock); return rc; } @@ -1107,9 +1121,33 @@ EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) { /* clear all state linking urb to this dev (and hcd) */ +#ifdef DEBUG +#if 0 + if (!spin_trylock(&hcd_urb_list_lock)) { + int i; + printk(KERN_CRIT "HCD URB list locked by %s!\n", _urb_list_holder); + dump_stack(); + for (int i = 0; i < 100; i++) schedule(); + } +#endif + unsigned int flags; + + if (!raw_irqs_disabled()) { + printk(KERN_CRIT "usb_hcd_unlink_urb_from_ep called with interrupts enabled!\n"); + dump_stack(); + } + spin_lock_irqsave(&hcd_urb_list_lock, flags); +#else spin_lock(&hcd_urb_list_lock); +#endif + URB_LIST_HOLDER(usb_hcd_unlink_urb_from_ep) list_del_init(&urb->urb_list); + URB_LIST_RELEASE +#ifdef DEBUG + spin_unlock_irqrestore(&hcd_urb_list_lock, flags); +#else spin_unlock(&hcd_urb_list_lock); +#endif } EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); @@ -1448,6 +1486,7 @@ void usb_hcd_flush_endpoint(struct usb_device *udev, /* No more submits can occur */ spin_lock_irq(&hcd_urb_list_lock); + URB_LIST_HOLDER(usb_hcd_flush_endpoint_INITIAL) rescan: list_for_each_entry (urb, &ep->urb_list, urb_list) { int is_in; @@ -1456,6 +1495,7 @@ rescan: continue; usb_get_urb (urb); is_in = usb_urb_dir_in(urb); + URB_LIST_RELEASE spin_unlock(&hcd_urb_list_lock); /* kick hcd */ @@ -1482,13 +1522,16 @@ rescan: /* list contents may have changed */ spin_lock(&hcd_urb_list_lock); + URB_LIST_HOLDER(usb_hcd_flush_endpoint_RESCAN) goto rescan; } + URB_LIST_RELEASE spin_unlock_irq(&hcd_urb_list_lock); /* Wait until the endpoint queue is completely empty */ while (!list_empty (&ep->urb_list)) { spin_lock_irq(&hcd_urb_list_lock); + URB_LIST_HOLDER(usb_hcd_flush_endpoint_LIST) /* The list may have changed while we acquired the spinlock */ urb = NULL; @@ -1497,6 +1540,7 @@ rescan: urb_list); usb_get_urb (urb); } + URB_LIST_RELEASE spin_unlock_irq(&hcd_urb_list_lock); if (urb) {