usb: hcd: Try MSI interrupts on PCI devices

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>
This commit is contained in:
Andy Shevchenko 2020-07-02 17:30:45 +03:00 committed by Greg Kroah-Hartman
parent eed3c957dd
commit 306c54d0ed
1 changed files with 10 additions and 4 deletions

View 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 * make sure irq setup is not touched for xhci in generic hcd code
*/ */
if ((driver->flags & HCD_MASK) < HCD_USB3) { 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, dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n", "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
pci_name(dev)); pci_name(dev));
retval = -ENODEV; retval = -ENODEV;
goto disable_pci; goto disable_pci;
} }
hcd_irq = dev->irq; hcd_irq = pci_irq_vector(dev, 0);
} }
hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
if (!hcd) { if (!hcd) {
retval = -ENOMEM; retval = -ENOMEM;
goto disable_pci; goto free_irq_vectors;
} }
hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) && 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: put_hcd:
usb_put_hcd(hcd); usb_put_hcd(hcd);
free_irq_vectors:
if ((driver->flags & HCD_MASK) < HCD_USB3)
pci_free_irq_vectors(dev);
disable_pci: disable_pci:
pci_disable_device(dev); pci_disable_device(dev);
dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); 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); up_read(&companions_rwsem);
} }
usb_put_hcd(hcd); usb_put_hcd(hcd);
if ((hcd->driver->flags & HCD_MASK) < HCD_USB3)
pci_free_irq_vectors(dev);
pci_disable_device(dev); pci_disable_device(dev);
} }
EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
@ -454,7 +460,7 @@ static int suspend_common(struct device *dev, bool do_wakeup)
* synchronized here. * synchronized here.
*/ */
if (!hcd->msix_enabled) 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 /* Downstream ports from this root hub should already be quiesced, so
* there will be no DMA activity. Now we can shut down the upstream * there will be no DMA activity. Now we can shut down the upstream