Change usb_add_hcd to accept a negative interrupt number to mean that the generic handler is not desired. This is needed by the xHCI driver because it uses its own handlers for MSI-X interrupts; in this way the driver avoids having to request and free the 'legacy' handler before requesting its own handlers. Since IRQF_DISABLED is a noop, hcd-pci no longer bothers to set it. Signed-off-by: Clemens Ladisch <clemens@xxxxxxxxxx> --- drivers/usb/core/hcd-pci.c | 17 +++++++++++++---- drivers/usb/core/hcd.c | 5 ++--- drivers/usb/host/xhci-pci.c | 5 +++-- drivers/usb/host/xhci.c | 5 ----- include/linux/usb/hcd.h | 7 +++++-- 5 files changed, 23 insertions(+), 16 deletions(-) --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -190,7 +190,10 @@ struct hc_driver { #define HCD_USB3 0x0040 /* USB 3.0 */ #define HCD_MASK 0x0070 - /* used to enable MSI, if desired */ + /* + * Can be used to enable MSI. Return a positive value to prevent + * the HCD framework from requesting the irq. + */ int (*pci_prepare_irq)(struct usb_hcd *hcd); void (*pci_cleanup_irq)(struct usb_hcd *hcd); @@ -332,7 +335,7 @@ extern struct usb_hcd *usb_create_hcd(co extern struct usb_hcd *usb_get_hcd(struct usb_hcd *hcd); extern void usb_put_hcd(struct usb_hcd *hcd); extern int usb_add_hcd(struct usb_hcd *hcd, - unsigned int irqnum, unsigned long irqflags); + int irqnum, unsigned long irqflags); extern void usb_remove_hcd(struct usb_hcd *hcd); struct platform_device; --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2190,8 +2190,7 @@ EXPORT_SYMBOL_GPL(usb_put_hcd); * buffers of consistent memory, register the bus, request the IRQ line, * and call the driver's reset() and start() routines. */ -int usb_add_hcd(struct usb_hcd *hcd, - unsigned int irqnum, unsigned long irqflags) +int usb_add_hcd(struct usb_hcd *hcd, int irqnum, unsigned long irqflags) { int retval; struct usb_device *rhdev; @@ -2254,7 +2253,7 @@ int usb_add_hcd(struct usb_hcd *hcd, dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); /* enable irqs just before we start the controller */ - if (hcd->driver->irq) { + if (irqnum >= 0 && hcd->driver->irq) { /* IRQF_DISABLED doesn't work as advertised when used together * with IRQF_SHARED. As usb_hcd_irq() will always disable --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -176,6 +176,7 @@ int usb_hcd_pci_probe(struct pci_dev *de { struct hc_driver *driver; struct usb_hcd *hcd; + int irqnum; unsigned long irqflags; int retval; @@ -247,16 +248,24 @@ int usb_hcd_pci_probe(struct pci_dev *de pci_set_master(dev); + retval = 0; if (driver->pci_prepare_irq) { retval = driver->pci_prepare_irq(hcd); if (retval < 0) goto err4; } - irqflags = IRQF_DISABLED; - if (!pci_dev_msi_enabled(dev)) - irqflags |= IRQF_SHARED; - retval = usb_add_hcd(hcd, dev->irq, irqflags); + if (retval > 0) { + irqnum = -1; + irqflags = 0; + } else if (pci_dev_msi_enabled(dev)) { + irqnum = dev->irq; + irqflags = 0; + } else { + irqnum = dev->irq; + irqflags = IRQF_SHARED; + } + retval = usb_add_hcd(hcd, irqnum, irqflags); if (retval != 0) goto err5; set_hs_companion(dev, hcd); --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -90,8 +90,9 @@ static int xhci_pci_prepare_irq(struct u { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - if (xhci_prepare_msix(xhci) != 0) - xhci_prepare_msi(xhci); + if (!xhci_prepare_msix(xhci)) + return 1; + xhci_prepare_msi(xhci); return 0; } --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -430,11 +430,6 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg(xhci, "xhci_run\n"); if (xhci->msix_entries) { - /* unregister the legacy interrupt */ - if (hcd->irq >= 0) - free_irq(hcd->irq, hcd); - hcd->irq = -1; - ret = xhci_setup_msix(xhci); if (ret) return ret; -- 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