aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorShreyas B. Prabhu <shreyas@linux.vnet.ibm.com>2014-12-09 13:56:51 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2014-12-14 18:46:40 -0500
commit8eb8ac89a364305d05ad16be983b7890eb462cc3 (patch)
tree4661793e77c8b83bc5c805f3502a8fb5a037aa32 /arch
parent8117ac6a6c2fa0f847ff6a21a1f32c8d2c8501d0 (diff)
powerpc/powernv: Enable Offline CPUs to enter deep idle states
The secondary threads should enter deep idle states so as to gain maximum powersavings when the entire core is offline. To do so the offline path must be made aware of the available deepest idle state. Hence probe the device tree for the possible idle states in powernv core code and expose the deepest idle state through flags. Since the device tree is probed by the cpuidle driver as well, move the parameters required to discover the idle states into an appropriate common place to both the driver and the powernv core code. Another point is that fastsleep idle state may require workarounds in the kernel to function properly. This workaround is introduced in the subsequent patches. However neither the cpuidle driver or the hotplug path need be bothered about this workaround. They will be taken care of by the core powernv code. Originally-by: Srivatsa S. Bhat <srivatsa@mit.edu> Signed-off-by: Preeti U. Murthy <preeti@linux.vnet.ibm.com> Signed-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com> Reviewed-by: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: linux-pm@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/include/asm/opal.h8
-rw-r--r--arch/powerpc/platforms/powernv/powernv.h2
-rw-r--r--arch/powerpc/platforms/powernv/setup.c49
-rw-r--r--arch/powerpc/platforms/powernv/smp.c7
4 files changed, 65 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 4095749c973f..6dedf9b05a86 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -168,6 +168,14 @@ struct opal_sg_list {
168#define OPAL_IPMI_RECV 108 168#define OPAL_IPMI_RECV 108
169#define OPAL_I2C_REQUEST 109 169#define OPAL_I2C_REQUEST 109
170 170
171/* Device tree flags */
172
173/* Flags set in power-mgmt nodes in device tree if
174 * respective idle states are supported in the platform.
175 */
176#define OPAL_PM_NAP_ENABLED 0x00010000
177#define OPAL_PM_SLEEP_ENABLED 0x00020000
178
171#ifndef __ASSEMBLY__ 179#ifndef __ASSEMBLY__
172 180
173#include <linux/notifier.h> 181#include <linux/notifier.h>
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index 6c8e2d188cd0..604c48e7879a 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -29,6 +29,8 @@ static inline u64 pnv_pci_dma_get_required_mask(struct pci_dev *pdev)
29} 29}
30#endif 30#endif
31 31
32extern u32 pnv_get_supported_cpuidle_states(void);
33
32extern void pnv_lpc_init(void); 34extern void pnv_lpc_init(void);
33 35
34bool cpu_core_split_required(void); 36bool cpu_core_split_required(void);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 30b1c3e298a6..88e579e62a73 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -288,6 +288,55 @@ static void __init pnv_setup_machdep_rtas(void)
288} 288}
289#endif /* CONFIG_PPC_POWERNV_RTAS */ 289#endif /* CONFIG_PPC_POWERNV_RTAS */
290 290
291static u32 supported_cpuidle_states;
292
293u32 pnv_get_supported_cpuidle_states(void)
294{
295 return supported_cpuidle_states;
296}
297
298static int __init pnv_init_idle_states(void)
299{
300 struct device_node *power_mgt;
301 int dt_idle_states;
302 const __be32 *idle_state_flags;
303 u32 len_flags, flags;
304 int i;
305
306 supported_cpuidle_states = 0;
307
308 if (cpuidle_disable != IDLE_NO_OVERRIDE)
309 return 0;
310
311 if (!firmware_has_feature(FW_FEATURE_OPALv3))
312 return 0;
313
314 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
315 if (!power_mgt) {
316 pr_warn("opal: PowerMgmt Node not found\n");
317 return 0;
318 }
319
320 idle_state_flags = of_get_property(power_mgt,
321 "ibm,cpu-idle-state-flags", &len_flags);
322 if (!idle_state_flags) {
323 pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
324 return 0;
325 }
326
327 dt_idle_states = len_flags / sizeof(u32);
328
329 for (i = 0; i < dt_idle_states; i++) {
330 flags = be32_to_cpu(idle_state_flags[i]);
331 supported_cpuidle_states |= flags;
332 }
333
334 return 0;
335}
336
337subsys_initcall(pnv_init_idle_states);
338
339
291static int __init pnv_probe(void) 340static int __init pnv_probe(void)
292{ 341{
293 unsigned long root = of_get_flat_dt_root(); 342 unsigned long root = of_get_flat_dt_root();
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index b716f666e48a..83299ef2dc3d 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -150,6 +150,7 @@ static void pnv_smp_cpu_kill_self(void)
150{ 150{
151 unsigned int cpu; 151 unsigned int cpu;
152 unsigned long srr1; 152 unsigned long srr1;
153 u32 idle_states;
153 154
154 /* Standard hot unplug procedure */ 155 /* Standard hot unplug procedure */
155 local_irq_disable(); 156 local_irq_disable();
@@ -160,13 +161,17 @@ static void pnv_smp_cpu_kill_self(void)
160 generic_set_cpu_dead(cpu); 161 generic_set_cpu_dead(cpu);
161 smp_wmb(); 162 smp_wmb();
162 163
164 idle_states = pnv_get_supported_cpuidle_states();
163 /* We don't want to take decrementer interrupts while we are offline, 165 /* We don't want to take decrementer interrupts while we are offline,
164 * so clear LPCR:PECE1. We keep PECE2 enabled. 166 * so clear LPCR:PECE1. We keep PECE2 enabled.
165 */ 167 */
166 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); 168 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
167 while (!generic_check_cpu_restart(cpu)) { 169 while (!generic_check_cpu_restart(cpu)) {
168 ppc64_runlatch_off(); 170 ppc64_runlatch_off();
169 srr1 = power7_nap(1); 171 if (idle_states & OPAL_PM_SLEEP_ENABLED)
172 srr1 = power7_sleep();
173 else
174 srr1 = power7_nap(1);
170 ppc64_runlatch_on(); 175 ppc64_runlatch_on();
171 176
172 /* 177 /*