aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-07-04 04:39:27 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-07-04 06:25:14 -0400
commit5e385a6ef31fbbf2acbda770aecc2bc2ff933d17 (patch)
tree2845d6e1d4633d50683a07d0c2bebafc990c7b2a /kernel
parent0972fa57f53525ffa6ced12d703750fc2791e3ce (diff)
genirq: Add a helper to spread an affinity mask for MSI/MSI-X vectors
This is lifted from the blk-mq code and adopted to use the affinity mask concept just introduced in the irq handling code. It tries to keep the algorithm the same as the one current used by blk-mq, but improvements like assining vectors on a per-node basis instead of just per sibling are possible with this simple move and refactoring. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: linux-block@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: linux-nvme@lists.infradead.org Cc: axboe@fb.com Cc: agordeev@redhat.com Link: http://lkml.kernel.org/r/1467621574-8277-7-git-send-email-hch@lst.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/Makefile1
-rw-r--r--kernel/irq/affinity.c61
2 files changed, 62 insertions, 0 deletions
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index 2ee42e95a3ce..1d3ee3169202 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o
9obj-$(CONFIG_PM_SLEEP) += pm.o 9obj-$(CONFIG_PM_SLEEP) += pm.o
10obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o 10obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
11obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o 11obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o
12obj-$(CONFIG_SMP) += affinity.o
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
new file mode 100644
index 000000000000..f68959341c0f
--- /dev/null
+++ b/kernel/irq/affinity.c
@@ -0,0 +1,61 @@
1
2#include <linux/interrupt.h>
3#include <linux/kernel.h>
4#include <linux/slab.h>
5#include <linux/cpu.h>
6
7static int get_first_sibling(unsigned int cpu)
8{
9 unsigned int ret;
10
11 ret = cpumask_first(topology_sibling_cpumask(cpu));
12 if (ret < nr_cpu_ids)
13 return ret;
14 return cpu;
15}
16
17/*
18 * Take a map of online CPUs and the number of available interrupt vectors
19 * and generate an output cpumask suitable for spreading MSI/MSI-X vectors
20 * so that they are distributed as good as possible around the CPUs. If
21 * more vectors than CPUs are available we'll map one to each CPU,
22 * otherwise we map one to the first sibling of each socket.
23 *
24 * If there are more vectors than CPUs we will still only have one bit
25 * set per CPU, but interrupt code will keep on assigning the vectors from
26 * the start of the bitmap until we run out of vectors.
27 */
28struct cpumask *irq_create_affinity_mask(unsigned int *nr_vecs)
29{
30 struct cpumask *affinity_mask;
31 unsigned int max_vecs = *nr_vecs;
32
33 if (max_vecs == 1)
34 return NULL;
35
36 affinity_mask = kzalloc(cpumask_size(), GFP_KERNEL);
37 if (!affinity_mask) {
38 *nr_vecs = 1;
39 return NULL;
40 }
41
42 if (max_vecs >= num_online_cpus()) {
43 cpumask_copy(affinity_mask, cpu_online_mask);
44 *nr_vecs = num_online_cpus();
45 } else {
46 unsigned int vecs = 0, cpu;
47
48 for_each_online_cpu(cpu) {
49 if (cpu == get_first_sibling(cpu)) {
50 cpumask_set_cpu(cpu, affinity_mask);
51 vecs++;
52 }
53
54 if (--max_vecs == 0)
55 break;
56 }
57 *nr_vecs = vecs;
58 }
59
60 return affinity_mask;
61}