Commit 2af6e243 authored by Len Brown's avatar Len Brown Committed by Len Brown

[ACPI] make the c-state policy decisions of demotion and promotion

independent of the assumption "one state per type."
make the state a pointer inside struct acpi_processor_cx_policy.
make max_cstate aware of c-state types instead of c-state number.

http://bugzilla.kernel.org/show_bug.cgi?id=1958Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.de>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 4dac0c1e
...@@ -97,15 +97,14 @@ ticks_elapsed ( ...@@ -97,15 +97,14 @@ ticks_elapsed (
static void static void
acpi_processor_power_activate ( acpi_processor_power_activate (
struct acpi_processor *pr, struct acpi_processor *pr,
int state) struct acpi_processor_cx *new)
{ {
struct acpi_processor_cx *old, *new; struct acpi_processor_cx *old;
if (!pr) if (!pr || !new)
return; return;
old = pr->power.state; old = pr->power.state;
new = &pr->power.states[state];
if (old) if (old)
old->promotion.count = 0; old->promotion.count = 0;
...@@ -141,7 +140,7 @@ void acpi_processor_idle (void) ...@@ -141,7 +140,7 @@ void acpi_processor_idle (void)
{ {
struct acpi_processor *pr = NULL; struct acpi_processor *pr = NULL;
struct acpi_processor_cx *cx = NULL; struct acpi_processor_cx *cx = NULL;
int next_state = 0; struct acpi_processor_cx *next_state = NULL;
int sleep_ticks = 0; int sleep_ticks = 0;
u32 t1, t2 = 0; u32 t1, t2 = 0;
...@@ -281,7 +280,7 @@ void acpi_processor_idle (void) ...@@ -281,7 +280,7 @@ void acpi_processor_idle (void)
return; return;
} }
next_state = pr->power.state - pr->power.states; next_state = pr->power.state;
/* /*
* Promotion? * Promotion?
...@@ -291,7 +290,7 @@ void acpi_processor_idle (void) ...@@ -291,7 +290,7 @@ void acpi_processor_idle (void)
* mastering activity may prevent promotions. * mastering activity may prevent promotions.
* Do not promote above max_cstate. * Do not promote above max_cstate.
*/ */
if (cx->promotion.state && (cx->promotion.state <= max_cstate)) { if (cx->promotion.state && (cx->promotion.state->type <= max_cstate)) {
if (sleep_ticks > cx->promotion.threshold.ticks) { if (sleep_ticks > cx->promotion.threshold.ticks) {
cx->promotion.count++; cx->promotion.count++;
cx->demotion.count = 0; cx->demotion.count = 0;
...@@ -342,7 +341,7 @@ void acpi_processor_idle (void) ...@@ -342,7 +341,7 @@ void acpi_processor_idle (void)
* If we're going to start using a new Cx state we must clean up * If we're going to start using a new Cx state we must clean up
* from the previous and prepare to use the new. * from the previous and prepare to use the new.
*/ */
if (&pr->power.states[next_state] != pr->power.state) if (next_state != pr->power.state)
acpi_processor_power_activate(pr, next_state); acpi_processor_power_activate(pr, next_state);
return; return;
...@@ -361,7 +360,16 @@ static int ...@@ -361,7 +360,16 @@ static int
acpi_processor_set_power_policy ( acpi_processor_set_power_policy (
struct acpi_processor *pr) struct acpi_processor *pr)
{ {
ACPI_FUNCTION_TRACE("acpi_processor_set_power_policy"); unsigned int i;
unsigned int state_is_set = 0;
struct acpi_processor_cx *lower = NULL;
struct acpi_processor_cx *higher = NULL;
struct acpi_processor_cx *cx;
ACPI_FUNCTION_TRACE("acpi_processor_set_power_policy");
if (!pr)
return_VALUE(-EINVAL);
/* /*
* This function sets the default Cx state policy (OS idle handler). * This function sets the default Cx state policy (OS idle handler).
...@@ -372,67 +380,62 @@ acpi_processor_set_power_policy ( ...@@ -372,67 +380,62 @@ acpi_processor_set_power_policy (
* customizable and can be altered dynamically. * customizable and can be altered dynamically.
*/ */
if (!pr) /* startup state */
return_VALUE(-EINVAL); for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
cx = &pr->power.states[i];
if (!cx->valid)
continue;
/* if (!state_is_set)
* C0/C1 pr->power.state = cx;
* ----- state_is_set++;
*/ break;
pr->power.state = &pr->power.states[ACPI_STATE_C1]; }
/* if (!state_is_set)
* C1/C2 return_VALUE(-ENODEV);
* -----
* Set the default C1 promotion and C2 demotion policies, where we /* demotion */
* promote from C1 to C2 after several (10) successive C1 transitions, for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
* as we cannot (currently) measure the time spent in C1. Demote from cx = &pr->power.states[i];
* C2 to C1 anytime we experience a 'short' (time spent in C2 is less if (!cx->valid)
* than the C2 transtion latency). Note the simplifying assumption continue;
* that the 'cost' of a transition is amortized when we sleep for at
* least as long as the transition's latency (thus the total transition if (lower) {
* time is two times the latency). cx->demotion.state = lower;
* cx->demotion.threshold.ticks = cx->latency_ticks;
* TBD: Measure C1 sleep times by instrumenting the core IRQ handler. cx->demotion.threshold.count = 1;
* TBD: Demote to default C-State after long periods of activity. if (cx->type == ACPI_STATE_C3)
* TBD: Investigate policy's use of CPU utilization -vs- sleep duration. cx->demotion.threshold.bm = 0x0F;
*/ }
if (pr->power.states[ACPI_STATE_C2].valid) {
pr->power.states[ACPI_STATE_C1].promotion.threshold.count = 10; /* from C3 we always demote to C2, even if there are multiple
pr->power.states[ACPI_STATE_C1].promotion.threshold.ticks = * states of type C3 available. */
pr->power.states[ACPI_STATE_C2].latency_ticks; if (cx->type < ACPI_STATE_C3)
pr->power.states[ACPI_STATE_C1].promotion.state = ACPI_STATE_C2; lower = cx;
pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 1;
pr->power.states[ACPI_STATE_C2].demotion.threshold.ticks =
pr->power.states[ACPI_STATE_C2].latency_ticks;
pr->power.states[ACPI_STATE_C2].demotion.state = ACPI_STATE_C1;
} }
/* /* promotion */
* C2/C3 for (i = (ACPI_PROCESSOR_MAX_POWER - 1); i > 0; i--) {
* ----- cx = &pr->power.states[i];
* Set default C2 promotion and C3 demotion policies, where we promote if (!cx->valid)
* from C2 to C3 after several (4) cycles of no bus mastering activity continue;
* while maintaining sleep time criteria. Demote immediately on a
* short or whenever bus mastering activity occurs. if (higher) {
*/ cx->promotion.state = higher;
if ((pr->power.states[ACPI_STATE_C2].valid) && cx->demotion.threshold.ticks = cx->latency_ticks;
(pr->power.states[ACPI_STATE_C3].valid)) { if (cx->type >= ACPI_STATE_C2)
pr->power.states[ACPI_STATE_C2].promotion.threshold.count = 4; cx->promotion.threshold.count = 4;
pr->power.states[ACPI_STATE_C2].promotion.threshold.ticks = else
pr->power.states[ACPI_STATE_C3].latency_ticks; cx->promotion.threshold.count = 10;
pr->power.states[ACPI_STATE_C2].promotion.threshold.bm = 0x0F; if (higher->type == ACPI_STATE_C3)
pr->power.states[ACPI_STATE_C2].promotion.state = ACPI_STATE_C3; cx->demotion.threshold.bm = 0x0F;
}
pr->power.states[ACPI_STATE_C3].demotion.threshold.count = 1;
pr->power.states[ACPI_STATE_C3].demotion.threshold.ticks = higher = cx;
pr->power.states[ACPI_STATE_C3].latency_ticks;
pr->power.states[ACPI_STATE_C3].demotion.threshold.bm = 0x0F;
pr->power.states[ACPI_STATE_C3].demotion.state = ACPI_STATE_C2;
} }
return_VALUE(0); return_VALUE(0);
} }
...@@ -684,13 +687,15 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) ...@@ -684,13 +687,15 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
if (pr->power.states[i].promotion.state) if (pr->power.states[i].promotion.state)
seq_printf(seq, "promotion[%d] ", seq_printf(seq, "promotion[%d] ",
pr->power.states[i].promotion.state); (pr->power.states[i].promotion.state -
pr->power.states));
else else
seq_puts(seq, "promotion[-] "); seq_puts(seq, "promotion[-] ");
if (pr->power.states[i].demotion.state) if (pr->power.states[i].demotion.state)
seq_printf(seq, "demotion[%d] ", seq_printf(seq, "demotion[%d] ",
pr->power.states[i].demotion.state); (pr->power.states[i].demotion.state -
pr->power.states));
else else
seq_puts(seq, "demotion[-] "); seq_puts(seq, "demotion[-] ");
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
/* Power Management */ /* Power Management */
struct acpi_processor_cx;
struct acpi_processor_cx_policy { struct acpi_processor_cx_policy {
u32 count; u32 count;
u32 state; struct acpi_processor_cx *state;
struct { struct {
u32 time; u32 time;
u32 ticks; u32 ticks;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment