diff options
Diffstat (limited to 'drivers/idle/intel_idle.c')
| -rw-r--r-- | drivers/idle/intel_idle.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 1fa091e0569..4a5c4a44ffb 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 |
| @@ -281,6 +288,15 @@ static struct notifier_block setup_broadcast_notifier = { | |||
| 281 | .notifier_call = setup_broadcast_cpuhp_notify, | 288 | .notifier_call = setup_broadcast_cpuhp_notify, |
| 282 | }; | 289 | }; |
| 283 | 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 | |||
| 284 | /* | 300 | /* |
| 285 | * intel_idle_probe() | 301 | * intel_idle_probe() |
| 286 | */ | 302 | */ |
| @@ -324,11 +340,17 @@ static int intel_idle_probe(void) | |||
| 324 | case 0x25: /* Westmere */ | 340 | case 0x25: /* Westmere */ |
| 325 | case 0x2C: /* Westmere */ | 341 | case 0x2C: /* Westmere */ |
| 326 | 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); | ||
| 327 | break; | 345 | break; |
| 328 | 346 | ||
| 329 | case 0x1C: /* 28 - Atom Processor */ | 347 | case 0x1C: /* 28 - Atom Processor */ |
| 348 | cpuidle_state_table = atom_cstates; | ||
| 349 | break; | ||
| 350 | |||
| 330 | case 0x26: /* 38 - Lincroft Atom Processor */ | 351 | case 0x26: /* 38 - Lincroft Atom Processor */ |
| 331 | cpuidle_state_table = atom_cstates; | 352 | cpuidle_state_table = atom_cstates; |
| 353 | auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE; | ||
| 332 | break; | 354 | break; |
| 333 | 355 | ||
| 334 | case 0x2A: /* SNB */ | 356 | case 0x2A: /* SNB */ |
| @@ -436,6 +458,8 @@ static int intel_idle_cpuidle_devices_init(void) | |||
| 436 | return -EIO; | 458 | return -EIO; |
| 437 | } | 459 | } |
| 438 | } | 460 | } |
| 461 | if (auto_demotion_disable_flags) | ||
| 462 | smp_call_function(auto_demotion_disable, NULL, 1); | ||
| 439 | 463 | ||
| 440 | return 0; | 464 | return 0; |
| 441 | } | 465 | } |
