usb: hcd: Try MSI interrupts on PCI devices
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Thu, 2 Jul 2020 14:30:45 +0000 (17:30 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 21 Jul 2020 11:38:21 +0000 (13:38 +0200)
It appears that some platforms share same IRQ line between several devices,
some of which are EHCI and OHCI controllers. This is neither practical nor
performance-wise, especially in the case when they are supporting MSI.

In order to improve the situation try to allocate MSI and fallback to legacy
IRQ if no MSI available.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20200702143045.23429-1-andriy.shevchenko@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/hcd-pci.c

index 1547aa6e5314c2a8983a7f503735c3c0a4251852..4dc443aaef5c624526624b178b57e73318efd3cc 100644 (file)
@@ -194,20 +194,21 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id,
         * make sure irq setup is not touched for xhci in generic hcd code
         */
        if ((driver->flags & HCD_MASK) < HCD_USB3) {
-               if (!dev->irq) {
+               retval = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSI);
+               if (retval < 0) {
                        dev_err(&dev->dev,
                        "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
                                pci_name(dev));
                        retval = -ENODEV;
                        goto disable_pci;
                }
-               hcd_irq = dev->irq;
+               hcd_irq = pci_irq_vector(dev, 0);
        }
 
        hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
        if (!hcd) {
                retval = -ENOMEM;
-               goto disable_pci;
+               goto free_irq_vectors;
        }
 
        hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) &&
@@ -286,6 +287,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id,
 
 put_hcd:
        usb_put_hcd(hcd);
+free_irq_vectors:
+       if ((driver->flags & HCD_MASK) < HCD_USB3)
+               pci_free_irq_vectors(dev);
 disable_pci:
        pci_disable_device(dev);
        dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);
@@ -343,6 +347,8 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
                up_read(&companions_rwsem);
        }
        usb_put_hcd(hcd);
+       if ((hcd->driver->flags & HCD_MASK) < HCD_USB3)
+               pci_free_irq_vectors(dev);
        pci_disable_device(dev);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
@@ -454,7 +460,7 @@ static int suspend_common(struct device *dev, bool do_wakeup)
         * synchronized here.
         */
        if (!hcd->msix_enabled)
-               synchronize_irq(pci_dev->irq);
+               synchronize_irq(pci_irq_vector(pci_dev, 0));
 
        /* Downstream ports from this root hub should already be quiesced, so
         * there will be no DMA activity.  Now we can shut down the upstream