diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hcd.c | 16 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 7 |
2 files changed, 21 insertions, 2 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1e741bca0265..f034716190ff 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -2151,8 +2151,15 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); | |||
2151 | irqreturn_t usb_hcd_irq (int irq, void *__hcd) | 2151 | irqreturn_t usb_hcd_irq (int irq, void *__hcd) |
2152 | { | 2152 | { |
2153 | struct usb_hcd *hcd = __hcd; | 2153 | struct usb_hcd *hcd = __hcd; |
2154 | unsigned long flags; | ||
2154 | irqreturn_t rc; | 2155 | irqreturn_t rc; |
2155 | 2156 | ||
2157 | /* IRQF_DISABLED doesn't work correctly with shared IRQs | ||
2158 | * when the first handler doesn't use it. So let's just | ||
2159 | * assume it's never used. | ||
2160 | */ | ||
2161 | local_irq_save(flags); | ||
2162 | |||
2156 | if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) | 2163 | if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) |
2157 | rc = IRQ_NONE; | 2164 | rc = IRQ_NONE; |
2158 | else if (hcd->driver->irq(hcd) == IRQ_NONE) | 2165 | else if (hcd->driver->irq(hcd) == IRQ_NONE) |
@@ -2160,6 +2167,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) | |||
2160 | else | 2167 | else |
2161 | rc = IRQ_HANDLED; | 2168 | rc = IRQ_HANDLED; |
2162 | 2169 | ||
2170 | local_irq_restore(flags); | ||
2163 | return rc; | 2171 | return rc; |
2164 | } | 2172 | } |
2165 | EXPORT_SYMBOL_GPL(usb_hcd_irq); | 2173 | EXPORT_SYMBOL_GPL(usb_hcd_irq); |
@@ -2347,6 +2355,14 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, | |||
2347 | int retval; | 2355 | int retval; |
2348 | 2356 | ||
2349 | if (hcd->driver->irq) { | 2357 | if (hcd->driver->irq) { |
2358 | |||
2359 | /* IRQF_DISABLED doesn't work as advertised when used together | ||
2360 | * with IRQF_SHARED. As usb_hcd_irq() will always disable | ||
2361 | * interrupts we can remove it here. | ||
2362 | */ | ||
2363 | if (irqflags & IRQF_SHARED) | ||
2364 | irqflags &= ~IRQF_DISABLED; | ||
2365 | |||
2350 | snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", | 2366 | snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", |
2351 | hcd->driver->description, hcd->self.busnum); | 2367 | hcd->driver->description, hcd->self.busnum); |
2352 | retval = request_irq(irqnum, &usb_hcd_irq, irqflags, | 2368 | retval = request_irq(irqnum, &usb_hcd_irq, irqflags, |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 64854d76f529..1af04bdeaf0c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -739,13 +739,16 @@ static void hub_tt_work(struct work_struct *work) | |||
739 | int limit = 100; | 739 | int limit = 100; |
740 | 740 | ||
741 | spin_lock_irqsave (&hub->tt.lock, flags); | 741 | spin_lock_irqsave (&hub->tt.lock, flags); |
742 | while (--limit && !list_empty (&hub->tt.clear_list)) { | 742 | while (!list_empty(&hub->tt.clear_list)) { |
743 | struct list_head *next; | 743 | struct list_head *next; |
744 | struct usb_tt_clear *clear; | 744 | struct usb_tt_clear *clear; |
745 | struct usb_device *hdev = hub->hdev; | 745 | struct usb_device *hdev = hub->hdev; |
746 | const struct hc_driver *drv; | 746 | const struct hc_driver *drv; |
747 | int status; | 747 | int status; |
748 | 748 | ||
749 | if (!hub->quiescing && --limit < 0) | ||
750 | break; | ||
751 | |||
749 | next = hub->tt.clear_list.next; | 752 | next = hub->tt.clear_list.next; |
750 | clear = list_entry (next, struct usb_tt_clear, clear_list); | 753 | clear = list_entry (next, struct usb_tt_clear, clear_list); |
751 | list_del (&clear->clear_list); | 754 | list_del (&clear->clear_list); |
@@ -1210,7 +1213,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) | |||
1210 | if (hub->has_indicators) | 1213 | if (hub->has_indicators) |
1211 | cancel_delayed_work_sync(&hub->leds); | 1214 | cancel_delayed_work_sync(&hub->leds); |
1212 | if (hub->tt.hub) | 1215 | if (hub->tt.hub) |
1213 | cancel_work_sync(&hub->tt.clear_work); | 1216 | flush_work(&hub->tt.clear_work); |
1214 | } | 1217 | } |
1215 | 1218 | ||
1216 | /* caller has locked the hub device */ | 1219 | /* caller has locked the hub device */ |