diff options
author | Deepthi Dharwar <deepthi@linux.vnet.ibm.com> | 2012-10-03 14:42:18 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-10-17 19:57:24 -0400 |
commit | 8ea959a17fe6e27f7954dddad5b17b0e33f0d7ee (patch) | |
tree | e16bf4c3b7a9bbcb2822c862fccf7b1b8ab336b0 /arch/powerpc | |
parent | 817deb05df45577d4037230f2facee486c11d9df (diff) |
cpuidle/powerpc: Fix smt_snooze_delay functionality.
smt_snooze_delay was designed to delay idle loop's nap entry
in the native idle code before it got ported over to use as part of
the cpuidle framework.
A -ve value assigned to smt_snooze_delay should result in
busy looping, in other words disabling the entry to nap state.
- https://lists.ozlabs.org/pipermail/linuxppc-dev/2010-May/082450.html
This particular functionality can be achieved currently by
echo 1 > /sys/devices/system/cpu/cpu*/state1/disable
but it is broken when one assigns -ve value to the smt_snooze_delay
variable either via sysfs entry or ppc64_cpu util.
This patch aims to fix this, by disabling nap state when smt_snooze_delay
variable is set to -ve value.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/sysfs.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/processor_idle.c | 24 |
3 files changed, 20 insertions, 10 deletions
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 8734b3855272..87502046c0dc 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h | |||
@@ -388,9 +388,9 @@ extern int powersave_nap; /* set if nap mode can be used in idle loop */ | |||
388 | extern void power7_nap(void); | 388 | extern void power7_nap(void); |
389 | 389 | ||
390 | #ifdef CONFIG_PSERIES_IDLE | 390 | #ifdef CONFIG_PSERIES_IDLE |
391 | extern void update_smt_snooze_delay(int snooze); | 391 | extern void update_smt_snooze_delay(int cpu, int residency); |
392 | #else | 392 | #else |
393 | static inline void update_smt_snooze_delay(int snooze) {} | 393 | static inline void update_smt_snooze_delay(int cpu, int residency) {} |
394 | #endif | 394 | #endif |
395 | 395 | ||
396 | extern void flush_instruction_cache(void); | 396 | extern void flush_instruction_cache(void); |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 8302af649219..cf357a059ddb 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -50,7 +50,7 @@ static ssize_t store_smt_snooze_delay(struct device *dev, | |||
50 | return -EINVAL; | 50 | return -EINVAL; |
51 | 51 | ||
52 | per_cpu(smt_snooze_delay, cpu->dev.id) = snooze; | 52 | per_cpu(smt_snooze_delay, cpu->dev.id) = snooze; |
53 | update_smt_snooze_delay(snooze); | 53 | update_smt_snooze_delay(cpu->dev.id, snooze); |
54 | 54 | ||
55 | return count; | 55 | return count; |
56 | } | 56 | } |
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 02e425aa2af8..a32d56d1f854 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c | |||
@@ -33,13 +33,6 @@ static int max_idle_state = MAX_IDLE_STATE_COUNT - 1; | |||
33 | static struct cpuidle_device __percpu *pseries_cpuidle_devices; | 33 | static struct cpuidle_device __percpu *pseries_cpuidle_devices; |
34 | static struct cpuidle_state *cpuidle_state_table; | 34 | static struct cpuidle_state *cpuidle_state_table; |
35 | 35 | ||
36 | void update_smt_snooze_delay(int snooze) | ||
37 | { | ||
38 | struct cpuidle_driver *drv = cpuidle_get_driver(); | ||
39 | if (drv) | ||
40 | drv->states[0].target_residency = snooze; | ||
41 | } | ||
42 | |||
43 | static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) | 36 | static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before) |
44 | { | 37 | { |
45 | 38 | ||
@@ -190,6 +183,23 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = { | |||
190 | .enter = &shared_cede_loop }, | 183 | .enter = &shared_cede_loop }, |
191 | }; | 184 | }; |
192 | 185 | ||
186 | void update_smt_snooze_delay(int cpu, int residency) | ||
187 | { | ||
188 | struct cpuidle_driver *drv = cpuidle_get_driver(); | ||
189 | struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); | ||
190 | |||
191 | if (cpuidle_state_table != dedicated_states) | ||
192 | return; | ||
193 | |||
194 | if (residency < 0) { | ||
195 | /* Disable the Nap state on that cpu */ | ||
196 | if (dev) | ||
197 | dev->states_usage[1].disable = 1; | ||
198 | } else | ||
199 | if (drv) | ||
200 | drv->states[0].target_residency = residency; | ||
201 | } | ||
202 | |||
193 | static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n, | 203 | static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n, |
194 | unsigned long action, void *hcpu) | 204 | unsigned long action, void *hcpu) |
195 | { | 205 | { |