aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cpu.c')
-rw-r--r--kernel/cpu.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 1972b161c61e..94bbe4695232 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -20,6 +20,7 @@
20#include <linux/gfp.h> 20#include <linux/gfp.h>
21#include <linux/suspend.h> 21#include <linux/suspend.h>
22#include <linux/lockdep.h> 22#include <linux/lockdep.h>
23#include <linux/tick.h>
23#include <trace/events/power.h> 24#include <trace/events/power.h>
24 25
25#include "smpboot.h" 26#include "smpboot.h"
@@ -338,6 +339,8 @@ static int __ref take_cpu_down(void *_param)
338 return err; 339 return err;
339 340
340 cpu_notify(CPU_DYING | param->mod, param->hcpu); 341 cpu_notify(CPU_DYING | param->mod, param->hcpu);
342 /* Give up timekeeping duties */
343 tick_handover_do_timer();
341 /* Park the stopper thread */ 344 /* Park the stopper thread */
342 kthread_park(current); 345 kthread_park(current);
343 return 0; 346 return 0;
@@ -408,13 +411,17 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
408 * 411 *
409 * Wait for the stop thread to go away. 412 * Wait for the stop thread to go away.
410 */ 413 */
411 while (!idle_cpu(cpu)) 414 while (!per_cpu(cpu_dead_idle, cpu))
412 cpu_relax(); 415 cpu_relax();
416 smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */
417 per_cpu(cpu_dead_idle, cpu) = false;
413 418
419 hotplug_cpu__broadcast_tick_pull(cpu);
414 /* This actually kills the CPU. */ 420 /* This actually kills the CPU. */
415 __cpu_die(cpu); 421 __cpu_die(cpu);
416 422
417 /* CPU is completely dead: tell everyone. Too late to complain. */ 423 /* CPU is completely dead: tell everyone. Too late to complain. */
424 tick_cleanup_dead_cpu(cpu);
418 cpu_notify_nofail(CPU_DEAD | mod, hcpu); 425 cpu_notify_nofail(CPU_DEAD | mod, hcpu);
419 426
420 check_for_tasks(cpu); 427 check_for_tasks(cpu);
@@ -446,6 +453,37 @@ out:
446EXPORT_SYMBOL(cpu_down); 453EXPORT_SYMBOL(cpu_down);
447#endif /*CONFIG_HOTPLUG_CPU*/ 454#endif /*CONFIG_HOTPLUG_CPU*/
448 455
456/*
457 * Unpark per-CPU smpboot kthreads at CPU-online time.
458 */
459static int smpboot_thread_call(struct notifier_block *nfb,
460 unsigned long action, void *hcpu)
461{
462 int cpu = (long)hcpu;
463
464 switch (action & ~CPU_TASKS_FROZEN) {
465
466 case CPU_ONLINE:
467 smpboot_unpark_threads(cpu);
468 break;
469
470 default:
471 break;
472 }
473
474 return NOTIFY_OK;
475}
476
477static struct notifier_block smpboot_thread_notifier = {
478 .notifier_call = smpboot_thread_call,
479 .priority = CPU_PRI_SMPBOOT,
480};
481
482void __cpuinit smpboot_thread_init(void)
483{
484 register_cpu_notifier(&smpboot_thread_notifier);
485}
486
449/* Requires cpu_add_remove_lock to be held */ 487/* Requires cpu_add_remove_lock to be held */
450static int _cpu_up(unsigned int cpu, int tasks_frozen) 488static int _cpu_up(unsigned int cpu, int tasks_frozen)
451{ 489{
@@ -485,9 +523,6 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
485 goto out_notify; 523 goto out_notify;
486 BUG_ON(!cpu_online(cpu)); 524 BUG_ON(!cpu_online(cpu));
487 525
488 /* Wake the per cpu threads */
489 smpboot_unpark_threads(cpu);
490
491 /* Now call notifier in preparation. */ 526 /* Now call notifier in preparation. */
492 cpu_notify(CPU_ONLINE | mod, hcpu); 527 cpu_notify(CPU_ONLINE | mod, hcpu);
493 528