aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nvme
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2016-04-08 18:09:10 -0400
committerJens Axboe <axboe@fb.com>2016-04-12 15:44:00 -0400
commit788e15abbb9408c9399d7e3445ac9afb3b2fd7d6 (patch)
tree39a05fb007574db3ad1b7f8f329114042883a162 /drivers/nvme
parente0489487ec9cd79ee1fa0dc5d3789c08b0e51a2c (diff)
NVMe: Always use MSI/MSI-x interrupts
Multiple users have reported device initialization failure due the driver not receiving legacy PCI interrupts. This is not unique to any particular controller, but has been observed on multiple platforms. There have been no issues reported or observed when with message signaled interrupts, so this patch attempts to use MSI-x during initialization, falling back to MSI. If that fails, legacy would become the default. The setup_io_queues error handling had to change as a result: the admin queue's msix_entry used to be initialized to the legacy IRQ. The case where nr_io_queues is 0 would fail request_irq when setting up the admin queue's interrupt since re-enabling MSI-x fails with 0 vectors, leaving the admin queue's msix_entry invalid. Instead, return success immediately. Reported-by: Tim Muhlemmer <muhlemmer@gmail.com> Reported-by: Jon Derrick <jonathan.derrick@intel.com> Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/nvme')
-rw-r--r--drivers/nvme/host/pci.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 24ccda303efb..94d45b00d40f 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1478,8 +1478,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
1478 if (result > 0) { 1478 if (result > 0) {
1479 dev_err(dev->ctrl.device, 1479 dev_err(dev->ctrl.device,
1480 "Could not set queue count (%d)\n", result); 1480 "Could not set queue count (%d)\n", result);
1481 nr_io_queues = 0; 1481 return 0;
1482 result = 0;
1483 } 1482 }
1484 1483
1485 if (dev->cmb && NVME_CMB_SQS(dev->cmbsz)) { 1484 if (dev->cmb && NVME_CMB_SQS(dev->cmbsz)) {
@@ -1513,7 +1512,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
1513 * If we enable msix early due to not intx, disable it again before 1512 * If we enable msix early due to not intx, disable it again before
1514 * setting up the full range we need. 1513 * setting up the full range we need.
1515 */ 1514 */
1516 if (!pdev->irq) 1515 if (pdev->msi_enabled)
1516 pci_disable_msi(pdev);
1517 else if (pdev->msix_enabled)
1517 pci_disable_msix(pdev); 1518 pci_disable_msix(pdev);
1518 1519
1519 for (i = 0; i < nr_io_queues; i++) 1520 for (i = 0; i < nr_io_queues; i++)
@@ -1696,7 +1697,6 @@ static int nvme_pci_enable(struct nvme_dev *dev)
1696 if (pci_enable_device_mem(pdev)) 1697 if (pci_enable_device_mem(pdev))
1697 return result; 1698 return result;
1698 1699
1699 dev->entry[0].vector = pdev->irq;
1700 pci_set_master(pdev); 1700 pci_set_master(pdev);
1701 1701
1702 if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) && 1702 if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
@@ -1709,13 +1709,18 @@ static int nvme_pci_enable(struct nvme_dev *dev)
1709 } 1709 }
1710 1710
1711 /* 1711 /*
1712 * Some devices don't advertse INTx interrupts, pre-enable a single 1712 * Some devices and/or platforms don't advertise or work with INTx
1713 * MSIX vec for setup. We'll adjust this later. 1713 * interrupts. Pre-enable a single MSIX or MSI vec for setup. We'll
1714 * adjust this later.
1714 */ 1715 */
1715 if (!pdev->irq) { 1716 if (pci_enable_msix(pdev, dev->entry, 1)) {
1716 result = pci_enable_msix(pdev, dev->entry, 1); 1717 pci_enable_msi(pdev);
1717 if (result < 0) 1718 dev->entry[0].vector = pdev->irq;
1718 goto disable; 1719 }
1720
1721 if (!dev->entry[0].vector) {
1722 result = -ENODEV;
1723 goto disable;
1719 } 1724 }
1720 1725
1721 cap = lo_hi_readq(dev->bar + NVME_REG_CAP); 1726 cap = lo_hi_readq(dev->bar + NVME_REG_CAP);