diff --git a/kernel/cpu.c b/kernel/cpu.c index 1972b161c61e98fbe3e3ce003744cf1d2e8c5b1c..d46b4dae0ca097130f78ffa39a5aada6931e5a95 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -408,8 +408,10 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) * * Wait for the stop thread to go away. */ - while (!idle_cpu(cpu)) + while (!per_cpu(cpu_dead_idle, cpu)) cpu_relax(); + smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */ + per_cpu(cpu_dead_idle, cpu) = false; /* This actually kills the CPU. */ __cpu_die(cpu); diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 94b2d7b88a272856bf0f49ac0f0bdce430a5255d..e99e361ade2078b67ac144375025ad9ed7a92cca 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -198,6 +198,8 @@ static void cpuidle_idle_call(void) start_critical_timings(); } +DEFINE_PER_CPU(bool, cpu_dead_idle); + /* * Generic idle loop implementation * @@ -222,8 +224,11 @@ static void cpu_idle_loop(void) check_pgt_cache(); rmb(); - if (cpu_is_offline(smp_processor_id())) + if (cpu_is_offline(smp_processor_id())) { + smp_mb(); /* all activity before dead. */ + this_cpu_write(cpu_dead_idle, true); arch_cpu_idle_dead(); + } local_irq_disable(); arch_cpu_idle_enter();