aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2006-10-01 02:27:17 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-01 03:39:19 -0400
commit5c87579e65ee4f419b2369407f82326d38b5d2d8 (patch)
tree3e015ba93eb6eefb7ed4318daf95be0771d596a8 /drivers/acpi
parent130c6b98984a058068ea595c465fba2beb48b9ef (diff)
[PATCH] maximum latency tracking infrastructure
Add infrastructure to track "maximum allowable latency" for power saving policies. The reason for adding this infrastructure is that power management in the idle loop needs to make a tradeoff between latency and power savings (deeper power save modes have a longer latency to running code again). The code that today makes this tradeoff just does a rather simple algorithm; however this is not good enough: There are devices and use cases where a lower latency is required than that the higher power saving states provide. An example would be audio playback, but another example is the ipw2100 wireless driver that right now has a very direct and ugly acpi hook to disable some higher power states randomly when it gets certain types of error. The proposed solution is to have an interface where drivers can * announce the maximum latency (in microseconds) that they can deal with * modify this latency * give up their constraint and a function where the code that decides on power saving strategy can query the current global desired maximum. This patch has a user of each side: on the consumer side, ACPI is patched to use this, on the producer side the ipw2100 driver is patched. A generic maximum latency is also registered of 2 timer ticks (more and you lose accurate time tracking after all). While the existing users of the patch are x86 specific, the infrastructure is not. I'd like to ask the arch maintainers of other architectures if the infrastructure is generic enough for their use (assuming the architecture has such a tradeoff as concept at all), and the sound/multimedia driver owners to look at the driver facing API to see if this is something they can use. [akpm@osdl.org: cleanups] Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Acked-by: Jesse Barnes <jesse.barnes@intel.com> Cc: "Brown, Len" <len.brown@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/processor_idle.c38
1 files changed, 34 insertions, 4 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 71066066d626..0a395fca843b 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -38,6 +38,7 @@
38#include <linux/dmi.h> 38#include <linux/dmi.h>
39#include <linux/moduleparam.h> 39#include <linux/moduleparam.h>
40#include <linux/sched.h> /* need_resched() */ 40#include <linux/sched.h> /* need_resched() */
41#include <linux/latency.h>
41 42
42#include <asm/io.h> 43#include <asm/io.h>
43#include <asm/uaccess.h> 44#include <asm/uaccess.h>
@@ -453,7 +454,8 @@ static void acpi_processor_idle(void)
453 */ 454 */
454 if (cx->promotion.state && 455 if (cx->promotion.state &&
455 ((cx->promotion.state - pr->power.states) <= max_cstate)) { 456 ((cx->promotion.state - pr->power.states) <= max_cstate)) {
456 if (sleep_ticks > cx->promotion.threshold.ticks) { 457 if (sleep_ticks > cx->promotion.threshold.ticks &&
458 cx->promotion.state->latency <= system_latency_constraint()) {
457 cx->promotion.count++; 459 cx->promotion.count++;
458 cx->demotion.count = 0; 460 cx->demotion.count = 0;
459 if (cx->promotion.count >= 461 if (cx->promotion.count >=
@@ -494,8 +496,10 @@ static void acpi_processor_idle(void)
494 end: 496 end:
495 /* 497 /*
496 * Demote if current state exceeds max_cstate 498 * Demote if current state exceeds max_cstate
499 * or if the latency of the current state is unacceptable
497 */ 500 */
498 if ((pr->power.state - pr->power.states) > max_cstate) { 501 if ((pr->power.state - pr->power.states) > max_cstate ||
502 pr->power.state->latency > system_latency_constraint()) {
499 if (cx->demotion.state) 503 if (cx->demotion.state)
500 next_state = cx->demotion.state; 504 next_state = cx->demotion.state;
501 } 505 }
@@ -1009,9 +1013,11 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
1009 1013
1010 seq_printf(seq, "active state: C%zd\n" 1014 seq_printf(seq, "active state: C%zd\n"
1011 "max_cstate: C%d\n" 1015 "max_cstate: C%d\n"
1012 "bus master activity: %08x\n", 1016 "bus master activity: %08x\n"
1017 "maximum allowed latency: %d usec\n",
1013 pr->power.state ? pr->power.state - pr->power.states : 0, 1018 pr->power.state ? pr->power.state - pr->power.states : 0,
1014 max_cstate, (unsigned)pr->power.bm_activity); 1019 max_cstate, (unsigned)pr->power.bm_activity,
1020 system_latency_constraint());
1015 1021
1016 seq_puts(seq, "states:\n"); 1022 seq_puts(seq, "states:\n");
1017 1023
@@ -1077,6 +1083,28 @@ static const struct file_operations acpi_processor_power_fops = {
1077 .release = single_release, 1083 .release = single_release,
1078}; 1084};
1079 1085
1086static void smp_callback(void *v)
1087{
1088 /* we already woke the CPU up, nothing more to do */
1089}
1090
1091/*
1092 * This function gets called when a part of the kernel has a new latency
1093 * requirement. This means we need to get all processors out of their C-state,
1094 * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
1095 * wakes them all right up.
1096 */
1097static int acpi_processor_latency_notify(struct notifier_block *b,
1098 unsigned long l, void *v)
1099{
1100 smp_call_function(smp_callback, NULL, 0, 1);
1101 return NOTIFY_OK;
1102}
1103
1104static struct notifier_block acpi_processor_latency_notifier = {
1105 .notifier_call = acpi_processor_latency_notify,
1106};
1107
1080int acpi_processor_power_init(struct acpi_processor *pr, 1108int acpi_processor_power_init(struct acpi_processor *pr,
1081 struct acpi_device *device) 1109 struct acpi_device *device)
1082{ 1110{
@@ -1093,6 +1121,7 @@ int acpi_processor_power_init(struct acpi_processor *pr,
1093 "ACPI: processor limited to max C-state %d\n", 1121 "ACPI: processor limited to max C-state %d\n",
1094 max_cstate); 1122 max_cstate);
1095 first_run++; 1123 first_run++;
1124 register_latency_notifier(&acpi_processor_latency_notifier);
1096 } 1125 }
1097 1126
1098 if (!pr) 1127 if (!pr)
@@ -1164,6 +1193,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
1164 * copies of pm_idle before proceeding. 1193 * copies of pm_idle before proceeding.
1165 */ 1194 */
1166 cpu_idle_wait(); 1195 cpu_idle_wait();
1196 unregister_latency_notifier(&acpi_processor_latency_notifier);
1167 } 1197 }
1168 1198
1169 return 0; 1199 return 0;