summaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorPreeti U Murthy <preeti@linux.vnet.ibm.com>2014-02-26 01:09:06 +0100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-03-05 05:57:04 +0100
commit0d94873011a10cea78d1bc0ba8cfc4203559d534 (patch)
tree852cdaaf289b4c80b80f908fd459d161d12721a8 /drivers/cpuidle
parentpowerpc/powernv: Add OPAL call to resync timebase on wakeup (diff)
downloadlinux-0d94873011a10cea78d1bc0ba8cfc4203559d534.tar.xz
linux-0d94873011a10cea78d1bc0ba8cfc4203559d534.zip
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>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c34
1 files changed, 34 insertions, 0 deletions
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 @@
#include <linux/cpuidle.h>
#include <linux/cpu.h>
#include <linux/notifier.h>
+#include <linux/clockchips.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
@@ -49,6 +50,32 @@ static int nap_loop(struct cpuidle_device *dev,
return index;
}
+static int fastsleep_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long old_lpcr = mfspr(SPRN_LPCR);
+ unsigned long new_lpcr;
+
+ if (unlikely(system_state < SYSTEM_RUNNING))
+ return index;
+
+ new_lpcr = old_lpcr;
+ new_lpcr &= ~(LPCR_MER | LPCR_PECE); /* lpcr[mer] must be 0 */
+
+ /* exit powersave upon external interrupt, but not decrementer
+ * interrupt.
+ */
+ new_lpcr |= LPCR_PECE0;
+
+ mtspr(SPRN_LPCR, new_lpcr);
+ power7_sleep();
+
+ mtspr(SPRN_LPCR, old_lpcr);
+
+ return index;
+}
+
/*
* States for dedicated partition case.
*/
@@ -67,6 +94,13 @@ static struct cpuidle_state powernv_states[] = {
.exit_latency = 10,
.target_residency = 100,
.enter = &nap_loop },
+ { /* Fastsleep */
+ .name = "fastsleep",
+ .desc = "fastsleep",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 100,
+ .enter = &fastsleep_loop },
};
static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,