From: "Gautham R. Shenoy" <ego@xxxxxxxxxxxxxxxxxx> The POWER ISA v3.0 allows stop instruction to be executed from a HV=0,PR=0 context. If the PSSCR[ESL|EC] bits are cleared, then the stop instruction thus executed will cause the thread to pause, thereby donating its cycles to the other threads in the core until the paused thread is woken up by an interrupt. In this patch we define a cpuidle state for pseries guests named stop0lite. This has a latency and residency intermediate to that of snooze and CEDE. While snooze has non-existent latency, it consumes the CPU cycles without contributing to anything useful. CEDE on the other hand requires a full VM exit, which can result in some other vCPU being scheduled on this physical CPU thereby delaying the scheduling of the CEDEd vCPU back. In such cases, when the expected idle duration is small (1-20us), the vCPU can go to this stop0lite state which provides a nice intermediate state between snooze and CEDE. Signed-off-by: Gautham R. Shenoy <ego@xxxxxxxxxxxxxxxxxx> --- drivers/cpuidle/cpuidle-pseries.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c index 74c2479..9c8c18d 100644 --- a/drivers/cpuidle/cpuidle-pseries.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -20,6 +20,7 @@ #include <asm/firmware.h> #include <asm/runlatch.h> #include <asm/plpar_wrappers.h> +#include <asm/processor.h> struct cpuidle_driver pseries_idle_driver = { .name = "pseries_idle", @@ -170,6 +171,26 @@ static int shared_cede_loop(struct cpuidle_device *dev, .enter = &dedicated_cede_loop }, }; + + +static int stop_loop(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long srr1 = 0; + + if (!prep_irq_for_idle_irqsoff()) + return index; + + __ppc64_runlatch_off(); + asm volatile("stop"); + __ppc64_runlatch_on(); + fini_irq_for_idle_irqsoff(); + irq_set_pending_from_srr1(srr1); + + return index; +} + /* * States for shared partition case. */ @@ -180,6 +201,12 @@ static int shared_cede_loop(struct cpuidle_device *dev, .exit_latency = 0, .target_residency = 0, .enter = &snooze_loop }, + { /* stop0_lite */ + .name = "stop0lite", + .desc = "Pauses the CPU", + .exit_latency = 2, + .target_residency=20, + .enter = &stop_loop }, { /* Shared Cede */ .name = "Shared Cede", .desc = "Shared Cede", -- 1.9.4