aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-15 15:29:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-15 15:29:46 -0400
commit68d54d3ff3e872009ff7a003d5c43816e1f7864b (patch)
tree36888a2f6bb2dd1e500ff6c559139855fd4a083d /kernel
parent9dceab89d88572eb673883e98c2b62e9b3b4537e (diff)
parentd3056812e7dfe6bf4f8ad9e397a9116dd5d32d15 (diff)
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq affinity fixes from Thomas Gleixner: - Fix error path handling in the affinity spreading code - Make affinity spreading smarter to avoid issues on systems which claim to have hotpluggable CPUs while in fact they can't hotplug anything. So instead of trying to spread the vectors (and thereby the associated device queues) to all possibe CPUs, spread them on all present CPUs first. If there are left over vectors after that first step they are spread among the possible, but not present CPUs which keeps the code backwards compatible for virtual decives and NVME which allocate a queue per possible CPU, but makes the spreading smarter for devices which have less queues than possible or present CPUs. * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: genirq/affinity: Spread irq vectors among present CPUs as far as possible genirq/affinity: Allow irq spreading from a given starting point genirq/affinity: Move actual irq vector spreading into a helper function genirq/affinity: Rename *node_to_possible_cpumask as *node_to_cpumask genirq/affinity: Don't return with empty affinity masks on error
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/affinity.c162
1 files changed, 106 insertions, 56 deletions
diff --git a/kernel/irq/affinity.c b/kernel/irq/affinity.c
index a37a3b4b6342..f4f29b9d90ee 100644
--- a/kernel/irq/affinity.c
+++ b/kernel/irq/affinity.c
@@ -39,7 +39,7 @@ static void irq_spread_init_one(struct cpumask *irqmsk, struct cpumask *nmsk,
39 } 39 }
40} 40}
41 41
42static cpumask_var_t *alloc_node_to_possible_cpumask(void) 42static cpumask_var_t *alloc_node_to_cpumask(void)
43{ 43{
44 cpumask_var_t *masks; 44 cpumask_var_t *masks;
45 int node; 45 int node;
@@ -62,7 +62,7 @@ out_unwind:
62 return NULL; 62 return NULL;
63} 63}
64 64
65static void free_node_to_possible_cpumask(cpumask_var_t *masks) 65static void free_node_to_cpumask(cpumask_var_t *masks)
66{ 66{
67 int node; 67 int node;
68 68
@@ -71,7 +71,7 @@ static void free_node_to_possible_cpumask(cpumask_var_t *masks)
71 kfree(masks); 71 kfree(masks);
72} 72}
73 73
74static void build_node_to_possible_cpumask(cpumask_var_t *masks) 74static void build_node_to_cpumask(cpumask_var_t *masks)
75{ 75{
76 int cpu; 76 int cpu;
77 77
@@ -79,14 +79,14 @@ static void build_node_to_possible_cpumask(cpumask_var_t *masks)
79 cpumask_set_cpu(cpu, masks[cpu_to_node(cpu)]); 79 cpumask_set_cpu(cpu, masks[cpu_to_node(cpu)]);
80} 80}
81 81
82static int get_nodes_in_cpumask(cpumask_var_t *node_to_possible_cpumask, 82static int get_nodes_in_cpumask(cpumask_var_t *node_to_cpumask,
83 const struct cpumask *mask, nodemask_t *nodemsk) 83 const struct cpumask *mask, nodemask_t *nodemsk)
84{ 84{
85 int n, nodes = 0; 85 int n, nodes = 0;
86 86
87 /* Calculate the number of nodes in the supplied affinity mask */ 87 /* Calculate the number of nodes in the supplied affinity mask */
88 for_each_node(n) { 88 for_each_node(n) {
89 if (cpumask_intersects(mask, node_to_possible_cpumask[n])) { 89 if (cpumask_intersects(mask, node_to_cpumask[n])) {
90 node_set(n, *nodemsk); 90 node_set(n, *nodemsk);
91 nodes++; 91 nodes++;
92 } 92 }
@@ -94,73 +94,46 @@ static int get_nodes_in_cpumask(cpumask_var_t *node_to_possible_cpumask,
94 return nodes; 94 return nodes;
95} 95}
96 96
97/** 97static int irq_build_affinity_masks(const struct irq_affinity *affd,
98 * irq_create_affinity_masks - Create affinity masks for multiqueue spreading 98 int startvec, int numvecs,
99 * @nvecs: The total number of vectors 99 cpumask_var_t *node_to_cpumask,
100 * @affd: Description of the affinity requirements 100 const struct cpumask *cpu_mask,
101 * 101 struct cpumask *nmsk,
102 * Returns the masks pointer or NULL if allocation failed. 102 struct cpumask *masks)
103 */
104struct cpumask *
105irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
106{ 103{
107 int n, nodes, cpus_per_vec, extra_vecs, curvec; 104 int n, nodes, cpus_per_vec, extra_vecs, done = 0;
108 int affv = nvecs - affd->pre_vectors - affd->post_vectors; 105 int last_affv = affd->pre_vectors + numvecs;
109 int last_affv = affv + affd->pre_vectors; 106 int curvec = startvec;
110 nodemask_t nodemsk = NODE_MASK_NONE; 107 nodemask_t nodemsk = NODE_MASK_NONE;
111 struct cpumask *masks;
112 cpumask_var_t nmsk, *node_to_possible_cpumask;
113
114 /*
115 * If there aren't any vectors left after applying the pre/post
116 * vectors don't bother with assigning affinity.
117 */
118 if (!affv)
119 return NULL;
120
121 if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
122 return NULL;
123
124 masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL);
125 if (!masks)
126 goto out;
127 108
128 node_to_possible_cpumask = alloc_node_to_possible_cpumask(); 109 if (!cpumask_weight(cpu_mask))
129 if (!node_to_possible_cpumask) 110 return 0;
130 goto out;
131 111
132 /* Fill out vectors at the beginning that don't need affinity */ 112 nodes = get_nodes_in_cpumask(node_to_cpumask, cpu_mask, &nodemsk);
133 for (curvec = 0; curvec < affd->pre_vectors; curvec++)
134 cpumask_copy(masks + curvec, irq_default_affinity);
135
136 /* Stabilize the cpumasks */
137 get_online_cpus();
138 build_node_to_possible_cpumask(node_to_possible_cpumask);
139 nodes = get_nodes_in_cpumask(node_to_possible_cpumask, cpu_possible_mask,
140 &nodemsk);
141 113
142 /* 114 /*
143 * If the number of nodes in the mask is greater than or equal the 115 * If the number of nodes in the mask is greater than or equal the
144 * number of vectors we just spread the vectors across the nodes. 116 * number of vectors we just spread the vectors across the nodes.
145 */ 117 */
146 if (affv <= nodes) { 118 if (numvecs <= nodes) {
147 for_each_node_mask(n, nodemsk) { 119 for_each_node_mask(n, nodemsk) {
148 cpumask_copy(masks + curvec, 120 cpumask_copy(masks + curvec, node_to_cpumask[n]);
149 node_to_possible_cpumask[n]); 121 if (++done == numvecs)
150 if (++curvec == last_affv)
151 break; 122 break;
123 if (++curvec == last_affv)
124 curvec = affd->pre_vectors;
152 } 125 }
153 goto done; 126 goto out;
154 } 127 }
155 128
156 for_each_node_mask(n, nodemsk) { 129 for_each_node_mask(n, nodemsk) {
157 int ncpus, v, vecs_to_assign, vecs_per_node; 130 int ncpus, v, vecs_to_assign, vecs_per_node;
158 131
159 /* Spread the vectors per node */ 132 /* Spread the vectors per node */
160 vecs_per_node = (affv - (curvec - affd->pre_vectors)) / nodes; 133 vecs_per_node = (numvecs - (curvec - affd->pre_vectors)) / nodes;
161 134
162 /* Get the cpus on this node which are in the mask */ 135 /* Get the cpus on this node which are in the mask */
163 cpumask_and(nmsk, cpu_possible_mask, node_to_possible_cpumask[n]); 136 cpumask_and(nmsk, cpu_mask, node_to_cpumask[n]);
164 137
165 /* Calculate the number of cpus per vector */ 138 /* Calculate the number of cpus per vector */
166 ncpus = cpumask_weight(nmsk); 139 ncpus = cpumask_weight(nmsk);
@@ -181,19 +154,96 @@ irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
181 irq_spread_init_one(masks + curvec, nmsk, cpus_per_vec); 154 irq_spread_init_one(masks + curvec, nmsk, cpus_per_vec);
182 } 155 }
183 156
184 if (curvec >= last_affv) 157 done += v;
158 if (done >= numvecs)
185 break; 159 break;
160 if (curvec >= last_affv)
161 curvec = affd->pre_vectors;
186 --nodes; 162 --nodes;
187 } 163 }
188 164
189done: 165out:
166 return done;
167}
168
169/**
170 * irq_create_affinity_masks - Create affinity masks for multiqueue spreading
171 * @nvecs: The total number of vectors
172 * @affd: Description of the affinity requirements
173 *
174 * Returns the masks pointer or NULL if allocation failed.
175 */
176struct cpumask *
177irq_create_affinity_masks(int nvecs, const struct irq_affinity *affd)
178{
179 int affvecs = nvecs - affd->pre_vectors - affd->post_vectors;
180 int curvec, usedvecs;
181 cpumask_var_t nmsk, npresmsk, *node_to_cpumask;
182 struct cpumask *masks = NULL;
183
184 /*
185 * If there aren't any vectors left after applying the pre/post
186 * vectors don't bother with assigning affinity.
187 */
188 if (nvecs == affd->pre_vectors + affd->post_vectors)
189 return NULL;
190
191 if (!zalloc_cpumask_var(&nmsk, GFP_KERNEL))
192 return NULL;
193
194 if (!zalloc_cpumask_var(&npresmsk, GFP_KERNEL))
195 goto outcpumsk;
196
197 node_to_cpumask = alloc_node_to_cpumask();
198 if (!node_to_cpumask)
199 goto outnpresmsk;
200
201 masks = kcalloc(nvecs, sizeof(*masks), GFP_KERNEL);
202 if (!masks)
203 goto outnodemsk;
204
205 /* Fill out vectors at the beginning that don't need affinity */
206 for (curvec = 0; curvec < affd->pre_vectors; curvec++)
207 cpumask_copy(masks + curvec, irq_default_affinity);
208
209 /* Stabilize the cpumasks */
210 get_online_cpus();
211 build_node_to_cpumask(node_to_cpumask);
212
213 /* Spread on present CPUs starting from affd->pre_vectors */
214 usedvecs = irq_build_affinity_masks(affd, curvec, affvecs,
215 node_to_cpumask, cpu_present_mask,
216 nmsk, masks);
217
218 /*
219 * Spread on non present CPUs starting from the next vector to be
220 * handled. If the spreading of present CPUs already exhausted the
221 * vector space, assign the non present CPUs to the already spread
222 * out vectors.
223 */
224 if (usedvecs >= affvecs)
225 curvec = affd->pre_vectors;
226 else
227 curvec = affd->pre_vectors + usedvecs;
228 cpumask_andnot(npresmsk, cpu_possible_mask, cpu_present_mask);
229 usedvecs += irq_build_affinity_masks(affd, curvec, affvecs,
230 node_to_cpumask, npresmsk,
231 nmsk, masks);
190 put_online_cpus(); 232 put_online_cpus();
191 233
192 /* Fill out vectors at the end that don't need affinity */ 234 /* Fill out vectors at the end that don't need affinity */
235 if (usedvecs >= affvecs)
236 curvec = affd->pre_vectors + affvecs;
237 else
238 curvec = affd->pre_vectors + usedvecs;
193 for (; curvec < nvecs; curvec++) 239 for (; curvec < nvecs; curvec++)
194 cpumask_copy(masks + curvec, irq_default_affinity); 240 cpumask_copy(masks + curvec, irq_default_affinity);
195 free_node_to_possible_cpumask(node_to_possible_cpumask); 241
196out: 242outnodemsk:
243 free_node_to_cpumask(node_to_cpumask);
244outnpresmsk:
245 free_cpumask_var(npresmsk);
246outcpumsk:
197 free_cpumask_var(nmsk); 247 free_cpumask_var(nmsk);
198 return masks; 248 return masks;
199} 249}