aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}