aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-02-26 13:43:43 -0500
committerThomas Gleixner <tglx@linutronix.de>2016-03-01 14:36:58 -0500
commite69aab13117efc1987620090e539b4ebeb33a04c (patch)
tree94de41d8547dbaa76fffe73f7f2352dbf03ad21b
parent8df3e07e7f21f2ed8d001e6fabf9505946b438aa (diff)
cpu/hotplug: Make wait for dead cpu completion based
Kill the busy spinning on the control side and just wait for the hotplugged cpu to tell that it reached the dead state. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: linux-arch@vger.kernel.org Cc: Rik van Riel <riel@redhat.com> Cc: Rafael Wysocki <rafael.j.wysocki@intel.com> Cc: "Srivatsa S. Bhat" <srivatsa@mit.edu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Sebastian Siewior <bigeasy@linutronix.de> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Tejun Heo <tj@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Paul McKenney <paulmck@linux.vnet.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Turner <pjt@google.com> Link: http://lkml.kernel.org/r/20160226182341.776157858@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/cpu.h5
-rw-r--r--include/linux/cpuhotplug.h1
-rw-r--r--kernel/cpu.c16
-rw-r--r--kernel/sched/idle.c5
4 files changed, 17 insertions, 10 deletions
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 83f35767016d..91a48d1b4ca0 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -276,14 +276,15 @@ void arch_cpu_idle_enter(void);
276void arch_cpu_idle_exit(void); 276void arch_cpu_idle_exit(void);
277void arch_cpu_idle_dead(void); 277void arch_cpu_idle_dead(void);
278 278
279DECLARE_PER_CPU(bool, cpu_dead_idle);
280
281int cpu_report_state(int cpu); 279int cpu_report_state(int cpu);
282int cpu_check_up_prepare(int cpu); 280int cpu_check_up_prepare(int cpu);
283void cpu_set_state_online(int cpu); 281void cpu_set_state_online(int cpu);
284#ifdef CONFIG_HOTPLUG_CPU 282#ifdef CONFIG_HOTPLUG_CPU
285bool cpu_wait_death(unsigned int cpu, int seconds); 283bool cpu_wait_death(unsigned int cpu, int seconds);
286bool cpu_report_death(void); 284bool cpu_report_death(void);
285void cpuhp_report_idle_dead(void);
286#else
287static inline void cpuhp_report_idle_dead(void) { }
287#endif /* #ifdef CONFIG_HOTPLUG_CPU */ 288#endif /* #ifdef CONFIG_HOTPLUG_CPU */
288 289
289#endif /* _LINUX_CPU_H_ */ 290#endif /* _LINUX_CPU_H_ */
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index ad5d7fcb0130..5d68e15e46b7 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -6,6 +6,7 @@ enum cpuhp_state {
6 CPUHP_CREATE_THREADS, 6 CPUHP_CREATE_THREADS,
7 CPUHP_NOTIFY_PREPARE, 7 CPUHP_NOTIFY_PREPARE,
8 CPUHP_BRINGUP_CPU, 8 CPUHP_BRINGUP_CPU,
9 CPUHP_AP_IDLE_DEAD,
9 CPUHP_AP_OFFLINE, 10 CPUHP_AP_OFFLINE,
10 CPUHP_AP_NOTIFY_STARTING, 11 CPUHP_AP_NOTIFY_STARTING,
11 CPUHP_AP_ONLINE, 12 CPUHP_AP_ONLINE,
diff --git a/kernel/cpu.c b/kernel/cpu.c
index f1f880fac832..0e8c07f2566e 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -688,6 +688,7 @@ static int take_cpu_down(void *_param)
688 688
689static int takedown_cpu(unsigned int cpu) 689static int takedown_cpu(unsigned int cpu)
690{ 690{
691 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
691 int err; 692 int err;
692 693
693 /* 694 /*
@@ -733,10 +734,8 @@ static int takedown_cpu(unsigned int cpu)
733 * 734 *
734 * Wait for the stop thread to go away. 735 * Wait for the stop thread to go away.
735 */ 736 */
736 while (!per_cpu(cpu_dead_idle, cpu)) 737 wait_for_completion(&st->done);
737 cpu_relax(); 738 BUG_ON(st->state != CPUHP_AP_IDLE_DEAD);
738 smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */
739 per_cpu(cpu_dead_idle, cpu) = false;
740 739
741 /* Interrupts are moved away from the dying cpu, reenable alloc/free */ 740 /* Interrupts are moved away from the dying cpu, reenable alloc/free */
742 irq_unlock_sparse(); 741 irq_unlock_sparse();
@@ -756,6 +755,15 @@ static int notify_dead(unsigned int cpu)
756 return 0; 755 return 0;
757} 756}
758 757
758void cpuhp_report_idle_dead(void)
759{
760 struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
761
762 BUG_ON(st->state != CPUHP_AP_OFFLINE);
763 st->state = CPUHP_AP_IDLE_DEAD;
764 complete(&st->done);
765}
766
759#else 767#else
760#define notify_down_prepare NULL 768#define notify_down_prepare NULL
761#define takedown_cpu NULL 769#define takedown_cpu NULL
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index a4b9813afc96..8abbe89e9114 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -194,8 +194,6 @@ exit_idle:
194 rcu_idle_exit(); 194 rcu_idle_exit();
195} 195}
196 196
197DEFINE_PER_CPU(bool, cpu_dead_idle);
198
199/* 197/*
200 * Generic idle loop implementation 198 * Generic idle loop implementation
201 * 199 *
@@ -224,8 +222,7 @@ static void cpu_idle_loop(void)
224 if (cpu_is_offline(smp_processor_id())) { 222 if (cpu_is_offline(smp_processor_id())) {
225 rcu_cpu_notify(NULL, CPU_DYING_IDLE, 223 rcu_cpu_notify(NULL, CPU_DYING_IDLE,
226 (void *)(long)smp_processor_id()); 224 (void *)(long)smp_processor_id());
227 smp_mb(); /* all activity before dead. */ 225 cpuhp_report_idle_dead();
228 this_cpu_write(cpu_dead_idle, true);
229 arch_cpu_idle_dead(); 226 arch_cpu_idle_dead();
230 } 227 }
231 228