[PATCH 01/17] lpfc: Use new pci_alloc_irq_vectors() interface

James Smart jsmart2021 at gmail.com
Tue Jan 17 17:20:44 PST 2017


Move to new pci_alloc_irq_vectors() interface for intx/msi/msix

Note: io channel paradigm remains, for now.

Signed-off-by: Dick Kennedy <dick.kennedy at broadcom.com>
Signed-off-by: James Smart <james.smart at broadcom.com>
---
 drivers/scsi/lpfc/lpfc_init.c | 227 ++++++++++++++++++++++++++++--------------
 1 file changed, 154 insertions(+), 73 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4776fd8..7a17bd0 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -8485,16 +8485,14 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to enable the MSI-X interrupt vectors to device
- * with SLI-3 interface specs. The kernel function pci_enable_msix_exact()
- * is called to enable the MSI-X vectors. Note that pci_enable_msix_exact(),
- * once invoked, enables either all or nothing, depending on the current
- * availability of PCI vector resources. The device driver is responsible
+ * with SLI-3 interface specs. The kernel function pci_alloc_irq_vectors()
+ * is called to enable the MSI-X vectors. The device driver is responsible
  * for calling the individual request_irq() to register each MSI-X vector
  * with a interrupt handler, which is done in this function. Note that
  * later when device is unloading, the driver should always call free_irq()
  * on all MSI-X vectors it has done request_irq() on before calling
- * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device
- * will be left with MSI-X enabled and leaks its vectors.
+ * pci_free_irq_vectors(). Failure to do so results in a BUG_ON() and a
+ * device will be left with MSI-X enabled and leaks its vectors.
  *
  * Return codes
  *   0 - successful
@@ -8503,21 +8501,33 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
 static int
 lpfc_sli_enable_msix(struct lpfc_hba *phba)
 {
-	int rc, i;
+	int vectors, rc, i;
 	LPFC_MBOXQ_t *pmb;
+	unsigned int irq_flags;
+	uint32_t min_cnt;
 
 	/* Set up MSI-X multi-message vectors */
 	for (i = 0; i < LPFC_MSIX_VECTORS; i++)
 		phba->msix_entries[i].entry = i;
 
 	/* Configure MSI-X capability structure */
-	rc = pci_enable_msix_exact(phba->pcidev, phba->msix_entries,
-				   LPFC_MSIX_VECTORS);
-	if (rc) {
+	/* Allocate explicitly LPFC_MSIX_VECTORS number of vectors */
+	min_cnt = LPFC_MSIX_VECTORS;
+	irq_flags = PCI_IRQ_MSIX;
+	vectors = pci_alloc_irq_vectors(phba->pcidev, min_cnt,
+					LPFC_MSIX_VECTORS, irq_flags);
+	if (vectors < 0) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"0420 PCI enable MSI-X failed (%d)\n", rc);
+				"0420 PCI enable MSI-X failed (%d)\n",
+				vectors);
+		rc = -1;
 		goto vec_fail_out;
 	}
+
+	/* Complete the MSIX vector setup. */
+	for (i = 0; i < LPFC_MSIX_VECTORS; i++)
+		phba->msix_entries[i].vector = pci_irq_vector(phba->pcidev, i);
+
 	for (i = 0; i < LPFC_MSIX_VECTORS; i++)
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"0477 MSI-X entry[%d]: vector=x%x "
@@ -8593,7 +8603,7 @@ lpfc_sli_enable_msix(struct lpfc_hba *phba)
 
 msi_fail_out:
 	/* Unconfigure MSI-X capability structure */
-	pci_disable_msix(phba->pcidev);
+	pci_free_irq_vectors(phba->pcidev);
 
 vec_fail_out:
 	return rc;
@@ -8615,7 +8625,7 @@ lpfc_sli_disable_msix(struct lpfc_hba *phba)
 	for (i = 0; i < LPFC_MSIX_VECTORS; i++)
 		free_irq(phba->msix_entries[i].vector, phba);
 	/* Disable MSI-X */
-	pci_disable_msix(phba->pcidev);
+	pci_free_irq_vectors(phba->pcidev);
 
 	return;
 }
@@ -8625,10 +8635,10 @@ lpfc_sli_disable_msix(struct lpfc_hba *phba)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to enable the MSI interrupt mode to device with
- * SLI-3 interface spec. The kernel function pci_enable_msi() is called to
- * enable the MSI vector. The device driver is responsible for calling the
- * request_irq() to register MSI vector with a interrupt the handler, which
- * is done in this function.
+ * SLI-3 interface spec. The kernel function pci_alloc_irq_vectors() is
+ * called to enable the MSI vector. The device driver is responsible for
+ * calling the request_irq() to register MSI vector with a interrupt the
+ * handler, which is done in this function.
  *
  * Return codes
  * 	0 - successful
