[PATCH 4/5] USB: xHCI: use generic hcd-pci callbacks for MSI support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux