Commit 344eb010b2e399069bac474a9fd0ba04908a2601
1 parent
78b782cb78
Exists in
master
and in
20 other branches
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>
Showing 2 changed files with 78 additions and 2 deletions Side-by-side Diff
arch/powerpc/Kconfig
... | ... | @@ -323,7 +323,7 @@ |
323 | 323 | |
324 | 324 | config HOTPLUG_CPU |
325 | 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 | 327 | ---help--- |
328 | 328 | Say Y here to be able to disable and re-enable individual |
329 | 329 | CPUs at runtime on SMP machines. |
arch/powerpc/platforms/powernv/smp.c
... | ... | @@ -33,7 +33,14 @@ |
33 | 33 | |
34 | 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 | 45 | if (cpu != boot_cpuid) |
39 | 46 | xics_setup_cpu(); |
... | ... | @@ -55,6 +62,67 @@ |
55 | 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 | 126 | static struct smp_ops_t pnv_smp_ops = { |
59 | 127 | .message_pass = smp_muxed_ipi_message_pass, |
60 | 128 | .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */ |
... | ... | @@ -62,6 +130,10 @@ |
62 | 130 | .kick_cpu = smp_generic_kick_cpu, |
63 | 131 | .setup_cpu = pnv_smp_setup_cpu, |
64 | 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 | 139 | /* This is called very early during platform setup_arch */ |
... | ... | @@ -80,5 +152,9 @@ |
80 | 152 | smp_ops->take_timebase = rtas_take_timebase; |
81 | 153 | } |
82 | 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 | } |