@@ -8637,10 +8647,18 @@ lpfc_sli_disable_msix(struct lpfc_hba *phba)
 static int
 lpfc_sli_enable_msi(struct lpfc_hba *phba)
 {
-	int rc;
+	int vector, rc;
+	unsigned int irq_flags;
+
+	/* The adapter supports all these modes and wants the irq affinity.
+	 * The kernel documents MSIX first, then MSI and then IRQ.  No
+	 * need for failover code.
+	 */
+	irq_flags = PCI_IRQ_MSI;
 
-	rc = pci_enable_msi(phba->pcidev);
-	if (!rc)
+	/* Only 1 vector. */
+	rc = pci_alloc_irq_vectors(phba->pcidev, 1, 1, irq_flags);
+	if (rc == 1)
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"0462 PCI enable MSI mode success.\n");
 	else {
@@ -8649,10 +8667,11 @@ lpfc_sli_enable_msi(struct lpfc_hba *phba)
 		return rc;
 	}
 
-	rc = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler,
+	vector = pci_irq_vector(phba->pcidev, 0);
+	rc = request_irq(vector, lpfc_sli_intr_handler,
 			 0, LPFC_DRIVER_NAME, phba);
 	if (rc) {
-		pci_disable_msi(phba->pcidev);
+		pci_free_irq_vectors(phba->pcidev);
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 				"0478 MSI request_irq failed (%d)\n", rc);
 	}
@@ -8665,15 +8684,18 @@ lpfc_sli_enable_msi(struct lpfc_hba *phba)
  *
  * This routine is invoked to disable the MSI interrupt mode to device with
  * SLI-3 interface spec. The driver calls free_irq() on MSI vector it has
- * done request_irq() on before calling pci_disable_msi(). Failure to do so
- * results in a BUG_ON() and a device will be left with MSI enabled and leaks
- * its vector.
+ * done request_irq() on before calling pci_free_irq_vectors(). Failure to
+ * do so results in a BUG_ON() and a device will be left with MSI enabled
+ * and leaks its vector.
  */
 static void
 lpfc_sli_disable_msi(struct lpfc_hba *phba)
 {
-	free_irq(phba->pcidev->irq, phba);
-	pci_disable_msi(phba->pcidev);
+	int vector;
+
+	vector = pci_irq_vector(phba->pcidev, 0);
+	free_irq(vector, phba);
+	pci_free_irq_vectors(phba->pcidev);
 	return;
 }
 
