summaryrefslogtreecommitdiffstats
path: root/drivers/idle/intel_idle.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-13 09:50:21 +0200
committerIngo Molnar <mingo@kernel.org>2012-04-13 09:50:21 +0200
commit659c36fcda403013a01b85da07cf2d9711e6d6c7 (patch)
treeece2e7d0e2c19ea5a3d0ec172ad0b81a8a19021d /drivers/idle/intel_idle.c
parent9521d830b6341d1887dcfc2aebde23fbfa5f1473 (diff)
parent5a7ed29c7572d00a75e8c4529e30c5ac2ef82271 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Fixes and improvements for perf/core: . Overhaul the tools/ makefiles, gluing them to the top level Makefile, from Borislav Petkov. . Move the UI files from tools/perf/util/ui/ to tools/perf/ui/. Also move the GTK+ browser to tools/perf/ui/gtk/, from Namhyung Kim. . Only fallback to sw cycles counter on ENOENT for the hw cycles, from Robert Richter . Trivial fixes from Robert Richter . Handle the autogenerated bison/flex files better, from Namhyung and Jiri Olsa. . Navigate jump instructions in the annotate browser, just press enter or ->, still needs support for a jump navigation history, i.e. to go back. . Search string in the annotate browser: same keys as vim: / forward n next backward/forward ? backward . Clarify number of events/samples in the report header, from Ashay Rane Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r--drivers/idle/intel_idle.c120
1 files changed, 66 insertions, 54 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 54ab97bae04..d0f59c3f87e 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 <linux/module.h>
+#include <asm/cpu_device_id.h>
#include <asm/mwait.h>
#include <asm/msr.h>
@@ -81,6 +82,17 @@ static unsigned int mwait_substates;
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
+struct idle_cpu {
+ struct cpuidle_state *state_table;
+
+ /*
+ * Hardware C-state auto-demotion may not always be optimal.
+ * Indicate which enable bits to clear here.
+ */
+ unsigned long auto_demotion_disable_flags;
+};
+
+static const struct idle_cpu *icpu;
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
static int intel_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
@@ -88,12 +100,6 @@ static int intel_idle(struct cpuidle_device *dev,
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
@@ -319,27 +325,68 @@ 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;
+ msr_bits &= ~(icpu->auto_demotion_disable_flags);
wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
}
+static const struct idle_cpu idle_cpu_nehalem = {
+ .state_table = nehalem_cstates,
+ .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
+};
+
+static const struct idle_cpu idle_cpu_atom = {
+ .state_table = atom_cstates,
+};
+
+static const struct idle_cpu idle_cpu_lincroft = {
+ .state_table = atom_cstates,
+ .auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE,
+};
+
+static const struct idle_cpu idle_cpu_snb = {
+ .state_table = snb_cstates,
+};
+
+#define ICPU(model, cpu) \
+ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
+
+static const struct x86_cpu_id intel_idle_ids[] = {
+ ICPU(0x1a, idle_cpu_nehalem),
+ ICPU(0x1e, idle_cpu_nehalem),
+ ICPU(0x1f, idle_cpu_nehalem),
+ ICPU(0x25, idle_cpu_nehalem),
+ ICPU(0x2c, idle_cpu_nehalem),
+ ICPU(0x2e, idle_cpu_nehalem),
+ ICPU(0x1c, idle_cpu_atom),
+ ICPU(0x26, idle_cpu_lincroft),
+ ICPU(0x2f, idle_cpu_nehalem),
+ ICPU(0x2a, idle_cpu_snb),
+ ICPU(0x2d, idle_cpu_snb),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
+
/*
* intel_idle_probe()
*/
static int intel_idle_probe(void)
{
unsigned int eax, ebx, ecx;
+ const struct x86_cpu_id *id;
if (max_cstate == 0) {
pr_debug(PREFIX "disabled\n");
return -EPERM;
}
- if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
- return -ENODEV;
-
- if (!boot_cpu_has(X86_FEATURE_MWAIT))
+ id = x86_match_cpu(intel_idle_ids);
+ if (!id) {
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+ boot_cpu_data.x86 == 6)
+ pr_debug(PREFIX "does not run on family %d model %d\n",
+ boot_cpu_data.x86, boot_cpu_data.x86_model);
return -ENODEV;
+ }
if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
return -ENODEV;
@@ -353,43 +400,8 @@ static int intel_idle_probe(void)
pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
-
- if (boot_cpu_data.x86 != 6) /* family 6 */
- return -ENODEV;
-
- switch (boot_cpu_data.x86_model) {
-
- case 0x1A: /* Core i7, Xeon 5500 series */
- case 0x1E: /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
- case 0x1F: /* Core i7 and i5 Processor - Nehalem */
- case 0x2E: /* Nehalem-EX Xeon */
- case 0x2F: /* Westmere-EX Xeon */
- 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 */
- case 0x2D: /* SNB Xeon */
- cpuidle_state_table = snb_cstates;
- break;
-
- default:
- pr_debug(PREFIX "does not run on family %d model %d\n",
- boot_cpu_data.x86, boot_cpu_data.x86_model);
- return -ENODEV;
- }
+ icpu = (const struct idle_cpu *)id->driver_data;
+ cpuidle_state_table = icpu->state_table;
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
@@ -470,7 +482,7 @@ static int intel_idle_cpuidle_driver_init(void)
drv->state_count += 1;
}
- if (auto_demotion_disable_flags)
+ if (icpu->auto_demotion_disable_flags)
on_each_cpu(auto_demotion_disable, NULL, 1);
return 0;
@@ -495,8 +507,7 @@ int intel_idle_cpu_init(int cpu)
int num_substates;
if (cstate > max_cstate) {
- printk(PREFIX "max_cstate %d reached\n",
- max_cstate);
+ printk(PREFIX "max_cstate %d reached\n", max_cstate);
break;
}
@@ -512,8 +523,9 @@ int intel_idle_cpu_init(int cpu)
dev->states_usage[dev->state_count].driver_data =
(void *)get_driver_data(cstate);
- dev->state_count += 1;
- }
+ dev->state_count += 1;
+ }
+
dev->cpu = cpu;
if (cpuidle_register_device(dev)) {
@@ -522,7 +534,7 @@ int intel_idle_cpu_init(int cpu)
return -EIO;
}
- if (auto_demotion_disable_flags)
+ if (icpu->auto_demotion_disable_flags)
smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
return 0;