aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c9
5 files changed, 68 insertions, 7 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 /*
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 7d3a3497dd4c..0a7d827897e4 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -16,13 +16,10 @@
16 16
17#include <asm/machdep.h> 17#include <asm/machdep.h>
18#include <asm/firmware.h> 18#include <asm/firmware.h>
19#include <asm/opal.h>
19#include <asm/runlatch.h> 20#include <asm/runlatch.h>
20 21
21/* Flags and constants used in PowerNV platform */
22
23#define MAX_POWERNV_IDLE_STATES 8 22#define MAX_POWERNV_IDLE_STATES 8
24#define IDLE_USE_INST_NAP 0x00010000 /* Use nap instruction */
25#define IDLE_USE_INST_SLEEP 0x00020000 /* Use sleep instruction */
26 23
27struct cpuidle_driver powernv_idle_driver = { 24struct cpuidle_driver powernv_idle_driver = {
28 .name = "powernv_idle", 25 .name = "powernv_idle",
@@ -198,7 +195,7 @@ static int powernv_add_idle_states(void)
198 * target residency to be 10x exit_latency 195 * target residency to be 10x exit_latency
199 */ 196 */
200 latency_ns = be32_to_cpu(idle_state_latency[i]); 197 latency_ns = be32_to_cpu(idle_state_latency[i]);
201 if (flags & IDLE_USE_INST_NAP) { 198 if (flags & OPAL_PM_NAP_ENABLED) {
202 /* Add NAP state */ 199 /* Add NAP state */
203 strcpy(powernv_states[nr_idle_states].name, "Nap"); 200 strcpy(powernv_states[nr_idle_states].name, "Nap");
204 strcpy(powernv_states[nr_idle_states].desc, "Nap"); 201 strcpy(powernv_states[nr_idle_states].desc, "Nap");
@@ -211,7 +208,7 @@ static int powernv_add_idle_states(void)
211 nr_idle_states++; 208 nr_idle_states++;
212 } 209 }
213 210
214 if (flags & IDLE_USE_INST_SLEEP) { 211 if (flags & OPAL_PM_SLEEP_ENABLED) {
215 /* Add FASTSLEEP state */ 212 /* Add FASTSLEEP state */
216 strcpy(powernv_states[nr_idle_states].name, "FastSleep"); 213 strcpy(powernv_states[nr_idle_states].name, "FastSleep");
217 strcpy(powernv_states[nr_idle_states].desc, "FastSleep"); 214 strcpy(powernv_states[nr_idle_states].desc, "FastSleep");