powerpc/smp: More generic support for "soft hotplug"
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 19 Sep 2011 17:44:49 +0000 (17:44 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 20 Sep 2011 05:53:24 +0000 (15:53 +1000)
This adds more generic support for doing CPU hotplug with a simple
idle loop and no actual reset of the processors. The generic
smp_generic_kick_cpu() does the hotplug bringup trick if the PACA
shows that the CPU has already been started at boot and we provide
an accessor for the CPU state.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/smp.h
arch/powerpc/kernel/smp.c

index 15a70b7..adba970 100644 (file)
@@ -65,6 +65,7 @@ int generic_cpu_disable(void);
 void generic_cpu_die(unsigned int cpu);
 void generic_mach_cpu_die(void);
 void generic_set_cpu_dead(unsigned int cpu);
+int generic_check_cpu_restart(unsigned int cpu);
 #endif
 
 #ifdef CONFIG_PPC64
index 7bf2187..af7e772 100644 (file)
 static DEFINE_PER_CPU(struct task_struct *, idle_thread_array);
 #define get_idle_for_cpu(x)      (per_cpu(idle_thread_array, x))
 #define set_idle_for_cpu(x, p)   (per_cpu(idle_thread_array, x) = (p))
+
+/* State of each CPU during hotplug phases */
+static DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
 #else
 static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
 #define get_idle_for_cpu(x)      (idle_thread_array[(x)])
@@ -104,12 +108,25 @@ int __devinit smp_generic_kick_cpu(int nr)
         * cpu_start field to become non-zero After we set cpu_start,
         * the processor will continue on to secondary_start
         */
-       paca[nr].cpu_start = 1;
-       smp_mb();
+       if (!paca[nr].cpu_start) {
+               paca[nr].cpu_start = 1;
+               smp_mb();
+               return 0;
+       }
+
+#ifdef CONFIG_HOTPLUG_CPU
+       /*
+        * Ok it's not there, so it might be soft-unplugged, let's
+        * try to bring it back
+        */
+       per_cpu(cpu_state, nr) = CPU_UP_PREPARE;
+       smp_wmb();
+       smp_send_reschedule(nr);
+#endif /* CONFIG_HOTPLUG_CPU */
 
        return 0;
 }
-#endif
+#endif /* CONFIG_PPC64 */
 
 static irqreturn_t call_function_action(int irq, void *data)
 {
@@ -357,8 +374,6 @@ void __devinit smp_prepare_boot_cpu(void)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-/* State of each CPU during hotplug phases */
-static DEFINE_PER_CPU(int, cpu_state) = { 0 };
 
 int generic_cpu_disable(void)
 {
@@ -406,6 +421,11 @@ void generic_set_cpu_dead(unsigned int cpu)
 {
        per_cpu(cpu_state, cpu) = CPU_DEAD;
 }
+
+int generic_check_cpu_restart(unsigned int cpu)
+{
+       return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE;
+}
 #endif
 
 struct create_idle {