@@ -8697,7 +8719,7 @@ static uint32_t
 lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 {
 	uint32_t intr_mode = LPFC_INTR_ERROR;
-	int retval;
+	int retval, vector;
 
 	if (cfg_mode == 2) {
 		/* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
@@ -8725,7 +8747,24 @@ lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 
 	/* Fallback to INTx if both MSI-X/MSI initalization failed */
 	if (phba->intr_type == NONE) {
-		retval = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler,
+
+		/* Only 1 vector. */
+		retval = pci_alloc_irq_vectors(phba->pcidev, 1, 1,
+						PCI_IRQ_LEGACY);
+		if (retval < 0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"6313 Failed to Alloc INTX Vector "
+					"(%d)\n", retval);
+		}
+
+		vector = pci_irq_vector(phba->pcidev, 0);
+		if (vector < 0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"9998 Failed to Get INTX Vector "
+					"Number (%d)\n", vector);
+		}
+
+		retval = request_irq(vector, lpfc_sli4_intr_handler,
 				     IRQF_SHARED, LPFC_DRIVER_NAME, phba);
 		if (!retval) {
 			/* Indicate initialization to INTx mode */
@@ -8748,13 +8787,18 @@ lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 static void
 lpfc_sli_disable_intr(struct lpfc_hba *phba)
 {
+	int vector;
+
 	/* Disable the currently initialized interrupt mode */
 	if (phba->intr_type == MSIX)
 		lpfc_sli_disable_msix(phba);
 	else if (phba->intr_type == MSI)
 		lpfc_sli_disable_msi(phba);
-	else if (phba->intr_type == INTx)
-		free_irq(phba->pcidev->irq, phba);
+	else if (phba->intr_type == INTx) {
+		vector = pci_irq_vector(phba->pcidev, 0);
+		free_irq(vector, phba);
+		pci_free_irq_vectors(phba->pcidev);
+	}
 
 	/* Reset interrupt management states */
 	phba->intr_type = NONE;
@@ -9048,14 +9092,14 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to enable the MSI-X interrupt vectors to device
- * with SLI-4 interface spec. The kernel function pci_enable_msix_range()
+ * with SLI-4 interface spec. The kernel function pci_alloc_irq_vectors()
  * is called to enable the MSI-X vectors. The device driver is responsible
  * for calling the individual request_irq() to register each MSI-X vector
  * with a interrupt handler, which is done in this function. Note that
  * later when device is unloading, the driver should always call free_irq()
  * on all MSI-X vectors it has done request_irq() on before calling
- * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device
- * will be left with MSI-X enabled and leaks its vectors.
+ * pci_free_irq_vectors(). Failure to do so results in a BUG_ON() and
+ * a device will be left with MSI-X enabled and leaks its vectors.
  *
  * Return codes
  * 0 - successful
@@ -9065,6 +9109,8 @@ static int
 lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 {
 	int vectors, rc, index;
+	unsigned int irq_flags;
+	uint32_t min_cnt;
 
 	/* Set up MSI-X multi-message vectors */
 	for (index = 0; index < phba->cfg_fcp_io_channel; index++)
@@ -9076,14 +9122,28 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 		phba->sli4_hba.msix_entries[index].entry = index;
 		vectors++;
 	}
-	rc = pci_enable_msix_range(phba->pcidev, phba->sli4_hba.msix_entries,
-				   2, vectors);
-	if (rc < 0) {
+
+	/* Need a vector for slow-path and fast-path minimally.  But for target
+	 * mode, the min is just one to service a single RQ.
+	 */
+	min_cnt = 2;
+	irq_flags = PCI_IRQ_MSIX | PCI_IRQ_AFFINITY;
+	vectors = pci_alloc_irq_vectors(phba->pcidev, min_cnt, vectors,
+					irq_flags);
+	if (vectors < 0) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"0484 PCI enable MSI-X failed (%d)\n", rc);
+				"0484 PCI enable MSI-X failed (%d) min 2 "
+				"max %d\n",
+				vectors, phba->cfg_fcp_io_channel);
+		rc = -1;
 		goto vec_fail_out;
 	}
-	vectors = rc;
+
+	/* Complete the MSIX vector setup. */
+	for (index = 0; index < vectors; index++) {
+		phba->sli4_hba.msix_entries[index].vector =
+			pci_irq_vector(phba->pcidev, index);
+	}
 
 	/* Log MSI-X vector assignment */
 	for (index = 0; index < vectors; index++)
@@ -9141,14 +9201,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
 cfg_fail_out:
 	/* free the irq already requested */
 	for (--index; index >= 0; index--) {
-		irq_set_affinity_hint(phba->sli4_hba.msix_entries[index].
-					  vector, NULL);
 		free_irq(phba->sli4_hba.msix_entries[index].vector,
 			 &phba->sli4_hba.fcp_eq_hdl[index]);
 	}
-
-	/* Unconfigure MSI-X capability structure */
-	pci_disable_msix(phba->pcidev);
+	pci_free_irq_vectors(phba->pcidev);
 
 vec_fail_out:
 	return rc;
@@ -9168,8 +9224,6 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
 
 	/* Free up MSI-X multi-message vectors */
 	for (index = 0; index < phba->cfg_fcp_io_channel; index++) {
-		irq_set_affinity_hint(phba->sli4_hba.msix_entries[index].
-					  vector, NULL);
 		free_irq(phba->sli4_hba.msix_entries[index].vector,
 			 &phba->sli4_hba.fcp_eq_hdl[index]);
 	}
@@ -9177,9 +9231,7 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
 		free_irq(phba->sli4_hba.msix_entries[index].vector,
 			 &phba->sli4_hba.fcp_eq_hdl[index]);
 	}
-	/* Disable MSI-X */
-	pci_disable_msix(phba->pcidev);
-
+	pci_free_irq_vectors(phba->pcidev);
 	return;
 }
 
@@ -9188,7 +9240,7 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to enable the MSI interrupt mode to device with
- * SLI-4 interface spec. The kernel function pci_enable_msi() is called
+ * SLI-4 interface spec. The kernel function pci_alloc_irq_vectors() is called
  * to enable the MSI vector. The device driver is responsible for calling
  * the request_irq() to register MSI vector with a interrupt the handler,
  * which is done in this function.
