aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-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 /*