diff options
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r-- | drivers/idle/intel_idle.c | 32 |
1 files changed, 26 insertions, 6 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 7acb32e7f817..4a5c4a44ffb1 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <linux/notifier.h> | 62 | #include <linux/notifier.h> |
63 | #include <linux/cpu.h> | 63 | #include <linux/cpu.h> |
64 | #include <asm/mwait.h> | 64 | #include <asm/mwait.h> |
65 | #include <asm/msr.h> | ||
65 | 66 | ||
66 | #define INTEL_IDLE_VERSION "0.4" | 67 | #define INTEL_IDLE_VERSION "0.4" |
67 | #define PREFIX "intel_idle: " | 68 | #define PREFIX "intel_idle: " |
@@ -85,6 +86,12 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); | |||
85 | static struct cpuidle_state *cpuidle_state_table; | 86 | static struct cpuidle_state *cpuidle_state_table; |
86 | 87 | ||
87 | /* | 88 | /* |
89 | * Hardware C-state auto-demotion may not always be optimal. | ||
90 | * Indicate which enable bits to clear here. | ||
91 | */ | ||
92 | static unsigned long long auto_demotion_disable_flags; | ||
93 | |||
94 | /* | ||
88 | * Set this flag for states where the HW flushes the TLB for us | 95 | * Set this flag for states where the HW flushes the TLB for us |
89 | * and so we don't need cross-calls to keep it consistent. | 96 | * and so we don't need cross-calls to keep it consistent. |
90 | * If this flag is set, SW flushes the TLB, so even if the | 97 | * If this flag is set, SW flushes the TLB, so even if the |
@@ -263,7 +270,7 @@ static void __setup_broadcast_timer(void *arg) | |||
263 | clockevents_notify(reason, &cpu); | 270 | clockevents_notify(reason, &cpu); |
264 | } | 271 | } |
265 | 272 | ||
266 | static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n, | 273 | static int setup_broadcast_cpuhp_notify(struct notifier_block *n, |
267 | unsigned long action, void *hcpu) | 274 | unsigned long action, void *hcpu) |
268 | { | 275 | { |
269 | int hotcpu = (unsigned long)hcpu; | 276 | int hotcpu = (unsigned long)hcpu; |
@@ -273,18 +280,23 @@ static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n, | |||
273 | smp_call_function_single(hotcpu, __setup_broadcast_timer, | 280 | smp_call_function_single(hotcpu, __setup_broadcast_timer, |
274 | (void *)true, 1); | 281 | (void *)true, 1); |
275 | break; | 282 | break; |
276 | case CPU_DOWN_PREPARE: | ||
277 | smp_call_function_single(hotcpu, __setup_broadcast_timer, | ||
278 | (void *)false, 1); | ||
279 | break; | ||
280 | } | 283 | } |
281 | return NOTIFY_OK; | 284 | return NOTIFY_OK; |
282 | } | 285 | } |
283 | 286 | ||
284 | static struct notifier_block __cpuinitdata setup_broadcast_notifier = { | 287 | static struct notifier_block setup_broadcast_notifier = { |
285 | .notifier_call = setup_broadcast_cpuhp_notify, | 288 | .notifier_call = setup_broadcast_cpuhp_notify, |
286 | }; | 289 | }; |
287 | 290 | ||
291 | static void auto_demotion_disable(void *dummy) | ||
292 | { | ||
293 | unsigned long long msr_bits; | ||
294 | |||
295 | rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); | ||
296 | msr_bits &= ~auto_demotion_disable_flags; | ||
297 | wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); | ||
298 | } | ||
299 | |||
288 | /* | 300 | /* |
289 | * intel_idle_probe() | 301 | * intel_idle_probe() |
290 | */ | 302 | */ |
@@ -328,11 +340,17 @@ static int intel_idle_probe(void) | |||
328 | case 0x25: /* Westmere */ | 340 | case 0x25: /* Westmere */ |
329 | case 0x2C: /* Westmere */ | 341 | case 0x2C: /* Westmere */ |
330 | cpuidle_state_table = nehalem_cstates; | 342 | cpuidle_state_table = nehalem_cstates; |
343 | auto_demotion_disable_flags = | ||
344 | (NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE); | ||
331 | break; | 345 | break; |
332 | 346 | ||
333 | case 0x1C: /* 28 - Atom Processor */ | 347 | case 0x1C: /* 28 - Atom Processor */ |
348 | cpuidle_state_table = atom_cstates; | ||
349 | break; | ||
350 | |||
334 | case 0x26: /* 38 - Lincroft Atom Processor */ | 351 | case 0x26: /* 38 - Lincroft Atom Processor */ |
335 | cpuidle_state_table = atom_cstates; | 352 | cpuidle_state_table = atom_cstates; |
353 | auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE; | ||
336 | break; | 354 | break; |
337 | 355 | ||
338 | case 0x2A: /* SNB */ | 356 | case 0x2A: /* SNB */ |
@@ -440,6 +458,8 @@ static int intel_idle_cpuidle_devices_init(void) | |||
440 | return -EIO; | 458 | return -EIO; |
441 | } | 459 | } |
442 | } | 460 | } |
461 | if (auto_demotion_disable_flags) | ||
462 | smp_call_function(auto_demotion_disable, NULL, 1); | ||
443 | 463 | ||
444 | return 0; | 464 | return 0; |
445 | } | 465 | } |