diff options
author | Christoph Hellwig <hch@lst.de> | 2016-09-14 10:18:57 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-09-15 10:42:03 -0400 |
commit | dca51e7892fa3bc545023f9f0d004a2db69eb2a1 (patch) | |
tree | 84a70f626ef572d35e5486f2db8f45101f7bcf92 | |
parent | 973c4e372c8f71a15ac39765e657ded70fc87d41 (diff) |
nvme: switch to use pci_alloc_irq_vectors
Use the new helper to automatically select the right interrupt type, as
well as to use the automatic interupt affinity assignment.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/nvme/host/pci.c | 107 |
1 files changed, 36 insertions, 71 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 086fd7e45119..47a44e92f5d3 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/bitops.h> | 16 | #include <linux/bitops.h> |
17 | #include <linux/blkdev.h> | 17 | #include <linux/blkdev.h> |
18 | #include <linux/blk-mq.h> | 18 | #include <linux/blk-mq.h> |
19 | #include <linux/blk-mq-pci.h> | ||
19 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
@@ -88,7 +89,6 @@ struct nvme_dev { | |||
88 | unsigned max_qid; | 89 | unsigned max_qid; |
89 | int q_depth; | 90 | int q_depth; |
90 | u32 db_stride; | 91 | u32 db_stride; |
91 | struct msix_entry *entry; | ||
92 | void __iomem *bar; | 92 | void __iomem *bar; |
93 | struct work_struct reset_work; | 93 | struct work_struct reset_work; |
94 | struct work_struct remove_work; | 94 | struct work_struct remove_work; |
@@ -201,6 +201,11 @@ static unsigned int nvme_cmd_size(struct nvme_dev *dev) | |||
201 | nvme_iod_alloc_size(dev, NVME_INT_BYTES(dev), NVME_INT_PAGES); | 201 | nvme_iod_alloc_size(dev, NVME_INT_BYTES(dev), NVME_INT_PAGES); |
202 | } | 202 | } |
203 | 203 | ||
204 | static int nvmeq_irq(struct nvme_queue *nvmeq) | ||
205 | { | ||
206 | return pci_irq_vector(to_pci_dev(nvmeq->dev->dev), nvmeq->cq_vector); | ||
207 | } | ||
208 | |||
204 | static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, | 209 | static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, |
205 | unsigned int hctx_idx) | 210 | unsigned int hctx_idx) |
206 | { | 211 | { |
@@ -263,6 +268,13 @@ static int nvme_init_request(void *data, struct request *req, | |||
263 | return 0; | 268 | return 0; |
264 | } | 269 | } |
265 | 270 | ||
271 | static int nvme_pci_map_queues(struct blk_mq_tag_set *set) | ||
272 | { | ||
273 | struct nvme_dev *dev = set->driver_data; | ||
274 | |||
275 | return blk_mq_pci_map_queues(set, to_pci_dev(dev->dev)); | ||
276 | } | ||
277 | |||
266 | /** | 278 | /** |
267 | * __nvme_submit_cmd() - Copy a command into a queue and ring the doorbell | 279 | * __nvme_submit_cmd() - Copy a command into a queue and ring the doorbell |
268 | * @nvmeq: The queue to use | 280 | * @nvmeq: The queue to use |
@@ -960,7 +972,7 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) | |||
960 | spin_unlock_irq(&nvmeq->q_lock); | 972 | spin_unlock_irq(&nvmeq->q_lock); |
961 | return 1; | 973 | return 1; |
962 | } | 974 | } |
963 | vector = nvmeq->dev->entry[nvmeq->cq_vector].vector; | 975 | vector = nvmeq_irq(nvmeq); |
964 | nvmeq->dev->online_queues--; | 976 | nvmeq->dev->online_queues--; |
965 | nvmeq->cq_vector = -1; | 977 | nvmeq->cq_vector = -1; |
966 | spin_unlock_irq(&nvmeq->q_lock); | 978 | spin_unlock_irq(&nvmeq->q_lock); |
@@ -968,7 +980,6 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) | |||
968 | if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q) | 980 | if (!nvmeq->qid && nvmeq->dev->ctrl.admin_q) |
969 | blk_mq_stop_hw_queues(nvmeq->dev->ctrl.admin_q); | 981 | blk_mq_stop_hw_queues(nvmeq->dev->ctrl.admin_q); |
970 | 982 | ||
971 | irq_set_affinity_hint(vector, NULL); | ||
972 | free_irq(vector, nvmeq); | 983 | free_irq(vector, nvmeq); |
973 | 984 | ||
974 | return 0; | 985 | return 0; |
@@ -1075,15 +1086,14 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, | |||
1075 | return NULL; | 1086 | return NULL; |
1076 | } | 1087 | } |
1077 | 1088 | ||
1078 | static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq, | 1089 | static int queue_request_irq(struct nvme_queue *nvmeq) |
1079 | const char *name) | ||
1080 | { | 1090 | { |
1081 | if (use_threaded_interrupts) | 1091 | if (use_threaded_interrupts) |
1082 | return request_threaded_irq(dev->entry[nvmeq->cq_vector].vector, | 1092 | return request_threaded_irq(nvmeq_irq(nvmeq), nvme_irq_check, |
1083 | nvme_irq_check, nvme_irq, IRQF_SHARED, | 1093 | nvme_irq, IRQF_SHARED, nvmeq->irqname, nvmeq); |
1084 | name, nvmeq); | 1094 | else |
1085 | return request_irq(dev->entry[nvmeq->cq_vector].vector, nvme_irq, | 1095 | return request_irq(nvmeq_irq(nvmeq), nvme_irq, IRQF_SHARED, |
1086 | IRQF_SHARED, name, nvmeq); | 1096 | nvmeq->irqname, nvmeq); |
1087 | } | 1097 | } |
1088 | 1098 | ||
1089 | static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) | 1099 | static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) |
@@ -1114,7 +1124,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) | |||
1114 | if (result < 0) | 1124 | if (result < 0) |
1115 | goto release_cq; | 1125 | goto release_cq; |
1116 | 1126 | ||
1117 | result = queue_request_irq(dev, nvmeq, nvmeq->irqname); | 1127 | result = queue_request_irq(nvmeq); |
1118 | if (result < 0) | 1128 | if (result < 0) |
1119 | goto release_sq; | 1129 | goto release_sq; |
1120 | 1130 | ||
@@ -1142,6 +1152,7 @@ static struct blk_mq_ops nvme_mq_ops = { | |||
1142 | .complete = nvme_complete_rq, | 1152 | .complete = nvme_complete_rq, |
1143 | .init_hctx = nvme_init_hctx, | 1153 | .init_hctx = nvme_init_hctx, |
1144 | .init_request = nvme_init_request, | 1154 | .init_request = nvme_init_request, |
1155 | .map_queues = nvme_pci_map_queues, | ||
1145 | .timeout = nvme_timeout, | 1156 | .timeout = nvme_timeout, |
1146 | .poll = nvme_poll, | 1157 | .poll = nvme_poll, |
1147 | }; | 1158 | }; |
@@ -1232,7 +1243,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) | |||
1232 | goto free_nvmeq; | 1243 | goto free_nvmeq; |
1233 | 1244 | ||
1234 | nvmeq->cq_vector = 0; | 1245 | nvmeq->cq_vector = 0; |
1235 | result = queue_request_irq(dev, nvmeq, nvmeq->irqname); | 1246 | result = queue_request_irq(nvmeq); |
1236 | if (result) { | 1247 | if (result) { |
1237 | nvmeq->cq_vector = -1; | 1248 | nvmeq->cq_vector = -1; |
1238 | goto free_nvmeq; | 1249 | goto free_nvmeq; |
@@ -1380,7 +1391,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) | |||
1380 | { | 1391 | { |
1381 | struct nvme_queue *adminq = dev->queues[0]; | 1392 | struct nvme_queue *adminq = dev->queues[0]; |
1382 | struct pci_dev *pdev = to_pci_dev(dev->dev); | 1393 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
1383 | int result, i, vecs, nr_io_queues, size; | 1394 | int result, nr_io_queues, size; |
1384 | 1395 | ||
1385 | nr_io_queues = num_online_cpus(); | 1396 | nr_io_queues = num_online_cpus(); |
1386 | result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues); | 1397 | result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues); |
@@ -1415,29 +1426,18 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) | |||
1415 | } | 1426 | } |
1416 | 1427 | ||
1417 | /* Deregister the admin queue's interrupt */ | 1428 | /* Deregister the admin queue's interrupt */ |
1418 | free_irq(dev->entry[0].vector, adminq); | 1429 | free_irq(pci_irq_vector(pdev, 0), adminq); |
1419 | 1430 | ||
1420 | /* | 1431 | /* |
1421 | * If we enable msix early due to not intx, disable it again before | 1432 | * If we enable msix early due to not intx, disable it again before |
1422 | * setting up the full range we need. | 1433 | * setting up the full range we need. |
1423 | */ | 1434 | */ |
1424 | if (pdev->msi_enabled) | 1435 | pci_free_irq_vectors(pdev); |
1425 | pci_disable_msi(pdev); | 1436 | nr_io_queues = pci_alloc_irq_vectors(pdev, 1, nr_io_queues, |
1426 | else if (pdev->msix_enabled) | 1437 | PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY); |
1427 | pci_disable_msix(pdev); | 1438 | if (nr_io_queues <= 0) |
1428 | 1439 | return -EIO; | |
1429 | for (i = 0; i < nr_io_queues; i++) | 1440 | dev->max_qid = nr_io_queues; |
1430 | dev->entry[i].entry = i; | ||
1431 | vecs = pci_enable_msix_range(pdev, dev->entry, 1, nr_io_queues); | ||
1432 | if (vecs < 0) { | ||
1433 | vecs = pci_enable_msi_range(pdev, 1, min(nr_io_queues, 32)); | ||
1434 | if (vecs < 0) { | ||
1435 | vecs = 1; | ||
1436 | } else { | ||
1437 | for (i = 0; i < vecs; i++) | ||
1438 | dev->entry[i].vector = i + pdev->irq; | ||
1439 | } | ||
1440 | } | ||
1441 | 1441 | ||
1442 | /* | 1442 | /* |
1443 | * Should investigate if there's a performance win from allocating | 1443 | * Should investigate if there's a performance win from allocating |
@@ -1445,10 +1445,8 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) | |||
1445 | * path to scale better, even if the receive path is limited by the | 1445 | * path to scale better, even if the receive path is limited by the |
1446 | * number of interrupts. | 1446 | * number of interrupts. |
1447 | */ | 1447 | */ |
1448 | nr_io_queues = vecs; | ||
1449 | dev->max_qid = nr_io_queues; | ||
1450 | 1448 | ||
1451 | result = queue_request_irq(dev, adminq, adminq->irqname); | 1449 | result = queue_request_irq(adminq); |
1452 | if (result) { | 1450 | if (result) { |
1453 | adminq->cq_vector = -1; | 1451 | adminq->cq_vector = -1; |
1454 | goto free_queues; | 1452 | goto free_queues; |
@@ -1460,23 +1458,6 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) | |||
1460 | return result; | 1458 | return result; |
1461 | } | 1459 | } |
1462 | 1460 | ||
1463 | static void nvme_pci_post_scan(struct nvme_ctrl *ctrl) | ||
1464 | { | ||
1465 | struct nvme_dev *dev = to_nvme_dev(ctrl); | ||
1466 | struct nvme_queue *nvmeq; | ||
1467 | int i; | ||
1468 | |||
1469 | for (i = 0; i < dev->online_queues; i++) { | ||
1470 | nvmeq = dev->queues[i]; | ||
1471 | |||
1472 | if (!nvmeq->tags || !(*nvmeq->tags)) | ||
1473 | continue; | ||
1474 | |||
1475 | irq_set_affinity_hint(dev->entry[nvmeq->cq_vector].vector, | ||
1476 | blk_mq_tags_cpumask(*nvmeq->tags)); | ||
1477 | } | ||
1478 | } | ||
1479 | |||
1480 | static void nvme_del_queue_end(struct request *req, int error) | 1461 | static void nvme_del_queue_end(struct request *req, int error) |
1481 | { | 1462 | { |
1482 | struct nvme_queue *nvmeq = req->end_io_data; | 1463 | struct nvme_queue *nvmeq = req->end_io_data; |
@@ -1613,15 +1594,9 @@ static int nvme_pci_enable(struct nvme_dev *dev) | |||
1613 | * interrupts. Pre-enable a single MSIX or MSI vec for setup. We'll | 1594 | * interrupts. Pre-enable a single MSIX or MSI vec for setup. We'll |
1614 | * adjust this later. | 1595 | * adjust this later. |
1615 | */ | 1596 | */ |
1616 | if (pci_enable_msix(pdev, dev->entry, 1)) { | 1597 | result = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
1617 | pci_enable_msi(pdev); | 1598 | if (result < 0) |
1618 | dev->entry[0].vector = pdev->irq; | 1599 | return result; |
1619 | } | ||
1620 | |||
1621 | if (!dev->entry[0].vector) { | ||
1622 | result = -ENODEV; | ||
1623 | goto disable; | ||
1624 | } | ||
1625 | 1600 | ||
1626 | cap = lo_hi_readq(dev->bar + NVME_REG_CAP); | 1601 | cap = lo_hi_readq(dev->bar + NVME_REG_CAP); |
1627 | 1602 | ||
@@ -1663,10 +1638,7 @@ static void nvme_pci_disable(struct nvme_dev *dev) | |||
1663 | { | 1638 | { |
1664 | struct pci_dev *pdev = to_pci_dev(dev->dev); | 1639 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
1665 | 1640 | ||
1666 | if (pdev->msi_enabled) | 1641 | pci_free_irq_vectors(pdev); |
1667 | pci_disable_msi(pdev); | ||
1668 | else if (pdev->msix_enabled) | ||
1669 | pci_disable_msix(pdev); | ||
1670 | 1642 | ||
1671 | if (pci_is_enabled(pdev)) { | 1643 | if (pci_is_enabled(pdev)) { |
1672 | pci_disable_pcie_error_reporting(pdev); | 1644 | pci_disable_pcie_error_reporting(pdev); |
@@ -1736,7 +1708,6 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl) | |||
1736 | if (dev->ctrl.admin_q) | 1708 | if (dev->ctrl.admin_q) |
1737 | blk_put_queue(dev->ctrl.admin_q); | 1709 | blk_put_queue(dev->ctrl.admin_q); |
1738 | kfree(dev->queues); | 1710 | kfree(dev->queues); |
1739 | kfree(dev->entry); | ||
1740 | kfree(dev); | 1711 | kfree(dev); |
1741 | } | 1712 | } |
1742 | 1713 | ||
@@ -1880,7 +1851,6 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = { | |||
1880 | .reg_read64 = nvme_pci_reg_read64, | 1851 | .reg_read64 = nvme_pci_reg_read64, |
1881 | .reset_ctrl = nvme_pci_reset_ctrl, | 1852 | .reset_ctrl = nvme_pci_reset_ctrl, |
1882 | .free_ctrl = nvme_pci_free_ctrl, | 1853 | .free_ctrl = nvme_pci_free_ctrl, |
1883 | .post_scan = nvme_pci_post_scan, | ||
1884 | .submit_async_event = nvme_pci_submit_async_event, | 1854 | .submit_async_event = nvme_pci_submit_async_event, |
1885 | }; | 1855 | }; |
1886 | 1856 | ||
@@ -1913,10 +1883,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1913 | dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node); | 1883 | dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node); |
1914 | if (!dev) | 1884 | if (!dev) |
1915 | return -ENOMEM; | 1885 | return -ENOMEM; |
1916 | dev->entry = kzalloc_node(num_possible_cpus() * sizeof(*dev->entry), | ||
1917 | GFP_KERNEL, node); | ||
1918 | if (!dev->entry) | ||
1919 | goto free; | ||
1920 | dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(void *), | 1886 | dev->queues = kzalloc_node((num_possible_cpus() + 1) * sizeof(void *), |
1921 | GFP_KERNEL, node); | 1887 | GFP_KERNEL, node); |
1922 | if (!dev->queues) | 1888 | if (!dev->queues) |
@@ -1957,7 +1923,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1957 | nvme_dev_unmap(dev); | 1923 | nvme_dev_unmap(dev); |
1958 | free: | 1924 | free: |
1959 | kfree(dev->queues); | 1925 | kfree(dev->queues); |
1960 | kfree(dev->entry); | ||
1961 | kfree(dev); | 1926 | kfree(dev); |
1962 | return result; | 1927 | return result; |
1963 | } | 1928 | } |