Commit db2378e0 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.2.5 : Add MSI-X single message support

Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 1b32f6aa
...@@ -392,6 +392,13 @@ enum hba_temp_state { ...@@ -392,6 +392,13 @@ enum hba_temp_state {
HBA_OVER_TEMP HBA_OVER_TEMP
}; };
enum intr_type_t {
NONE = 0,
INTx,
MSI,
MSIX,
};
struct lpfc_hba { struct lpfc_hba {
struct lpfc_sli sli; struct lpfc_sli sli;
uint32_t sli_rev; /* SLI2 or SLI3 */ uint32_t sli_rev; /* SLI2 or SLI3 */
...@@ -555,7 +562,8 @@ struct lpfc_hba { ...@@ -555,7 +562,8 @@ struct lpfc_hba {
mempool_t *nlp_mem_pool; mempool_t *nlp_mem_pool;
struct fc_host_statistics link_stats; struct fc_host_statistics link_stats;
uint8_t using_msi; enum intr_type_t intr_type;
struct msix_entry msix_entries[1];
struct list_head port_list; struct list_head port_list;
struct lpfc_vport *pport; /* physical lpfc_vport pointer */ struct lpfc_vport *pport; /* physical lpfc_vport pointer */
......
...@@ -1592,9 +1592,11 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, ...@@ -1592,9 +1592,11 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
# support this feature # support this feature
# 0 = MSI disabled (default) # 0 = MSI disabled (default)
# 1 = MSI enabled # 1 = MSI enabled
# Value range is [0,1]. Default value is 0. # 2 = MSI-X enabled
# Value range is [0,2]. Default value is 0.
*/ */
LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or "
"MSI-X (2), if possible");
/* /*
# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
......
...@@ -1924,6 +1924,42 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) ...@@ -1924,6 +1924,42 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
spin_unlock_irq(shost->host_lock); spin_unlock_irq(shost->host_lock);
} }
static int
lpfc_enable_msix(struct lpfc_hba *phba)
{
int error;
phba->msix_entries[0].entry = 0;
phba->msix_entries[0].vector = 0;
error = pci_enable_msix(phba->pcidev, phba->msix_entries,
ARRAY_SIZE(phba->msix_entries));
if (error) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0420 Enable MSI-X failed (%d), continuing "
"with MSI\n", error);
pci_disable_msix(phba->pcidev);
return error;
}
error = request_irq(phba->msix_entries[0].vector, lpfc_intr_handler, 0,
LPFC_DRIVER_NAME, phba);
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0421 MSI-X request_irq failed (%d), "
"continuing with MSI\n", error);
pci_disable_msix(phba->pcidev);
}
return error;
}
static void
lpfc_disable_msix(struct lpfc_hba *phba)
{
free_irq(phba->msix_entries[0].vector, phba);
pci_disable_msix(phba->pcidev);
}
static int __devinit static int __devinit
lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
{ {
...@@ -2125,24 +2161,36 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -2125,24 +2161,36 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
lpfc_debugfs_initialize(vport); lpfc_debugfs_initialize(vport);
pci_set_drvdata(pdev, shost); pci_set_drvdata(pdev, shost);
phba->intr_type = NONE;
if (phba->cfg_use_msi) { if (phba->cfg_use_msi == 2) {
error = lpfc_enable_msix(phba);
if (!error)
phba->intr_type = MSIX;
}
/* Fallback to MSI if MSI-X initialization failed */
if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
retval = pci_enable_msi(phba->pcidev); retval = pci_enable_msi(phba->pcidev);
if (!retval) if (!retval)
phba->using_msi = 1; phba->intr_type = MSI;
else else
lpfc_printf_log(phba, KERN_INFO, LOG_INIT, lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0452 Enable MSI failed, continuing " "0452 Enable MSI failed, continuing "
"with IRQ\n"); "with IRQ\n");
} }
retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, /* MSI-X is the only case the doesn't need to call request_irq */
LPFC_DRIVER_NAME, phba); if (phba->intr_type != MSIX) {
if (retval) { retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, IRQF_SHARED, LPFC_DRIVER_NAME, phba);
"0451 Enable interrupt handler failed\n"); if (retval) {
error = retval; lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable "
goto out_disable_msi; "interrupt handler failed\n");
error = retval;
goto out_disable_msi;
} else if (phba->intr_type != MSI)
phba->intr_type = INTx;
} }
phba->MBslimaddr = phba->slim_memmap_p; phba->MBslimaddr = phba->slim_memmap_p;
...@@ -2187,9 +2235,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) ...@@ -2187,9 +2235,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
out_free_irq: out_free_irq:
lpfc_stop_phba_timers(phba); lpfc_stop_phba_timers(phba);
phba->pport->work_port_events = 0; phba->pport->work_port_events = 0;
free_irq(phba->pcidev->irq, phba);
if (phba->intr_type == MSIX)
lpfc_disable_msix(phba);
else
free_irq(phba->pcidev->irq, phba);
out_disable_msi: out_disable_msi:
if (phba->using_msi) if (phba->intr_type == MSI)
pci_disable_msi(phba->pcidev); pci_disable_msi(phba->pcidev);
destroy_port(vport); destroy_port(vport);
out_kthread_stop: out_kthread_stop:
...@@ -2262,10 +2315,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev) ...@@ -2262,10 +2315,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
lpfc_debugfs_terminate(vport); lpfc_debugfs_terminate(vport);
/* Release the irq reservation */ if (phba->intr_type == MSIX)
free_irq(phba->pcidev->irq, phba); lpfc_disable_msix(phba);
if (phba->using_msi) else {
pci_disable_msi(phba->pcidev); free_irq(phba->pcidev->irq, phba);
if (phba->intr_type == MSI)
pci_disable_msi(phba->pcidev);
}
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
scsi_host_put(shost); scsi_host_put(shost);
...@@ -2324,10 +2380,13 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, ...@@ -2324,10 +2380,13 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
pring = &psli->ring[psli->fcp_ring]; pring = &psli->ring[psli->fcp_ring];
lpfc_sli_abort_iocb_ring(phba, pring); lpfc_sli_abort_iocb_ring(phba, pring);
/* Release the irq reservation */ if (phba->intr_type == MSIX)
free_irq(phba->pcidev->irq, phba); lpfc_disable_msix(phba);
if (phba->using_msi) else {
pci_disable_msi(phba->pcidev); free_irq(phba->pcidev->irq, phba);
if (phba->intr_type == MSI)
pci_disable_msi(phba->pcidev);
}
/* Request a slot reset. */ /* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET; return PCI_ERS_RESULT_NEED_RESET;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment