diff options
Diffstat (limited to 'drivers/nvme/host/pci.c')
| -rw-r--r-- | drivers/nvme/host/pci.c | 117 |
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 | /* |
| 2045 | static 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 | */ | ||
| 2048 | static 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 | ||
| 2081 | static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) | 2082 | static 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 | ||
| 2153 | static void nvme_disable_io_queues(struct nvme_dev *dev) | 2113 | static void nvme_disable_io_queues(struct nvme_dev *dev) |
| @@ -3024,6 +2984,7 @@ static struct pci_driver nvme_driver = { | |||
| 3024 | 2984 | ||
| 3025 | static int __init nvme_init(void) | 2985 | static 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 | ||
