[SCSI] lpfc 8.2.5 : Add MSI-X single message support
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
committed by
James Bottomley
parent
1b32f6aa99
commit
db2378e091
@@ -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 {
|
|||||||
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,
|
|||||||
# 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)
|
|||||||
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)
|
|||||||
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 @@ out_remove_device:
|
|||||||
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)
|
|||||||
|
|
||||||
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,
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user