aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/lpfc/lpfc.h10
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c97
3 files changed, 91 insertions, 22 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index cbe07d79bd12..10f983b479c6 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -392,6 +392,13 @@ enum hba_temp_state {
392 HBA_OVER_TEMP 392 HBA_OVER_TEMP
393}; 393};
394 394
395enum intr_type_t {
396 NONE = 0,
397 INTx,
398 MSI,
399 MSIX,
400};
401
395struct lpfc_hba { 402struct lpfc_hba {
396 struct lpfc_sli sli; 403 struct lpfc_sli sli;
397 uint32_t sli_rev; /* SLI2 or SLI3 */ 404 uint32_t sli_rev; /* SLI2 or SLI3 */
@@ -555,7 +562,8 @@ struct lpfc_hba {
555 mempool_t *nlp_mem_pool; 562 mempool_t *nlp_mem_pool;
556 563
557 struct fc_host_statistics link_stats; 564 struct fc_host_statistics link_stats;
558 uint8_t using_msi; 565 enum intr_type_t intr_type;
566 struct msix_entry msix_entries[1];
559 567
560 struct list_head port_list; 568 struct list_head port_list;
561 struct lpfc_vport *pport; /* physical lpfc_vport pointer */ 569 struct lpfc_vport *pport; /* physical lpfc_vport pointer */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index fc48e40c4d29..b12a841703ca 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1592,9 +1592,11 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
1592# support this feature 1592# support this feature
1593# 0 = MSI disabled (default) 1593# 0 = MSI disabled (default)
1594# 1 = MSI enabled 1594# 1 = MSI enabled
1595# Value range is [0,1]. Default value is 0. 1595# 2 = MSI-X enabled
1596# Value range is [0,2]. Default value is 0.
1596*/ 1597*/
1597LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); 1598LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or "
1599 "MSI-X (2), if possible");
1598 1600
1599/* 1601/*
1600# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. 1602# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 99141545c25e..a087524acf41 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1924,6 +1924,42 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
1924 spin_unlock_irq(shost->host_lock); 1924 spin_unlock_irq(shost->host_lock);
1925} 1925}
1926 1926
1927static int
1928lpfc_enable_msix(struct lpfc_hba *phba)
1929{
1930 int error;
1931
1932 phba->msix_entries[0].entry = 0;
1933 phba->msix_entries[0].vector = 0;
1934
1935 error = pci_enable_msix(phba->pcidev, phba->msix_entries,
1936 ARRAY_SIZE(phba->msix_entries));
1937 if (error) {
1938 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
1939 "0420 Enable MSI-X failed (%d), continuing "
1940 "with MSI\n", error);
1941 pci_disable_msix(phba->pcidev);
1942 return error;
1943 }
1944
1945 error = request_irq(phba->msix_entries[0].vector, lpfc_intr_handler, 0,
1946 LPFC_DRIVER_NAME, phba);
1947 if (error) {
1948 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
1949 "0421 MSI-X request_irq failed (%d), "
1950 "continuing with MSI\n", error);
1951 pci_disable_msix(phba->pcidev);
1952 }
1953 return error;
1954}
1955
1956static void
1957lpfc_disable_msix(struct lpfc_hba *phba)
1958{
1959 free_irq(phba->msix_entries[0].vector, phba);
1960 pci_disable_msix(phba->pcidev);
1961}
1962
1927static int __devinit 1963static int __devinit
1928lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) 1964lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
1929{ 1965{
@@ -2125,24 +2161,36 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
2125 lpfc_debugfs_initialize(vport); 2161 lpfc_debugfs_initialize(vport);
2126 2162
2127 pci_set_drvdata(pdev, shost); 2163 pci_set_drvdata(pdev, shost);
2164 phba->intr_type = NONE;
2128 2165
2129 if (phba->cfg_use_msi) { 2166 if (phba->cfg_use_msi == 2) {
2167 error = lpfc_enable_msix(phba);
2168 if (!error)
2169 phba->intr_type = MSIX;
2170 }
2171
2172 /* Fallback to MSI if MSI-X initialization failed */
2173 if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
2130 retval = pci_enable_msi(phba->pcidev); 2174 retval = pci_enable_msi(phba->pcidev);
2131 if (!retval) 2175 if (!retval)
2132 phba->using_msi = 1; 2176 phba->intr_type = MSI;
2133 else 2177 else
2134 lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 2178 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2135 "0452 Enable MSI failed, continuing " 2179 "0452 Enable MSI failed, continuing "
2136 "with IRQ\n"); 2180 "with IRQ\n");
2137 } 2181 }
2138 2182
2139 retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, 2183 /* MSI-X is the only case the doesn't need to call request_irq */
2140 LPFC_DRIVER_NAME, phba); 2184 if (phba->intr_type != MSIX) {
2141 if (retval) { 2185 retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
2142 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 2186 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
2143 "0451 Enable interrupt handler failed\n"); 2187 if (retval) {
2144 error = retval; 2188 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable "
2145 goto out_disable_msi; 2189 "interrupt handler failed\n");
2190 error = retval;
2191 goto out_disable_msi;
2192 } else if (phba->intr_type != MSI)
2193 phba->intr_type = INTx;
2146 } 2194 }
2147 2195
2148 phba->MBslimaddr = phba->slim_memmap_p; 2196 phba->MBslimaddr = phba->slim_memmap_p;
@@ -2187,9 +2235,14 @@ out_remove_device:
2187out_free_irq: 2235out_free_irq:
2188 lpfc_stop_phba_timers(phba); 2236 lpfc_stop_phba_timers(phba);
2189 phba->pport->work_port_events = 0; 2237 phba->pport->work_port_events = 0;
2190 free_irq(phba->pcidev->irq, phba); 2238
2239 if (phba->intr_type == MSIX)
2240 lpfc_disable_msix(phba);
2241 else
2242 free_irq(phba->pcidev->irq, phba);
2243
2191out_disable_msi: 2244out_disable_msi:
2192 if (phba->using_msi) 2245 if (phba->intr_type == MSI)
2193 pci_disable_msi(phba->pcidev); 2246 pci_disable_msi(phba->pcidev);
2194 destroy_port(vport); 2247 destroy_port(vport);
2195out_kthread_stop: 2248out_kthread_stop:
@@ -2262,10 +2315,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
2262 2315
2263 lpfc_debugfs_terminate(vport); 2316 lpfc_debugfs_terminate(vport);
2264 2317
2265 /* Release the irq reservation */ 2318 if (phba->intr_type == MSIX)
2266 free_irq(phba->pcidev->irq, phba); 2319 lpfc_disable_msix(phba);
2267 if (phba->using_msi) 2320 else {
2268 pci_disable_msi(phba->pcidev); 2321 free_irq(phba->pcidev->irq, phba);
2322 if (phba->intr_type == MSI)
2323 pci_disable_msi(phba->pcidev);
2324 }
2269 2325
2270 pci_set_drvdata(pdev, NULL); 2326 pci_set_drvdata(pdev, NULL);
2271 scsi_host_put(shost); 2327 scsi_host_put(shost);
@@ -2324,10 +2380,13 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
2324 pring = &psli->ring[psli->fcp_ring]; 2380 pring = &psli->ring[psli->fcp_ring];
2325 lpfc_sli_abort_iocb_ring(phba, pring); 2381 lpfc_sli_abort_iocb_ring(phba, pring);
2326 2382
2327 /* Release the irq reservation */ 2383 if (phba->intr_type == MSIX)
2328 free_irq(phba->pcidev->irq, phba); 2384 lpfc_disable_msix(phba);
2329 if (phba->using_msi) 2385 else {
2330 pci_disable_msi(phba->pcidev); 2386 free_irq(phba->pcidev->irq, phba);
2387 if (phba->intr_type == MSI)
2388 pci_disable_msi(phba->pcidev);
2389 }
2331 2390
2332 /* Request a slot reset. */ 2391 /* Request a slot reset. */
2333 return PCI_ERS_RESULT_NEED_RESET; 2392 return PCI_ERS_RESULT_NEED_RESET;