diff options
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r-- | drivers/idle/intel_idle.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 1fa091e0569..a46dddf6107 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -62,6 +62,7 @@ #include <linux/notifier.h> #include <linux/cpu.h> #include <asm/mwait.h> +#include <asm/msr.h> #define INTEL_IDLE_VERSION "0.4" #define PREFIX "intel_idle: " @@ -85,6 +86,12 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); static struct cpuidle_state *cpuidle_state_table; /* + * Hardware C-state auto-demotion may not always be optimal. + * Indicate which enable bits to clear here. + */ +static unsigned long long auto_demotion_disable_flags; + +/* * Set this flag for states where the HW flushes the TLB for us * and so we don't need cross-calls to keep it consistent. * If this flag is set, SW flushes the TLB, so even if the @@ -100,7 +107,7 @@ static struct cpuidle_state *cpuidle_state_table; static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C0 */ }, { /* MWAIT C1 */ - .name = "NHM-C1", + .name = "C1-NHM", .desc = "MWAIT 0x00", .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -108,7 +115,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 6, .enter = &intel_idle }, { /* MWAIT C2 */ - .name = "NHM-C3", + .name = "C3-NHM", .desc = "MWAIT 0x10", .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -116,7 +123,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 80, .enter = &intel_idle }, { /* MWAIT C3 */ - .name = "NHM-C6", + .name = "C6-NHM", .desc = "MWAIT 0x20", .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -128,7 +135,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C0 */ }, { /* MWAIT C1 */ - .name = "SNB-C1", + .name = "C1-SNB", .desc = "MWAIT 0x00", .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -136,7 +143,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 1, .enter = &intel_idle }, { /* MWAIT C2 */ - .name = "SNB-C3", + .name = "C3-SNB", .desc = "MWAIT 0x10", .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -144,7 +151,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 211, .enter = &intel_idle }, { /* MWAIT C3 */ - .name = "SNB-C6", + .name = "C6-SNB", .desc = "MWAIT 0x20", .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -152,7 +159,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 345, .enter = &intel_idle }, { /* MWAIT C4 */ - .name = "SNB-C7", + .name = "C7-SNB", .desc = "MWAIT 0x30", .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -164,7 +171,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C0 */ }, { /* MWAIT C1 */ - .name = "ATM-C1", + .name = "C1-ATM", .desc = "MWAIT 0x00", .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -172,7 +179,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 4, .enter = &intel_idle }, { /* MWAIT C2 */ - .name = "ATM-C2", + .name = "C2-ATM", .desc = "MWAIT 0x10", .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -181,7 +188,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .enter = &intel_idle }, { /* MWAIT C3 */ }, { /* MWAIT C4 */ - .name = "ATM-C4", + .name = "C4-ATM", .desc = "MWAIT 0x30", .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -190,7 +197,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .enter = &intel_idle }, { /* MWAIT C5 */ }, { /* MWAIT C6 */ - .name = "ATM-C6", + .name = "C6-ATM", .desc = "MWAIT 0x52", .driver_data = (void *) 0x52, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -281,6 +288,15 @@ static struct notifier_block setup_broadcast_notifier = { .notifier_call = setup_broadcast_cpuhp_notify, }; +static void auto_demotion_disable(void *dummy) +{ + unsigned long long msr_bits; + + rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); + msr_bits &= ~auto_demotion_disable_flags; + wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); +} + /* * intel_idle_probe() */ @@ -324,11 +340,17 @@ static int intel_idle_probe(void) case 0x25: /* Westmere */ case 0x2C: /* Westmere */ cpuidle_state_table = nehalem_cstates; + auto_demotion_disable_flags = + (NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE); break; case 0x1C: /* 28 - Atom Processor */ + cpuidle_state_table = atom_cstates; + break; + case 0x26: /* 38 - Lincroft Atom Processor */ cpuidle_state_table = atom_cstates; + auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE; break; case 0x2A: /* SNB */ @@ -436,6 +458,8 @@ static int intel_idle_cpuidle_devices_init(void) return -EIO; } } + if (auto_demotion_disable_flags) + smp_call_function(auto_demotion_disable, NULL, 1); return 0; } |