diff options
Diffstat (limited to 'kernel/smp.c')
-rw-r--r-- | kernel/smp.c | 100 |
1 files changed, 70 insertions, 30 deletions
diff --git a/kernel/smp.c b/kernel/smp.c index c9d1c7835c2f..3fc697336183 100644 --- a/kernel/smp.c +++ b/kernel/smp.c | |||
@@ -9,18 +9,17 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/percpu.h> | 10 | #include <linux/percpu.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/gfp.h> | ||
12 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
13 | #include <linux/cpu.h> | 14 | #include <linux/cpu.h> |
14 | 15 | ||
15 | static DEFINE_PER_CPU(struct call_single_queue, call_single_queue); | ||
16 | |||
17 | static struct { | 16 | static struct { |
18 | struct list_head queue; | 17 | struct list_head queue; |
19 | spinlock_t lock; | 18 | raw_spinlock_t lock; |
20 | } call_function __cacheline_aligned_in_smp = | 19 | } call_function __cacheline_aligned_in_smp = |
21 | { | 20 | { |
22 | .queue = LIST_HEAD_INIT(call_function.queue), | 21 | .queue = LIST_HEAD_INIT(call_function.queue), |
23 | .lock = __SPIN_LOCK_UNLOCKED(call_function.lock), | 22 | .lock = __RAW_SPIN_LOCK_UNLOCKED(call_function.lock), |
24 | }; | 23 | }; |
25 | 24 | ||
26 | enum { | 25 | enum { |
@@ -33,12 +32,14 @@ struct call_function_data { | |||
33 | cpumask_var_t cpumask; | 32 | cpumask_var_t cpumask; |
34 | }; | 33 | }; |
35 | 34 | ||
35 | static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_function_data, cfd_data); | ||
36 | |||
36 | struct call_single_queue { | 37 | struct call_single_queue { |
37 | struct list_head list; | 38 | struct list_head list; |
38 | spinlock_t lock; | 39 | raw_spinlock_t lock; |
39 | }; | 40 | }; |
40 | 41 | ||
41 | static DEFINE_PER_CPU(struct call_function_data, cfd_data); | 42 | static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_queue, call_single_queue); |
42 | 43 | ||
43 | static int | 44 | static int |
44 | hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) | 45 | hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) |
@@ -80,7 +81,7 @@ static int __cpuinit init_call_single_data(void) | |||
80 | for_each_possible_cpu(i) { | 81 | for_each_possible_cpu(i) { |
81 | struct call_single_queue *q = &per_cpu(call_single_queue, i); | 82 | struct call_single_queue *q = &per_cpu(call_single_queue, i); |
82 | 83 | ||
83 | spin_lock_init(&q->lock); | 84 | raw_spin_lock_init(&q->lock); |
84 | INIT_LIST_HEAD(&q->list); | 85 | INIT_LIST_HEAD(&q->list); |
85 | } | 86 | } |
86 | 87 | ||
@@ -141,10 +142,10 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait) | |||
141 | unsigned long flags; | 142 | unsigned long flags; |
142 | int ipi; | 143 | int ipi; |
143 | 144 | ||
144 | spin_lock_irqsave(&dst->lock, flags); | 145 | raw_spin_lock_irqsave(&dst->lock, flags); |
145 | ipi = list_empty(&dst->list); | 146 | ipi = list_empty(&dst->list); |
146 | list_add_tail(&data->list, &dst->list); | 147 | list_add_tail(&data->list, &dst->list); |
147 | spin_unlock_irqrestore(&dst->lock, flags); | 148 | raw_spin_unlock_irqrestore(&dst->lock, flags); |
148 | 149 | ||
149 | /* | 150 | /* |
150 | * The list addition should be visible before sending the IPI | 151 | * The list addition should be visible before sending the IPI |
@@ -171,7 +172,7 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait) | |||
171 | void generic_smp_call_function_interrupt(void) | 172 | void generic_smp_call_function_interrupt(void) |
172 | { | 173 | { |
173 | struct call_function_data *data; | 174 | struct call_function_data *data; |
174 | int cpu = get_cpu(); | 175 | int cpu = smp_processor_id(); |
175 | 176 | ||
176 | /* | 177 | /* |
177 | * Shouldn't receive this interrupt on a cpu that is not yet online. | 178 | * Shouldn't receive this interrupt on a cpu that is not yet online. |
@@ -201,9 +202,9 @@ void generic_smp_call_function_interrupt(void) | |||
201 | refs = atomic_dec_return(&data->refs); | 202 | refs = atomic_dec_return(&data->refs); |
202 | WARN_ON(refs < 0); | 203 | WARN_ON(refs < 0); |
203 | if (!refs) { | 204 | if (!refs) { |
204 | spin_lock(&call_function.lock); | 205 | raw_spin_lock(&call_function.lock); |
205 | list_del_rcu(&data->csd.list); | 206 | list_del_rcu(&data->csd.list); |
206 | spin_unlock(&call_function.lock); | 207 | raw_spin_unlock(&call_function.lock); |
207 | } | 208 | } |
208 | 209 | ||
209 | if (refs) | 210 | if (refs) |
@@ -212,7 +213,6 @@ void generic_smp_call_function_interrupt(void) | |||
212 | csd_unlock(&data->csd); | 213 | csd_unlock(&data->csd); |
213 | } | 214 | } |
214 | 215 | ||
215 | put_cpu(); | ||
216 | } | 216 | } |
217 | 217 | ||
218 | /* | 218 | /* |
@@ -230,9 +230,9 @@ void generic_smp_call_function_single_interrupt(void) | |||
230 | */ | 230 | */ |
231 | WARN_ON_ONCE(!cpu_online(smp_processor_id())); | 231 | WARN_ON_ONCE(!cpu_online(smp_processor_id())); |
232 | 232 | ||
233 | spin_lock(&q->lock); | 233 | raw_spin_lock(&q->lock); |
234 | list_replace_init(&q->list, &list); | 234 | list_replace_init(&q->list, &list); |
235 | spin_unlock(&q->lock); | 235 | raw_spin_unlock(&q->lock); |
236 | 236 | ||
237 | while (!list_empty(&list)) { | 237 | while (!list_empty(&list)) { |
238 | struct call_single_data *data; | 238 | struct call_single_data *data; |
@@ -257,7 +257,7 @@ void generic_smp_call_function_single_interrupt(void) | |||
257 | } | 257 | } |
258 | } | 258 | } |
259 | 259 | ||
260 | static DEFINE_PER_CPU(struct call_single_data, csd_data); | 260 | static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_data, csd_data); |
261 | 261 | ||
262 | /* | 262 | /* |
263 | * smp_call_function_single - Run a function on a specific CPU | 263 | * smp_call_function_single - Run a function on a specific CPU |
@@ -265,9 +265,7 @@ static DEFINE_PER_CPU(struct call_single_data, csd_data); | |||
265 | * @info: An arbitrary pointer to pass to the function. | 265 | * @info: An arbitrary pointer to pass to the function. |
266 | * @wait: If true, wait until function has completed on other CPUs. | 266 | * @wait: If true, wait until function has completed on other CPUs. |
267 | * | 267 | * |
268 | * Returns 0 on success, else a negative status code. Note that @wait | 268 | * Returns 0 on success, else a negative status code. |
269 | * will be implicitly turned on in case of allocation failures, since | ||
270 | * we fall back to on-stack allocation. | ||
271 | */ | 269 | */ |
272 | int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | 270 | int smp_call_function_single(int cpu, void (*func) (void *info), void *info, |
273 | int wait) | 271 | int wait) |
@@ -321,6 +319,51 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | |||
321 | } | 319 | } |
322 | EXPORT_SYMBOL(smp_call_function_single); | 320 | EXPORT_SYMBOL(smp_call_function_single); |
323 | 321 | ||
322 | /* | ||
323 | * smp_call_function_any - Run a function on any of the given cpus | ||
324 | * @mask: The mask of cpus it can run on. | ||
325 | * @func: The function to run. This must be fast and non-blocking. | ||
326 | * @info: An arbitrary pointer to pass to the function. | ||
327 | * @wait: If true, wait until function has completed. | ||
328 | * | ||
329 | * Returns 0 on success, else a negative status code (if no cpus were online). | ||
330 | * Note that @wait will be implicitly turned on in case of allocation failures, | ||
331 | * since we fall back to on-stack allocation. | ||
332 | * | ||
333 | * Selection preference: | ||
334 | * 1) current cpu if in @mask | ||
335 | * 2) any cpu of current node if in @mask | ||
336 | * 3) any other online cpu in @mask | ||
337 | */ | ||
338 | int smp_call_function_any(const struct cpumask *mask, | ||
339 | void (*func)(void *info), void *info, int wait) | ||
340 | { | ||
341 | unsigned int cpu; | ||
342 | const struct cpumask *nodemask; | ||
343 | int ret; | ||
344 | |||
345 | /* Try for same CPU (cheapest) */ | ||
346 | cpu = get_cpu(); | ||
347 | if (cpumask_test_cpu(cpu, mask)) | ||
348 | goto call; | ||
349 | |||
350 | /* Try for same node. */ | ||
351 | nodemask = cpumask_of_node(cpu_to_node(cpu)); | ||
352 | for (cpu = cpumask_first_and(nodemask, mask); cpu < nr_cpu_ids; | ||
353 | cpu = cpumask_next_and(cpu, nodemask, mask)) { | ||
354 | if (cpu_online(cpu)) | ||
355 | goto call; | ||
356 | } | ||
357 | |||
358 | /* Any online will do: smp_call_function_single handles nr_cpu_ids. */ | ||
359 | cpu = cpumask_any_and(mask, cpu_online_mask); | ||
360 | call: | ||
361 | ret = smp_call_function_single(cpu, func, info, wait); | ||
362 | put_cpu(); | ||
363 | return ret; | ||
364 | } | ||
365 | EXPORT_SYMBOL_GPL(smp_call_function_any); | ||
366 | |||
324 | /** | 367 | /** |
325 | * __smp_call_function_single(): Run a function on another CPU | 368 | * __smp_call_function_single(): Run a function on another CPU |
326 | * @cpu: The CPU to run on. | 369 | * @cpu: The CPU to run on. |
@@ -355,9 +398,7 @@ void __smp_call_function_single(int cpu, struct call_single_data *data, | |||
355 | * @wait: If true, wait (atomically) until function has completed | 398 | * @wait: If true, wait (atomically) until function has completed |
356 | * on other CPUs. | 399 | * on other CPUs. |
357 | * | 400 | * |
358 | * If @wait is true, then returns once @func has returned. Note that @wait | 401 | * If @wait is true, then returns once @func has returned. |
359 | * will be implicitly turned on in case of allocation failures, since | ||
360 | * we fall back to on-stack allocation. | ||
361 | * | 402 | * |
362 | * You must not call this function with disabled interrupts or from a | 403 | * You must not call this function with disabled interrupts or from a |
363 | * hardware interrupt handler or from a bottom half handler. Preemption | 404 | * hardware interrupt handler or from a bottom half handler. Preemption |
@@ -408,14 +449,14 @@ void smp_call_function_many(const struct cpumask *mask, | |||
408 | cpumask_clear_cpu(this_cpu, data->cpumask); | 449 | cpumask_clear_cpu(this_cpu, data->cpumask); |
409 | atomic_set(&data->refs, cpumask_weight(data->cpumask)); | 450 | atomic_set(&data->refs, cpumask_weight(data->cpumask)); |
410 | 451 | ||
411 | spin_lock_irqsave(&call_function.lock, flags); | 452 | raw_spin_lock_irqsave(&call_function.lock, flags); |
412 | /* | 453 | /* |
413 | * Place entry at the _HEAD_ of the list, so that any cpu still | 454 | * Place entry at the _HEAD_ of the list, so that any cpu still |
414 | * observing the entry in generic_smp_call_function_interrupt() | 455 | * observing the entry in generic_smp_call_function_interrupt() |
415 | * will not miss any other list entries: | 456 | * will not miss any other list entries: |
416 | */ | 457 | */ |
417 | list_add_rcu(&data->csd.list, &call_function.queue); | 458 | list_add_rcu(&data->csd.list, &call_function.queue); |
418 | spin_unlock_irqrestore(&call_function.lock, flags); | 459 | raw_spin_unlock_irqrestore(&call_function.lock, flags); |
419 | 460 | ||
420 | /* | 461 | /* |
421 | * Make the list addition visible before sending the ipi. | 462 | * Make the list addition visible before sending the ipi. |
@@ -443,8 +484,7 @@ EXPORT_SYMBOL(smp_call_function_many); | |||
443 | * Returns 0. | 484 | * Returns 0. |
444 | * | 485 | * |
445 | * If @wait is true, then returns once @func has returned; otherwise | 486 | * If @wait is true, then returns once @func has returned; otherwise |
446 | * it returns just before the target cpu calls @func. In case of allocation | 487 | * it returns just before the target cpu calls @func. |
447 | * failure, @wait will be implicitly turned on. | ||
448 | * | 488 | * |
449 | * You must not call this function with disabled interrupts or from a | 489 | * You must not call this function with disabled interrupts or from a |
450 | * hardware interrupt handler or from a bottom half handler. | 490 | * hardware interrupt handler or from a bottom half handler. |
@@ -461,20 +501,20 @@ EXPORT_SYMBOL(smp_call_function); | |||
461 | 501 | ||
462 | void ipi_call_lock(void) | 502 | void ipi_call_lock(void) |
463 | { | 503 | { |
464 | spin_lock(&call_function.lock); | 504 | raw_spin_lock(&call_function.lock); |
465 | } | 505 | } |
466 | 506 | ||
467 | void ipi_call_unlock(void) | 507 | void ipi_call_unlock(void) |
468 | { | 508 | { |
469 | spin_unlock(&call_function.lock); | 509 | raw_spin_unlock(&call_function.lock); |
470 | } | 510 | } |
471 | 511 | ||
472 | void ipi_call_lock_irq(void) | 512 | void ipi_call_lock_irq(void) |
473 | { | 513 | { |
474 | spin_lock_irq(&call_function.lock); | 514 | raw_spin_lock_irq(&call_function.lock); |
475 | } | 515 | } |
476 | 516 | ||
477 | void ipi_call_unlock_irq(void) | 517 | void ipi_call_unlock_irq(void) |
478 | { | 518 | { |
479 | spin_unlock_irq(&call_function.lock); | 519 | raw_spin_unlock_irq(&call_function.lock); |
480 | } | 520 | } |