aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-09-19 13:44:54 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2011-09-20 02:09:45 -0400
commit344eb010b2e399069bac474a9fd0ba04908a2601 (patch)
tree5d3e5a2c62651c437318a23b9934fec027576cb2 /arch
parent78b782cb788cadbda151ecb61753c109602a250c (diff)
powerpc/powernv: Add CPU hotplug support
Unplugged CPU go into NAP mode in a loop until woken up Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/platforms/powernv/smp.c78
2 files changed, 78 insertions, 2 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 62711421cd64..8523bd1b8d7e 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -323,7 +323,7 @@ config SWIOTLB
323 323
324config HOTPLUG_CPU 324config HOTPLUG_CPU
325 bool "Support for enabling/disabling CPUs" 325 bool "Support for enabling/disabling CPUs"
326 depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC) 326 depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
327 ---help--- 327 ---help---
328 Say Y here to be able to disable and re-enable individual 328 Say Y here to be able to disable and re-enable individual
329 CPUs at runtime on SMP machines. 329 CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index 36c715102c58..4f4ec3797eb6 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -33,7 +33,14 @@
33 33
34#include "powernv.h" 34#include "powernv.h"
35 35
36static void __devinit pnv_smp_setup_cpu(int cpu) 36#ifdef DEBUG
37#include <asm/udbg.h>
38#define DBG(fmt...) udbg_printf(fmt)
39#else
40#define DBG(fmt...)
41#endif
42
43static void __cpuinit pnv_smp_setup_cpu(int cpu)
37{ 44{
38 if (cpu != boot_cpuid) 45 if (cpu != boot_cpuid)
39 xics_setup_cpu(); 46 xics_setup_cpu();
@@ -55,6 +62,67 @@ static int pnv_smp_cpu_bootable(unsigned int nr)
55 return 1; 62 return 1;
56} 63}
57 64
65#ifdef CONFIG_HOTPLUG_CPU
66
67static int pnv_smp_cpu_disable(void)
68{
69 int cpu = smp_processor_id();
70
71 /* This is identical to pSeries... might consolidate by
72 * moving migrate_irqs_away to a ppc_md with default to
73 * the generic fixup_irqs. --BenH.
74 */
75 set_cpu_online(cpu, false);
76 vdso_data->processorCount--;
77 if (cpu == boot_cpuid)
78 boot_cpuid = cpumask_any(cpu_online_mask);
79 xics_migrate_irqs_away();
80 return 0;
81}
82
83static void pnv_smp_cpu_kill_self(void)
84{
85 unsigned int cpu;
86
87 /* If powersave_nap is enabled, use NAP mode, else just
88 * spin aimlessly
89 */
90 if (!powersave_nap) {
91 generic_mach_cpu_die();
92 return;
93 }
94
95 /* Standard hot unplug procedure */
96 local_irq_disable();
97 idle_task_exit();
98 current->active_mm = NULL; /* for sanity */
99 cpu = smp_processor_id();
100 DBG("CPU%d offline\n", cpu);
101 generic_set_cpu_dead(cpu);
102 smp_wmb();
103
104 /* We don't want to take decrementer interrupts while we are offline,
105 * so clear LPCR:PECE1. We keep PECE2 enabled.
106 */
107 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
108 while (!generic_check_cpu_restart(cpu)) {
109 power7_idle();
110 if (!generic_check_cpu_restart(cpu)) {
111 DBG("CPU%d Unexpected exit while offline !\n", cpu);
112 /* We may be getting an IPI, so we re-enable
113 * interrupts to process it, it will be ignored
114 * since we aren't online (hopefully)
115 */
116 local_irq_enable();
117 local_irq_disable();
118 }
119 }
120 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1);
121 DBG("CPU%d coming online...\n", cpu);
122}
123
124#endif /* CONFIG_HOTPLUG_CPU */
125
58static struct smp_ops_t pnv_smp_ops = { 126static struct smp_ops_t pnv_smp_ops = {
59 .message_pass = smp_muxed_ipi_message_pass, 127 .message_pass = smp_muxed_ipi_message_pass,
60 .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ 128 .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
@@ -62,6 +130,10 @@ static struct smp_ops_t pnv_smp_ops = {
62 .kick_cpu = smp_generic_kick_cpu, 130 .kick_cpu = smp_generic_kick_cpu,
63 .setup_cpu = pnv_smp_setup_cpu, 131 .setup_cpu = pnv_smp_setup_cpu,
64 .cpu_bootable = pnv_smp_cpu_bootable, 132 .cpu_bootable = pnv_smp_cpu_bootable,
133#ifdef CONFIG_HOTPLUG_CPU
134 .cpu_disable = pnv_smp_cpu_disable,
135 .cpu_die = generic_cpu_die,
136#endif /* CONFIG_HOTPLUG_CPU */
65}; 137};
66 138
67/* This is called very early during platform setup_arch */ 139/* This is called very early during platform setup_arch */
@@ -80,4 +152,8 @@ void __init pnv_smp_init(void)
80 smp_ops->take_timebase = rtas_take_timebase; 152 smp_ops->take_timebase = rtas_take_timebase;
81 } 153 }
82#endif /* CONFIG_PPC_RTAS */ 154#endif /* CONFIG_PPC_RTAS */
155
156#ifdef CONFIG_HOTPLUG_CPU
157 ppc_md.cpu_die = pnv_smp_cpu_kill_self;
158#endif
83} 159}