aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPreeti U Murthy <preeti@linux.vnet.ibm.com>2014-02-25 19:09:06 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-03-04 23:57:04 -0500
commit0d94873011a10cea78d1bc0ba8cfc4203559d534 (patch)
tree852cdaaf289b4c80b80f908fd459d161d12721a8
parent97eb001f03494758a938300908b88929163650ce (diff)
cpuidle/powernv: Add "Fast-Sleep" CPU idle state
Fast sleep is one of the deep idle states on Power8 in which local timers of CPUs stop. On PowerPC we do not have an external clock device which can handle wakeup of such CPUs. Now that we have the support in the tick broadcast framework for archs that do not sport such a device and the low level support for fast sleep, enable it in the cpuidle framework on PowerNV. Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/kernel/time.c4
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c34
3 files changed, 39 insertions, 1 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 957bf344c0f5..b84142000a4d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -130,6 +130,8 @@ config PPC
130 select GENERIC_CMOS_UPDATE 130 select GENERIC_CMOS_UPDATE
131 select GENERIC_TIME_VSYSCALL_OLD 131 select GENERIC_TIME_VSYSCALL_OLD
132 select GENERIC_CLOCKEVENTS 132 select GENERIC_CLOCKEVENTS
133 select GENERIC_CLOCKEVENTS_BROADCAST if SMP
134 select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
133 select GENERIC_STRNCPY_FROM_USER 135 select GENERIC_STRNCPY_FROM_USER
134 select GENERIC_STRNLEN_USER 136 select GENERIC_STRNLEN_USER
135 select HAVE_MOD_ARCH_SPECIFIC 137 select HAVE_MOD_ARCH_SPECIFIC
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index df2989b0d4c0..122a580f7322 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -42,6 +42,7 @@
42#include <linux/timex.h> 42#include <linux/timex.h>
43#include <linux/kernel_stat.h> 43#include <linux/kernel_stat.h>
44#include <linux/time.h> 44#include <linux/time.h>
45#include <linux/clockchips.h>
45#include <linux/init.h> 46#include <linux/init.h>
46#include <linux/profile.h> 47#include <linux/profile.h>
47#include <linux/cpu.h> 48#include <linux/cpu.h>
@@ -106,7 +107,7 @@ struct clock_event_device decrementer_clockevent = {
106 .irq = 0, 107 .irq = 0,
107 .set_next_event = decrementer_set_next_event, 108 .set_next_event = decrementer_set_next_event,
108 .set_mode = decrementer_set_mode, 109 .set_mode = decrementer_set_mode,
109 .features = CLOCK_EVT_FEAT_ONESHOT, 110 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
110}; 111};
111EXPORT_SYMBOL(decrementer_clockevent); 112EXPORT_SYMBOL(decrementer_clockevent);
112 113
@@ -944,6 +945,7 @@ void __init time_init(void)
944 clocksource_init(); 945 clocksource_init();
945 946
946 init_decrementer_clockevent(); 947 init_decrementer_clockevent();
948 tick_setup_hrtimer_broadcast();
947} 949}
948 950
949 951
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 78fd174c57e8..4fb97cef82fd 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -11,6 +11,7 @@
11#include <linux/cpuidle.h> 11#include <linux/cpuidle.h>
12#include <linux/cpu.h> 12#include <linux/cpu.h>
13#include <linux/notifier.h> 13#include <linux/notifier.h>
14#include <linux/clockchips.h>
14 15
15#include <asm/machdep.h> 16#include <asm/machdep.h>
16#include <asm/firmware.h> 17#include <asm/firmware.h>
@@ -49,6 +50,32 @@ static int nap_loop(struct cpuidle_device *dev,
49 return index; 50 return index;
50} 51}
51 52
53static int fastsleep_loop(struct cpuidle_device *dev,
54 struct cpuidle_driver *drv,
55 int index)
56{
57 unsigned long old_lpcr = mfspr(SPRN_LPCR);
58 unsigned long new_lpcr;
59
60 if (unlikely(system_state < SYSTEM_RUNNING))
61 return index;
62
63 new_lpcr = old_lpcr;
64 new_lpcr &= ~(LPCR_MER | LPCR_PECE); /* lpcr[mer] must be 0 */
65
66 /* exit powersave upon external interrupt, but not decrementer
67 * interrupt.
68 */
69 new_lpcr |= LPCR_PECE0;
70
71 mtspr(SPRN_LPCR, new_lpcr);
72 power7_sleep();
73
74 mtspr(SPRN_LPCR, old_lpcr);
75
76 return index;
77}
78
52/* 79/*
53 * States for dedicated partition case. 80 * States for dedicated partition case.
54 */ 81 */
@@ -67,6 +94,13 @@ static struct cpuidle_state powernv_states[] = {
67 .exit_latency = 10, 94 .exit_latency = 10,
68 .target_residency = 100, 95 .target_residency = 100,
69 .enter = &nap_loop }, 96 .enter = &nap_loop },
97 { /* Fastsleep */
98 .name = "fastsleep",
99 .desc = "fastsleep",
100 .flags = CPUIDLE_FLAG_TIME_VALID,
101 .exit_latency = 10,
102 .target_residency = 100,
103 .enter = &fastsleep_loop },
70}; 104};
71 105
72static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n, 106static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,