diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-09-19 13:44:54 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2011-09-20 02:09:45 -0400 |
commit | 344eb010b2e399069bac474a9fd0ba04908a2601 (patch) | |
tree | 5d3e5a2c62651c437318a23b9934fec027576cb2 /arch | |
parent | 78b782cb788cadbda151ecb61753c109602a250c (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/Kconfig | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 78 |
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 | ||
324 | config HOTPLUG_CPU | 324 | config 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 | ||
36 | static 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 | |||
43 | static 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 | |||
67 | static 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 | |||
83 | static 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 | |||
58 | static struct smp_ops_t pnv_smp_ops = { | 126 | static 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 | } |