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@xxxxxxxxxxxx> Signed-off-by: James Smart <james.smart@xxxxxxxxxxxx> --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html