in case an HCD wants to use threaded irqs to spend less time in hardirq context, we need this. Eventually we will remove IRQF_ONESHOT but only after all HCDs are fixed. Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx> --- drivers/usb/core/hcd.c | 43 ++++++++++++++++++++++++++++++++++++++++--- include/linux/usb/hcd.h | 2 ++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 76a6cd0d3af9..66dc5a8dfca8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2420,7 +2420,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. * - * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise. + * Return: %IRQ_HANDLED if the IRQ was handled or %IRQ_WAKE_THREAD if we need to + * wake our threaded handler. %IRQ_NONE otherwise. */ irqreturn_t usb_hcd_irq (int irq, void *__hcd) { @@ -2433,6 +2434,29 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd) } EXPORT_SYMBOL_GPL(usb_hcd_irq); +/** + * usb_hcd_threaded_irq - hook threaded IRQs to HCD framework (bus glue) + * @irq the IRQ for which a thread is being woken + * @__hcd: pointer to the HCD whose IRQ is being signaled + * If the controller isn't HALTed, calls the driver's irq handler. + * Checks whether the controller is now dead. + * + * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise. + */ +irqreturn_t usb_hcd_threaded_irq (int irq, void *__hcd) +{ + struct usb_hcd *hcd = __hcd; + + if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) + return IRQ_NONE; + + if (hcd->driver->threaded_irq) + return hcd->driver->threaded_irq(hcd); + + return IRQ_NONE; +} +EXPORT_SYMBOL_GPL(usb_hcd_threaded_irq); + /*-------------------------------------------------------------------------*/ /** @@ -2646,8 +2670,21 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd, 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, - hcd->irq_descr, hcd); + + /* + * NOTICE: we're assuming here that if an HCD implements + * threaded_irq, it's because it wants to use it. For now, we're + * leaving IRQF_ONESHOT in place, but soon enough we plan on + * removing that after all HCDs are fixed. + */ + if (hcd->driver->threaded_irq) + retval = request_threaded_irq(irqnum, usb_hcd_irq, + usb_hcd_threaded_irq, + irqflags | IRQF_ONESHOT, hcd->irq_descr, + hcd); + else + retval = request_irq(irqnum, usb_hcd_irq, irqflags, + hcd->irq_descr, hcd); if (retval != 0) { dev_err(hcd->self.controller, "request interrupt %d failed\n", diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index b98f831dcda3..75287dd91a52 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -242,6 +242,7 @@ struct hc_driver { /* irq handler */ irqreturn_t (*irq) (struct usb_hcd *hcd); + irqreturn_t (*threaded_irq) (struct usb_hcd *hcd); int flags; #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ @@ -479,6 +480,7 @@ void hcd_buffer_free(struct usb_bus *bus, size_t size, /* generic bus glue, needed for host controllers that don't use PCI */ extern irqreturn_t usb_hcd_irq(int irq, void *__hcd); +extern irqreturn_t usb_hcd_threaded_irq(int irq, void *__hcd); extern void usb_hc_died(struct usb_hcd *hcd); extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); -- 2.8.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html