diff options
Diffstat (limited to 'drivers/usb/core/hcd.c')
| -rw-r--r-- | drivers/usb/core/hcd.c | 16 | 
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 1e741bca026..f034716190f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2151,8 +2151,15 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);  irqreturn_t usb_hcd_irq (int irq, void *__hcd)  {  	struct usb_hcd		*hcd = __hcd; +	unsigned long		flags;  	irqreturn_t		rc; +	/* IRQF_DISABLED doesn't work correctly with shared IRQs +	 * when the first handler doesn't use it.  So let's just +	 * assume it's never used. +	 */ +	local_irq_save(flags); +  	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))  		rc = IRQ_NONE;  	else if (hcd->driver->irq(hcd) == IRQ_NONE) @@ -2160,6 +2167,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)  	else  		rc = IRQ_HANDLED; +	local_irq_restore(flags);  	return rc;  }  EXPORT_SYMBOL_GPL(usb_hcd_irq); @@ -2347,6 +2355,14 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,  	int retval;  	if (hcd->driver->irq) { + +		/* IRQF_DISABLED doesn't work as advertised when used together +		 * with IRQF_SHARED. As usb_hcd_irq() will always disable +		 * interrupts we can remove it here. +		 */ +		if (irqflags & IRQF_SHARED) +			irqflags &= ~IRQF_DISABLED; +  		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",  				hcd->driver->description, hcd->self.busnum);  		retval = request_irq(irqnum, &usb_hcd_irq, irqflags,  |