aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/nvme.c
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew.r.wilcox@intel.com>2011-01-20 13:01:49 -0500
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2011-11-04 15:52:51 -0400
commit1b23484bd012c078de2ea939249e2fb2e85a0a6e (patch)
tree8147999ed348b47b2e400e9ed958d9db207bba23 /drivers/block/nvme.c
parentb3b06812e199f248561ce7824a4a8a9cd573c05a (diff)
NVMe: Implement per-CPU queues
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme.c')
-rw-r--r--drivers/block/nvme.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index 7efd7e92b637..b6a213c98584 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -172,11 +172,17 @@ static unsigned long free_cmdid(struct nvme_queue *nvmeq, int cmdid)
172 172
173static struct nvme_queue *get_nvmeq(struct nvme_ns *ns) 173static struct nvme_queue *get_nvmeq(struct nvme_ns *ns)
174{ 174{
175 return ns->dev->queues[1]; 175 int qid, cpu = get_cpu();
176 if (cpu < ns->dev->queue_count)
177 qid = cpu + 1;
178 else
179 qid = (cpu % rounddown_pow_of_two(ns->dev->queue_count)) + 1;
180 return ns->dev->queues[qid];
176} 181}
177 182
178static void put_nvmeq(struct nvme_queue *nvmeq) 183static void put_nvmeq(struct nvme_queue *nvmeq)
179{ 184{
185 put_cpu();
180} 186}
181 187
182/** 188/**
@@ -795,19 +801,51 @@ static int set_queue_count(struct nvme_dev *dev, int count)
795 return min(result & 0xffff, result >> 16) + 1; 801 return min(result & 0xffff, result >> 16) + 1;
796} 802}
797 803
798/* XXX: Create per-CPU queues */
799static int __devinit nvme_setup_io_queues(struct nvme_dev *dev) 804static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
800{ 805{
801 int this_cpu; 806 int result, cpu, i, nr_queues;
802 807
803 set_queue_count(dev, 1); 808 nr_queues = num_online_cpus();
809 result = set_queue_count(dev, nr_queues);
810 if (result < 0)
811 return result;
812 if (result < nr_queues)
813 nr_queues = result;
804 814
805 this_cpu = get_cpu(); 815 /* Deregister the admin queue's interrupt */
806 dev->queues[1] = nvme_create_queue(dev, 1, NVME_Q_DEPTH, this_cpu); 816 free_irq(dev->entry[0].vector, dev->queues[0]);
807 put_cpu(); 817
808 if (!dev->queues[1]) 818 for (i = 0; i < nr_queues; i++)
809 return -ENOMEM; 819 dev->entry[i].entry = i;
810 dev->queue_count++; 820 for (;;) {
821 result = pci_enable_msix(dev->pci_dev, dev->entry, nr_queues);
822 if (result == 0) {
823 break;
824 } else if (result > 0) {
825 nr_queues = result;
826 continue;
827 } else {
828 nr_queues = 1;
829 break;
830 }
831 }
832
833 result = queue_request_irq(dev, dev->queues[0], "nvme admin");
834 /* XXX: handle failure here */
835
836 cpu = cpumask_first(cpu_online_mask);
837 for (i = 0; i < nr_queues; i++) {
838 irq_set_affinity_hint(dev->entry[i].vector, get_cpu_mask(cpu));
839 cpu = cpumask_next(cpu, cpu_online_mask);
840 }
841
842 for (i = 0; i < nr_queues; i++) {
843 dev->queues[i + 1] = nvme_create_queue(dev, i + 1,
844 NVME_Q_DEPTH, i);
845 if (!dev->queues[i + 1])
846 return -ENOMEM;
847 dev->queue_count++;
848 }
811 849
812 return 0; 850 return 0;
813} 851}
@@ -931,7 +969,8 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
931 GFP_KERNEL); 969 GFP_KERNEL);
932 if (!dev->entry) 970 if (!dev->entry)
933 goto free; 971 goto free;
934 dev->queues = kcalloc(2, sizeof(void *), GFP_KERNEL); 972 dev->queues = kcalloc(num_possible_cpus() + 1, sizeof(void *),
973 GFP_KERNEL);
935 if (!dev->queues) 974 if (!dev->queues)
936 goto free; 975 goto free;
937 976