aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nvme/host/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nvme/host/pci.c')
-rw-r--r--drivers/nvme/host/pci.c117
1 files changed, 39 insertions, 78 deletions
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 7fee665ec45e..e905861186e3 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2041,53 +2041,52 @@ static int nvme_setup_host_mem(struct nvme_dev *dev)
2041 return ret; 2041 return ret;
2042} 2042}
2043 2043
2044/* irq_queues covers admin queue */ 2044/*
2045static void nvme_calc_io_queues(struct nvme_dev *dev, unsigned int irq_queues) 2045 * nirqs is the number of interrupts available for write and read
2046 * queues. The core already reserved an interrupt for the admin queue.
2047 */
2048static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs)
2046{ 2049{
2047 unsigned int this_w_queues = write_queues; 2050 struct nvme_dev *dev = affd->priv;
2048 2051 unsigned int nr_read_queues;
2049 WARN_ON(!irq_queues);
2050
2051 /*
2052 * Setup read/write queue split, assign admin queue one independent
2053 * irq vector if irq_queues is > 1.
2054 */
2055 if (irq_queues <= 2) {
2056 dev->io_queues[HCTX_TYPE_DEFAULT] = 1;
2057 dev->io_queues[HCTX_TYPE_READ] = 0;
2058 return;
2059 }
2060
2061 /*
2062 * If 'write_queues' is set, ensure it leaves room for at least
2063 * one read queue and one admin queue
2064 */
2065 if (this_w_queues >= irq_queues)
2066 this_w_queues = irq_queues - 2;
2067 2052
2068 /* 2053 /*
2069 * If 'write_queues' is set to zero, reads and writes will share 2054 * If there is no interupt available for queues, ensure that
2070 * a queue set. 2055 * the default queue is set to 1. The affinity set size is
2056 * also set to one, but the irq core ignores it for this case.
2057 *
2058 * If only one interrupt is available or 'write_queue' == 0, combine
2059 * write and read queues.
2060 *
2061 * If 'write_queues' > 0, ensure it leaves room for at least one read
2062 * queue.
2071 */ 2063 */
2072 if (!this_w_queues) { 2064 if (!nrirqs) {
2073 dev->io_queues[HCTX_TYPE_DEFAULT] = irq_queues - 1; 2065 nrirqs = 1;
2074 dev->io_queues[HCTX_TYPE_READ] = 0; 2066 nr_read_queues = 0;
2067 } else if (nrirqs == 1 || !write_queues) {
2068 nr_read_queues = 0;
2069 } else if (write_queues >= nrirqs) {
2070 nr_read_queues = 1;
2075 } else { 2071 } else {
2076 dev->io_queues[HCTX_TYPE_DEFAULT] = this_w_queues; 2072 nr_read_queues = nrirqs - write_queues;
2077 dev->io_queues[HCTX_TYPE_READ] = irq_queues - this_w_queues - 1;
2078 } 2073 }
2074
2075 dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues;
2076 affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues;
2077 dev->io_queues[HCTX_TYPE_READ] = nr_read_queues;
2078 affd->set_size[HCTX_TYPE_READ] = nr_read_queues;
2079 affd->nr_sets = nr_read_queues ? 2 : 1;
2079} 2080}
2080 2081
2081static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) 2082static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
2082{ 2083{
2083 struct pci_dev *pdev = to_pci_dev(dev->dev); 2084 struct pci_dev *pdev = to_pci_dev(dev->dev);
2084 int irq_sets[2];
2085 struct irq_affinity affd = { 2085 struct irq_affinity affd = {
2086 .pre_vectors = 1, 2086 .pre_vectors = 1,
2087 .nr_sets = ARRAY_SIZE(irq_sets), 2087 .calc_sets = nvme_calc_irq_sets,
2088 .sets = irq_sets, 2088 .priv = dev,
2089 }; 2089 };
2090 int result = 0;
2091 unsigned int irq_queues, this_p_queues; 2090 unsigned int irq_queues, this_p_queues;
2092 2091
2093 /* 2092 /*
@@ -2103,51 +2102,12 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)
2103 } 2102 }
2104 dev->io_queues[HCTX_TYPE_POLL] = this_p_queues; 2103 dev->io_queues[HCTX_TYPE_POLL] = this_p_queues;
2105 2104
2106 /* 2105 /* Initialize for the single interrupt case */
2107 * For irq sets, we have to ask for minvec == maxvec. This passes 2106 dev->io_queues[HCTX_TYPE_DEFAULT] = 1;
2108 * any reduction back to us, so we can adjust our queue counts and 2107 dev->io_queues[HCTX_TYPE_READ] = 0;
2109 * IRQ vector needs.
2110 */
2111 do {
2112 nvme_calc_io_queues(dev, irq_queues);
2113 irq_sets[0] = dev->io_queues[HCTX_TYPE_DEFAULT];
2114 irq_sets[1] = dev->io_queues[HCTX_TYPE_READ];
2115 if (!irq_sets[1])
2116 affd.nr_sets = 1;
2117
2118 /*
2119 * If we got a failure and we're down to asking for just
2120 * 1 + 1 queues, just ask for a single vector. We'll share
2121 * that between the single IO queue and the admin queue.
2122 * Otherwise, we assign one independent vector to admin queue.
2123 */
2124 if (irq_queues > 1)
2125 irq_queues = irq_sets[0] + irq_sets[1] + 1;
2126 2108
2127 result = pci_alloc_irq_vectors_affinity(pdev, irq_queues, 2109 return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues,
2128 irq_queues, 2110 PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd);
2129 PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd);
2130
2131 /*
2132 * Need to reduce our vec counts. If we get ENOSPC, the
2133 * platform should support mulitple vecs, we just need
2134 * to decrease our ask. If we get EINVAL, the platform
2135 * likely does not. Back down to ask for just one vector.
2136 */
2137 if (result == -ENOSPC) {
2138 irq_queues--;
2139 if (!irq_queues)
2140 return result;
2141 continue;
2142 } else if (result == -EINVAL) {
2143 irq_queues = 1;
2144 continue;
2145 } else if (result <= 0)
2146 return -EIO;
2147 break;
2148 } while (1);
2149
2150 return result;
2151} 2111}
2152 2112
2153static void nvme_disable_io_queues(struct nvme_dev *dev) 2113static void nvme_disable_io_queues(struct nvme_dev *dev)
@@ -3024,6 +2984,7 @@ static struct pci_driver nvme_driver = {
3024 2984
3025static int __init nvme_init(void) 2985static int __init nvme_init(void)
3026{ 2986{
2987 BUILD_BUG_ON(IRQ_AFFINITY_MAX_SETS < 2);
3027 return pci_register_driver(&nvme_driver); 2988 return pci_register_driver(&nvme_driver);
3028} 2989}
3029 2990