ia64/xen-unstable

view xen/arch/x86/acpi/cpuidle_menu.c @ 18748:112e81ae5824

CPUIDLE: Support C1 FFH entry

Add support for C1 FFH (mwait) entry. Meanwhile add timing for C1. The
timing for C1 should be accurate for FFH case, but may not for halt case.

Signed-off-by: Wei Gang <gang.wei@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Oct 30 13:33:40 2008 +0000 (2008-10-30)
parents 706844309f36
children b7f4937d76d1
line source
1 /*
2 * cpuidle_menu - menu governor for cpu idle, main idea come from Linux.
3 * drivers/cpuidle/governors/menu.c
4 *
5 * Copyright (C) 2006-2007 Adam Belay <abelay@novell.com>
6 * Copyright (C) 2007, 2008 Intel Corporation
7 *
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or (at
13 * your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 *
24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 */
26 #include <xen/config.h>
27 #include <xen/errno.h>
28 #include <xen/lib.h>
29 #include <xen/types.h>
30 #include <xen/acpi.h>
31 #include <xen/timer.h>
32 #include <xen/cpuidle.h>
34 #define BREAK_FUZZ 4 /* 4 us */
35 #define USEC_PER_SEC 1000000
37 struct menu_device
38 {
39 int last_state_idx;
40 unsigned int expected_us;
41 unsigned int predicted_us;
42 unsigned int last_measured_us;
43 unsigned int elapsed_us;
44 };
46 static DEFINE_PER_CPU(struct menu_device, menu_devices);
48 static s_time_t get_sleep_length_ns(void)
49 {
50 return per_cpu(timer_deadline, smp_processor_id()) - NOW();
51 }
53 static int menu_select(struct acpi_processor_power *power)
54 {
55 struct menu_device *data = &__get_cpu_var(menu_devices);
56 int i;
58 /* determine the expected residency time */
59 data->expected_us = (u32) get_sleep_length_ns() / 1000;
61 /* find the deepest idle state that satisfies our constraints */
62 for ( i = 2; i < power->count; i++ )
63 {
64 struct acpi_processor_cx *s = &power->states[i];
66 if ( s->target_residency > data->expected_us + s->latency )
67 break;
68 if ( s->target_residency > data->predicted_us )
69 break;
70 /* TBD: we need to check the QoS requirment in future */
71 }
73 data->last_state_idx = i - 1;
74 return i - 1;
75 }
77 static void menu_reflect(struct acpi_processor_power *power)
78 {
79 struct menu_device *data = &__get_cpu_var(menu_devices);
80 struct acpi_processor_cx *target = &power->states[data->last_state_idx];
81 unsigned int last_residency;
82 unsigned int measured_us;
84 last_residency = power->last_residency;
85 measured_us = last_residency + data->elapsed_us;
87 /* if wrapping, set to max uint (-1) */
88 measured_us = data->elapsed_us <= measured_us ? measured_us : -1;
90 /* Predict time remaining until next break event */
91 data->predicted_us = max(measured_us, data->last_measured_us);
93 /* Distinguish between expected & non-expected events */
94 if ( last_residency + BREAK_FUZZ
95 < data->expected_us + target->latency )
96 {
97 data->last_measured_us = measured_us;
98 data->elapsed_us = 0;
99 }
100 else
101 data->elapsed_us = measured_us;
102 }
104 static int menu_enable_device(struct acpi_processor_power *power)
105 {
106 struct menu_device *data = &per_cpu(menu_devices, power->cpu);
108 memset(data, 0, sizeof(struct menu_device));
110 return 0;
111 }
113 static struct cpuidle_governor menu_governor =
114 {
115 .name = "menu",
116 .rating = 20,
117 .enable = menu_enable_device,
118 .select = menu_select,
119 .reflect = menu_reflect,
120 };
122 struct cpuidle_governor *cpuidle_current_governor = &menu_governor;