@@ -9200,10 +9252,18 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
 static int
 lpfc_sli4_enable_msi(struct lpfc_hba *phba)
 {
-	int rc, index;
+	int rc, index, vector;
+	unsigned int irq_flags;
 
-	rc = pci_enable_msi(phba->pcidev);
-	if (!rc)
+	/* The adapter supports all these modes and wants the irq affinity.
+	 * The kernel documents MSIX first, then MSI and then IRQ.  No
+	 * need for failover code.
+	 */
+	irq_flags = PCI_IRQ_MSI | PCI_IRQ_AFFINITY;
+
+	/* Only 1 vector. */
+	rc = pci_alloc_irq_vectors(phba->pcidev, 1, 1, irq_flags);
+	if (rc == 1)
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"0487 PCI enable MSI mode success.\n");
 	else {
@@ -9212,10 +9272,11 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
 		return rc;
 	}
 
-	rc = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler,
+	vector = pci_irq_vector(phba->pcidev, 0);
+	rc = request_irq(vector, lpfc_sli4_intr_handler,
 			 0, LPFC_DRIVER_NAME, phba);
 	if (rc) {
-		pci_disable_msi(phba->pcidev);
+		pci_free_irq_vectors(phba->pcidev);
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 				"0490 MSI request_irq failed (%d)\n", rc);
 		return rc;
@@ -9239,15 +9300,18 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
  *
  * This routine is invoked to disable the MSI interrupt mode to device with
  * SLI-4 interface spec. The driver calls free_irq() on MSI vector it has
- * done request_irq() on before calling pci_disable_msi(). Failure to do so
- * results in a BUG_ON() and a device will be left with MSI enabled and leaks
- * its vector.
+ * done request_irq() on before calling pci_free_irq_vectors(). Failure to
+ * do so results in a BUG_ON() and a device will be left with MSI enabled
+ * and leaks its vector.
  **/
 static void
 lpfc_sli4_disable_msi(struct lpfc_hba *phba)
 {
-	free_irq(phba->pcidev->irq, phba);
-	pci_disable_msi(phba->pcidev);
+	int vector;
+
+	vector = pci_irq_vector(phba->pcidev, 0);
+	free_irq(vector, phba);
+	pci_free_irq_vectors(phba->pcidev);
 	return;
 }
 
@@ -9271,19 +9335,15 @@ static uint32_t
 lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 {
 	uint32_t intr_mode = LPFC_INTR_ERROR;
-	int retval, index;
+	int retval, index, vector;
 
 	if (cfg_mode == 2) {
-		/* Preparation before conf_msi mbox cmd */
-		retval = 0;
+		/* Now, try to enable MSI-X interrupt mode */
+		retval = lpfc_sli4_enable_msix(phba);
 		if (!retval) {
-			/* Now, try to enable MSI-X interrupt mode */
-			retval = lpfc_sli4_enable_msix(phba);
-			if (!retval) {
-				/* Indicate initialization to MSI-X mode */
-				phba->intr_type = MSIX;
-				intr_mode = 2;
-			}
+			/* Indicate initialization to MSI-X mode */
+			phba->intr_type = MSIX;
+			intr_mode = 2;
 		}
 	}
 
@@ -9299,7 +9359,23 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 
 	/* Fallback to INTx if both MSI-X/MSI initalization failed */
 	if (phba->intr_type == NONE) {
-		retval = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler,
+		/* Only 1 vector. */
+		retval = pci_alloc_irq_vectors(phba->pcidev, 1, 1,
+						PCI_IRQ_LEGACY);
+		if (retval < 0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"6313 Failed to Alloc INTX Vector "
+					"(%d)\n", retval);
+		}
+
+		vector = pci_irq_vector(phba->pcidev, 0);
+		if (vector < 0) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"9998 Failed to Get INTX Vector "
+					"Number (%d)\n", vector);
+		}
+
+		retval = request_irq(vector, lpfc_sli4_intr_handler,
 				     IRQF_SHARED, LPFC_DRIVER_NAME, phba);
 		if (!retval) {
 			/* Indicate initialization to INTx mode */
@@ -9335,13 +9411,18 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
 static void
 lpfc_sli4_disable_intr(struct lpfc_hba *phba)
 {
+	int vector;
+
 	/* Disable the currently initialized interrupt mode */
 	if (phba->intr_type == MSIX)
 		lpfc_sli4_disable_msix(phba);
 	else if (phba->intr_type == MSI)
 		lpfc_sli4_disable_msi(phba);
-	else if (phba->intr_type == INTx)
-		free_irq(phba->pcidev->irq, phba);
+	else if (phba->intr_type == INTx) {
+		vector = pci_irq_vector(phba->pcidev, 0);
+		free_irq(vector, phba);
+		pci_free_irq_vectors(phba->pcidev);
+	}
 
 	/* Reset interrupt management states */
 	phba->intr_type = NONE;
-- 
2.5.0




More information about the Linux-nvme mailing list