diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/opal.h | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/powernv.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/setup.c | 49 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 7 |
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 | ||
32 | extern u32 pnv_get_supported_cpuidle_states(void); | ||
33 | |||
32 | extern void pnv_lpc_init(void); | 34 | extern void pnv_lpc_init(void); |
33 | 35 | ||
34 | bool cpu_core_split_required(void); | 36 | bool 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 | ||
291 | static u32 supported_cpuidle_states; | ||
292 | |||
293 | u32 pnv_get_supported_cpuidle_states(void) | ||
294 | { | ||
295 | return supported_cpuidle_states; | ||
296 | } | ||
297 | |||
298 | static 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 | |||
337 | subsys_initcall(pnv_init_idle_states); | ||
338 | |||
339 | |||
291 | static int __init pnv_probe(void) | 340 | static 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 | /* |