Split the code that enables/disables MSI/MSI-X interrupts from the code that actuall requests/frees these interrupts, and move the former into the generic callbacks called by hcd-pci, in xhci-pci.c. This simplifies the MSI code because it can now use the generic USB interrupt handler. Signed-off-by: Clemens Ladisch <clemens@xxxxxxxxxx> --- drivers/usb/host/xhci-pci.c | 78 +++++++++++++++++++++ drivers/usb/host/xhci.c | 132 +++++------------------------------- 2 files changed, 99 insertions(+), 111 deletions(-) --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -30,6 +30,81 @@ static const char hcd_name[] = "xhci_hcd"; +static int xhci_prepare_msix(struct xhci_hcd *xhci) +{ + int i, ret; + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + /* + * calculate number of msi-x vectors supported. + * - HCS_MAX_INTRS: the max number of interrupts the host can handle, + * with max number of interrupters based on the xhci HCSPARAMS1. + * - num_online_cpus: maximum msi-x vectors per CPUs core. + * Add additional 1 vector to ensure always available interrupt. + */ + xhci->msix_count = min(num_online_cpus() + 1, + HCS_MAX_INTRS(xhci->hcs_params1)); + + xhci->msix_entries = + kmalloc(sizeof(*xhci->msix_entries) * xhci->msix_count, + GFP_KERNEL); + if (!xhci->msix_entries) { + xhci_err(xhci, "Failed to allocate MSI-X entries\n"); + return -ENOMEM; + } + + for (i = 0; i < xhci->msix_count; i++) { + xhci->msix_entries[i].entry = i; + xhci->msix_entries[i].vector = 0; + } + + ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); + if (ret) { + xhci_err(xhci, "Failed to enable MSI-X\n"); + goto free_entries; + } + + return 0; + +free_entries: + kfree(xhci->msix_entries); + xhci->msix_entries = NULL; + return ret; +} + +static int xhci_prepare_msi(struct xhci_hcd *xhci) +{ + int ret; + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + ret = pci_enable_msi(pdev); + if (ret) { + xhci_err(xhci, "Failed to enable MSI\n"); + return ret; + } + + return 0; +} + +static int xhci_pci_prepare_irq(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (xhci_prepare_msix(xhci) != 0) + xhci_prepare_msi(xhci); + return 0; +} + +static void xhci_pci_cleanup_irq(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + kfree(xhci->msix_entries); + pci_disable_msix(pdev); + pci_disable_msi(pdev); +} + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { @@ -118,6 +193,9 @@ static const struct hc_driver xhci_pci_h .irq = xhci_irq, .flags = HCD_MEMORY | HCD_USB3, + .pci_prepare_irq = xhci_pci_prepare_irq, + .pci_cleanup_irq = xhci_pci_cleanup_irq, + /* * basic lifecycle operations */ --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -172,7 +172,7 @@ int xhci_reset(struct xhci_hcd *xhci) return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); } -static irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) +static irqreturn_t xhci_msix_irq(int irq, struct usb_hcd *hcd) { irqreturn_t ret; @@ -187,10 +187,9 @@ static irqreturn_t xhci_msi_irq(int irq, * Free IRQs * free all IRQs request */ -static void xhci_free_irq(struct xhci_hcd *xhci) +static void xhci_free_msix_irqs(struct xhci_hcd *xhci) { int i; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); /* return if using legacy interrupt */ if (xhci_to_hcd(xhci)->irq >= 0) @@ -201,112 +200,34 @@ static void xhci_free_irq(struct xhci_hc if (xhci->msix_entries[i].vector) free_irq(xhci->msix_entries[i].vector, xhci_to_hcd(xhci)); - } else if (pdev->irq >= 0) - free_irq(pdev->irq, xhci_to_hcd(xhci)); - - return; -} - -/* - * Set up MSI - */ -static int xhci_setup_msi(struct xhci_hcd *xhci) -{ - int ret; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - ret = pci_enable_msi(pdev); - if (ret) { - xhci_err(xhci, "failed to allocate MSI entry\n"); - return ret; } - - ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) { - xhci_err(xhci, "disable MSI interrupt\n"); - pci_disable_msi(pdev); - } - - return ret; } - /* * Set up MSI-X */ static int xhci_setup_msix(struct xhci_hcd *xhci) { int i, ret = 0; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - /* - * calculate number of msi-x vectors supported. - * - HCS_MAX_INTRS: the max number of interrupts the host can handle, - * with max number of interrupters based on the xhci HCSPARAMS1. - * - num_online_cpus: maximum msi-x vectors per CPUs core. - * Add additional 1 vector to ensure always available interrupt. - */ - xhci->msix_count = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); - - xhci->msix_entries = - kmalloc((sizeof(struct msix_entry))*xhci->msix_count, - GFP_KERNEL); - if (!xhci->msix_entries) { - xhci_err(xhci, "Failed to allocate MSI-X entries\n"); - return -ENOMEM; - } - - for (i = 0; i < xhci->msix_count; i++) { - xhci->msix_entries[i].entry = i; - xhci->msix_entries[i].vector = 0; - } - - ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); - if (ret) { - xhci_err(xhci, "Failed to enable MSI-X\n"); - goto free_entries; - } for (i = 0; i < xhci->msix_count; i++) { ret = request_irq(xhci->msix_entries[i].vector, - (irq_handler_t)xhci_msi_irq, + (irq_handler_t)xhci_msix_irq, 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) - goto disable_msix; + if (ret) { + xhci_err(xhci, "request irq %u failed\n", + xhci->msix_entries[i].vector); + goto free_irqs; + } } return ret; -disable_msix: - xhci_err(xhci, "disable MSI-X interrupt\n"); - xhci_free_irq(xhci); - pci_disable_msix(pdev); -free_entries: - kfree(xhci->msix_entries); - xhci->msix_entries = NULL; +free_irqs: + xhci_free_msix_irqs(xhci); return ret; } -/* Free any IRQs and disable MSI-X */ -static void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - xhci_free_irq(xhci); - - if (xhci->msix_entries) { - pci_disable_msix(pdev); - kfree(xhci->msix_entries); - xhci->msix_entries = NULL; - } else { - pci_disable_msi(pdev); - } - - return; -} - /* * Initialize memory for HCD and xHC (one-time init). * @@ -501,33 +422,22 @@ int xhci_run(struct usb_hcd *hcd) u64 temp_64; u32 ret; struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); void (*doorbell)(struct xhci_hcd *) = NULL; hcd->uses_new_polling = 1; hcd->poll_rh = 0; xhci_dbg(xhci, "xhci_run\n"); - /* unregister the legacy interrupt */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = -1; - - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); - - if (ret) { - /* fall back to legacy interrupt*/ - ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (ret) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); + + 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; - } - hcd->irq = pdev->irq; } #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING @@ -614,7 +524,7 @@ void xhci_stop(struct usb_hcd *hcd) spin_lock_irq(&xhci->lock); xhci_halt(xhci); xhci_reset(xhci); - xhci_cleanup_msix(xhci); + xhci_free_msix_irqs(xhci); spin_unlock_irq(&xhci->lock); #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING @@ -650,7 +560,7 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_lock_irq(&xhci->lock); xhci_halt(xhci); - xhci_cleanup_msix(xhci); + xhci_free_msix_irqs(xhci); spin_unlock_irq(&xhci->lock); xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", -- 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