diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:20:30 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:21:47 -0500 |
commit | d392da5207352f09030e95d9ea335a4225667ec0 (patch) | |
tree | 7d6cd1932afcad0a5619a5c504a6d93ca318187c /drivers/idle/intel_idle.c | |
parent | e39d5ef678045d61812c1401f04fe8edb14d6359 (diff) | |
parent | 387c31c7e5c9805b0aef8833d1731a5fe7bdea14 (diff) |
Merge v2.6.37-rc8 into powerpc/next
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r--[-rwxr-xr-x] | drivers/idle/intel_idle.c | 159 |
1 files changed, 70 insertions, 89 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 03d202b1ff27..c131d58bcb50 100755..100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -59,33 +59,24 @@ | |||
59 | #include <linux/hrtimer.h> /* ktime_get_real() */ | 59 | #include <linux/hrtimer.h> /* ktime_get_real() */ |
60 | #include <trace/events/power.h> | 60 | #include <trace/events/power.h> |
61 | #include <linux/sched.h> | 61 | #include <linux/sched.h> |
62 | #include <asm/mwait.h> | ||
62 | 63 | ||
63 | #define INTEL_IDLE_VERSION "0.4" | 64 | #define INTEL_IDLE_VERSION "0.4" |
64 | #define PREFIX "intel_idle: " | 65 | #define PREFIX "intel_idle: " |
65 | 66 | ||
66 | #define MWAIT_SUBSTATE_MASK (0xf) | ||
67 | #define MWAIT_CSTATE_MASK (0xf) | ||
68 | #define MWAIT_SUBSTATE_SIZE (4) | ||
69 | #define MWAIT_MAX_NUM_CSTATES 8 | ||
70 | #define CPUID_MWAIT_LEAF (5) | ||
71 | #define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1) | ||
72 | #define CPUID5_ECX_INTERRUPT_BREAK (0x2) | ||
73 | |||
74 | static struct cpuidle_driver intel_idle_driver = { | 67 | static struct cpuidle_driver intel_idle_driver = { |
75 | .name = "intel_idle", | 68 | .name = "intel_idle", |
76 | .owner = THIS_MODULE, | 69 | .owner = THIS_MODULE, |
77 | }; | 70 | }; |
78 | /* intel_idle.max_cstate=0 disables driver */ | 71 | /* intel_idle.max_cstate=0 disables driver */ |
79 | static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1; | 72 | static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1; |
80 | static int power_policy = 7; /* 0 = max perf; 15 = max powersave */ | ||
81 | 73 | ||
82 | static unsigned int substates; | 74 | static unsigned int mwait_substates; |
83 | static int (*choose_substate)(int); | ||
84 | 75 | ||
85 | /* Reliable LAPIC Timer States, bit 1 for C1 etc. */ | 76 | /* Reliable LAPIC Timer States, bit 1 for C1 etc. */ |
86 | static unsigned int lapic_timer_reliable_states; | 77 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ |
87 | 78 | ||
88 | static struct cpuidle_device *intel_idle_cpuidle_devices; | 79 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; |
89 | static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); | 80 | static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); |
90 | 81 | ||
91 | static struct cpuidle_state *cpuidle_state_table; | 82 | static struct cpuidle_state *cpuidle_state_table; |
@@ -103,29 +94,62 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
103 | .driver_data = (void *) 0x00, | 94 | .driver_data = (void *) 0x00, |
104 | .flags = CPUIDLE_FLAG_TIME_VALID, | 95 | .flags = CPUIDLE_FLAG_TIME_VALID, |
105 | .exit_latency = 3, | 96 | .exit_latency = 3, |
106 | .power_usage = 1000, | ||
107 | .target_residency = 6, | 97 | .target_residency = 6, |
108 | .enter = &intel_idle }, | 98 | .enter = &intel_idle }, |
109 | { /* MWAIT C2 */ | 99 | { /* MWAIT C2 */ |
110 | .name = "NHM-C3", | 100 | .name = "NHM-C3", |
111 | .desc = "MWAIT 0x10", | 101 | .desc = "MWAIT 0x10", |
112 | .driver_data = (void *) 0x10, | 102 | .driver_data = (void *) 0x10, |
113 | .flags = CPUIDLE_FLAG_TIME_VALID, | 103 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
114 | .exit_latency = 20, | 104 | .exit_latency = 20, |
115 | .power_usage = 500, | ||
116 | .target_residency = 80, | 105 | .target_residency = 80, |
117 | .enter = &intel_idle }, | 106 | .enter = &intel_idle }, |
118 | { /* MWAIT C3 */ | 107 | { /* MWAIT C3 */ |
119 | .name = "NHM-C6", | 108 | .name = "NHM-C6", |
120 | .desc = "MWAIT 0x20", | 109 | .desc = "MWAIT 0x20", |
121 | .driver_data = (void *) 0x20, | 110 | .driver_data = (void *) 0x20, |
122 | .flags = CPUIDLE_FLAG_TIME_VALID, | 111 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
123 | .exit_latency = 200, | 112 | .exit_latency = 200, |
124 | .power_usage = 350, | ||
125 | .target_residency = 800, | 113 | .target_residency = 800, |
126 | .enter = &intel_idle }, | 114 | .enter = &intel_idle }, |
127 | }; | 115 | }; |
128 | 116 | ||
117 | static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { | ||
118 | { /* MWAIT C0 */ }, | ||
119 | { /* MWAIT C1 */ | ||
120 | .name = "SNB-C1", | ||
121 | .desc = "MWAIT 0x00", | ||
122 | .driver_data = (void *) 0x00, | ||
123 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
124 | .exit_latency = 1, | ||
125 | .target_residency = 4, | ||
126 | .enter = &intel_idle }, | ||
127 | { /* MWAIT C2 */ | ||
128 | .name = "SNB-C3", | ||
129 | .desc = "MWAIT 0x10", | ||
130 | .driver_data = (void *) 0x10, | ||
131 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | ||
132 | .exit_latency = 80, | ||
133 | .target_residency = 160, | ||
134 | .enter = &intel_idle }, | ||
135 | { /* MWAIT C3 */ | ||
136 | .name = "SNB-C6", | ||
137 | .desc = "MWAIT 0x20", | ||
138 | .driver_data = (void *) 0x20, | ||
139 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | ||
140 | .exit_latency = 104, | ||
141 | .target_residency = 208, | ||
142 | .enter = &intel_idle }, | ||
143 | { /* MWAIT C4 */ | ||
144 | .name = "SNB-C7", | ||
145 | .desc = "MWAIT 0x30", | ||
146 | .driver_data = (void *) 0x30, | ||
147 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, | ||
148 | .exit_latency = 109, | ||
149 | .target_residency = 300, | ||
150 | .enter = &intel_idle }, | ||
151 | }; | ||
152 | |||
129 | static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | 153 | static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { |
130 | { /* MWAIT C0 */ }, | 154 | { /* MWAIT C0 */ }, |
131 | { /* MWAIT C1 */ | 155 | { /* MWAIT C1 */ |
@@ -134,7 +158,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
134 | .driver_data = (void *) 0x00, | 158 | .driver_data = (void *) 0x00, |
135 | .flags = CPUIDLE_FLAG_TIME_VALID, | 159 | .flags = CPUIDLE_FLAG_TIME_VALID, |
136 | .exit_latency = 1, | 160 | .exit_latency = 1, |
137 | .power_usage = 1000, | ||
138 | .target_residency = 4, | 161 | .target_residency = 4, |
139 | .enter = &intel_idle }, | 162 | .enter = &intel_idle }, |
140 | { /* MWAIT C2 */ | 163 | { /* MWAIT C2 */ |
@@ -143,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
143 | .driver_data = (void *) 0x10, | 166 | .driver_data = (void *) 0x10, |
144 | .flags = CPUIDLE_FLAG_TIME_VALID, | 167 | .flags = CPUIDLE_FLAG_TIME_VALID, |
145 | .exit_latency = 20, | 168 | .exit_latency = 20, |
146 | .power_usage = 500, | ||
147 | .target_residency = 80, | 169 | .target_residency = 80, |
148 | .enter = &intel_idle }, | 170 | .enter = &intel_idle }, |
149 | { /* MWAIT C3 */ }, | 171 | { /* MWAIT C3 */ }, |
@@ -151,58 +173,21 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { | |||
151 | .name = "ATM-C4", | 173 | .name = "ATM-C4", |
152 | .desc = "MWAIT 0x30", | 174 | .desc = "MWAIT 0x30", |
153 | .driver_data = (void *) 0x30, | 175 | .driver_data = (void *) 0x30, |
154 | .flags = CPUIDLE_FLAG_TIME_VALID, | 176 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
155 | .exit_latency = 100, | 177 | .exit_latency = 100, |
156 | .power_usage = 250, | ||
157 | .target_residency = 400, | 178 | .target_residency = 400, |
158 | .enter = &intel_idle }, | 179 | .enter = &intel_idle }, |
159 | { /* MWAIT C5 */ }, | 180 | { /* MWAIT C5 */ }, |
160 | { /* MWAIT C6 */ | 181 | { /* MWAIT C6 */ |
161 | .name = "ATM-C6", | 182 | .name = "ATM-C6", |
162 | .desc = "MWAIT 0x40", | 183 | .desc = "MWAIT 0x52", |
163 | .driver_data = (void *) 0x40, | 184 | .driver_data = (void *) 0x52, |
164 | .flags = CPUIDLE_FLAG_TIME_VALID, | 185 | .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, |
165 | .exit_latency = 200, | 186 | .exit_latency = 140, |
166 | .power_usage = 150, | 187 | .target_residency = 560, |
167 | .target_residency = 800, | 188 | .enter = &intel_idle }, |
168 | .enter = NULL }, /* disabled */ | ||
169 | }; | 189 | }; |
170 | 190 | ||
171 | /* | ||
172 | * choose_tunable_substate() | ||
173 | * | ||
174 | * Run-time decision on which C-state substate to invoke | ||
175 | * If power_policy = 0, choose shallowest substate (0) | ||
176 | * If power_policy = 15, choose deepest substate | ||
177 | * If power_policy = middle, choose middle substate etc. | ||
178 | */ | ||
179 | static int choose_tunable_substate(int cstate) | ||
180 | { | ||
181 | unsigned int num_substates; | ||
182 | unsigned int substate_choice; | ||
183 | |||
184 | power_policy &= 0xF; /* valid range: 0-15 */ | ||
185 | cstate &= 7; /* valid range: 0-7 */ | ||
186 | |||
187 | num_substates = (substates >> ((cstate) * 4)) & MWAIT_SUBSTATE_MASK; | ||
188 | |||
189 | if (num_substates <= 1) | ||
190 | return 0; | ||
191 | |||
192 | substate_choice = ((power_policy + (power_policy + 1) * | ||
193 | (num_substates - 1)) / 16); | ||
194 | |||
195 | return substate_choice; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * choose_zero_substate() | ||
200 | */ | ||
201 | static int choose_zero_substate(int cstate) | ||
202 | { | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /** | 191 | /** |
207 | * intel_idle | 192 | * intel_idle |
208 | * @dev: cpuidle_device | 193 | * @dev: cpuidle_device |
@@ -220,10 +205,15 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) | |||
220 | 205 | ||
221 | cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; | 206 | cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; |
222 | 207 | ||
223 | eax = eax + (choose_substate)(cstate); | ||
224 | |||
225 | local_irq_disable(); | 208 | local_irq_disable(); |
226 | 209 | ||
210 | /* | ||
211 | * leave_mm() to avoid costly and often unnecessary wakeups | ||
212 | * for flushing the user TLB's associated with the active mm. | ||
213 | */ | ||
214 | if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED) | ||
215 | leave_mm(cpu); | ||
216 | |||
227 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) | 217 | if (!(lapic_timer_reliable_states & (1 << (cstate)))) |
228 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); | 218 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); |
229 | 219 | ||
@@ -259,7 +249,7 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) | |||
259 | */ | 249 | */ |
260 | static int intel_idle_probe(void) | 250 | static int intel_idle_probe(void) |
261 | { | 251 | { |
262 | unsigned int eax, ebx, ecx, edx; | 252 | unsigned int eax, ebx, ecx; |
263 | 253 | ||
264 | if (max_cstate == 0) { | 254 | if (max_cstate == 0) { |
265 | pr_debug(PREFIX "disabled\n"); | 255 | pr_debug(PREFIX "disabled\n"); |
@@ -275,20 +265,14 @@ static int intel_idle_probe(void) | |||
275 | if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) | 265 | if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) |
276 | return -ENODEV; | 266 | return -ENODEV; |
277 | 267 | ||
278 | cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx); | 268 | cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates); |
279 | 269 | ||
280 | if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || | 270 | if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || |
281 | !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) | 271 | !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) |
282 | return -ENODEV; | 272 | return -ENODEV; |
283 | #ifdef DEBUG | ||
284 | if (substates == 0) /* can over-ride via modparam */ | ||
285 | #endif | ||
286 | substates = edx; | ||
287 | 273 | ||
288 | pr_debug(PREFIX "MWAIT substates: 0x%x\n", substates); | 274 | pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); |
289 | 275 | ||
290 | if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ | ||
291 | lapic_timer_reliable_states = 0xFFFFFFFF; | ||
292 | 276 | ||
293 | if (boot_cpu_data.x86 != 6) /* family 6 */ | 277 | if (boot_cpu_data.x86 != 6) /* family 6 */ |
294 | return -ENODEV; | 278 | return -ENODEV; |
@@ -299,23 +283,21 @@ static int intel_idle_probe(void) | |||
299 | case 0x1E: /* Core i7 and i5 Processor - Lynnfield Jasper Forest */ | 283 | case 0x1E: /* Core i7 and i5 Processor - Lynnfield Jasper Forest */ |
300 | case 0x1F: /* Core i7 and i5 Processor - Nehalem */ | 284 | case 0x1F: /* Core i7 and i5 Processor - Nehalem */ |
301 | case 0x2E: /* Nehalem-EX Xeon */ | 285 | case 0x2E: /* Nehalem-EX Xeon */ |
302 | lapic_timer_reliable_states = (1 << 1); /* C1 */ | 286 | case 0x2F: /* Westmere-EX Xeon */ |
303 | |||
304 | case 0x25: /* Westmere */ | 287 | case 0x25: /* Westmere */ |
305 | case 0x2C: /* Westmere */ | 288 | case 0x2C: /* Westmere */ |
306 | cpuidle_state_table = nehalem_cstates; | 289 | cpuidle_state_table = nehalem_cstates; |
307 | choose_substate = choose_tunable_substate; | ||
308 | break; | 290 | break; |
309 | 291 | ||
310 | case 0x1C: /* 28 - Atom Processor */ | 292 | case 0x1C: /* 28 - Atom Processor */ |
311 | lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */ | 293 | case 0x26: /* 38 - Lincroft Atom Processor */ |
312 | cpuidle_state_table = atom_cstates; | 294 | cpuidle_state_table = atom_cstates; |
313 | choose_substate = choose_zero_substate; | ||
314 | break; | 295 | break; |
315 | #ifdef FUTURE_USE | 296 | |
316 | case 0x17: /* 23 - Core 2 Duo */ | 297 | case 0x2A: /* SNB */ |
317 | lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */ | 298 | case 0x2D: /* SNB Xeon */ |
318 | #endif | 299 | cpuidle_state_table = snb_cstates; |
300 | break; | ||
319 | 301 | ||
320 | default: | 302 | default: |
321 | pr_debug(PREFIX "does not run on family %d model %d\n", | 303 | pr_debug(PREFIX "does not run on family %d model %d\n", |
@@ -323,6 +305,9 @@ static int intel_idle_probe(void) | |||
323 | return -ENODEV; | 305 | return -ENODEV; |
324 | } | 306 | } |
325 | 307 | ||
308 | if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ | ||
309 | lapic_timer_reliable_states = 0xFFFFFFFF; | ||
310 | |||
326 | pr_debug(PREFIX "v" INTEL_IDLE_VERSION | 311 | pr_debug(PREFIX "v" INTEL_IDLE_VERSION |
327 | " model 0x%X\n", boot_cpu_data.x86_model); | 312 | " model 0x%X\n", boot_cpu_data.x86_model); |
328 | 313 | ||
@@ -376,7 +361,7 @@ static int intel_idle_cpuidle_devices_init(void) | |||
376 | } | 361 | } |
377 | 362 | ||
378 | /* does the state exist in CPUID.MWAIT? */ | 363 | /* does the state exist in CPUID.MWAIT? */ |
379 | num_substates = (substates >> ((cstate) * 4)) | 364 | num_substates = (mwait_substates >> ((cstate) * 4)) |
380 | & MWAIT_SUBSTATE_MASK; | 365 | & MWAIT_SUBSTATE_MASK; |
381 | if (num_substates == 0) | 366 | if (num_substates == 0) |
382 | continue; | 367 | continue; |
@@ -450,11 +435,7 @@ static void __exit intel_idle_exit(void) | |||
450 | module_init(intel_idle_init); | 435 | module_init(intel_idle_init); |
451 | module_exit(intel_idle_exit); | 436 | module_exit(intel_idle_exit); |
452 | 437 | ||
453 | module_param(power_policy, int, 0644); | ||
454 | module_param(max_cstate, int, 0444); | 438 | module_param(max_cstate, int, 0444); |
455 | #ifdef DEBUG | ||
456 | module_param(substates, int, 0444); | ||
457 | #endif | ||
458 | 439 | ||
459 | MODULE_AUTHOR("Len Brown <len.brown@intel.com>"); | 440 | MODULE_AUTHOR("Len Brown <len.brown@intel.com>"); |
460 | MODULE_DESCRIPTION("Cpuidle driver for Intel Hardware v" INTEL_IDLE_VERSION); | 441 | MODULE_DESCRIPTION("Cpuidle driver for Intel Hardware v" INTEL_IDLE_VERSION); |