aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle/intel_idle.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r--drivers/idle/intel_idle.c32
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);
85static struct cpuidle_state *cpuidle_state_table; 86static 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 */
92static 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
266static int __cpuinit setup_broadcast_cpuhp_notify(struct notifier_block *n, 273static 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
284static struct notifier_block __cpuinitdata setup_broadcast_notifier = { 287static struct notifier_block setup_broadcast_notifier = {
285 .notifier_call = setup_broadcast_cpuhp_notify, 288 .notifier_call = setup_broadcast_cpuhp_notify,
286}; 289};
287 290
291static 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}