aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/idle
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2012-01-25 18:09:07 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2012-01-26 19:48:11 -0500
commitb66b8b9a4a79087dde1b358a016e5c8739ccf186 (patch)
treea78f20cafa051b74241c54eb09a4078148713d6d /drivers/idle
parent3bd391f056df61e928de1680ff4a3e7e07e5b399 (diff)
intel-idle: convert to x86_cpu_id auto probing
With this it should be automatically loaded on suitable systems by udev. The old switch () is replaced with a table based approach, this also cleans up the code. Cc: Len Brown <lenb@kernel.org> Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Thomas Renninger <trenn@suse.de> Acked-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/idle')
-rw-r--r--drivers/idle/intel_idle.c116
1 files changed, 66 insertions, 50 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 20bce51c2e8..ef6a409ff1a 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 <linux/module.h> 64#include <linux/module.h>
65#include <asm/cpu_device_id.h>
65#include <asm/mwait.h> 66#include <asm/mwait.h>
66#include <asm/msr.h> 67#include <asm/msr.h>
67 68
@@ -81,6 +82,17 @@ static unsigned int mwait_substates;
81/* Reliable LAPIC Timer States, bit 1 for C1 etc. */ 82/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
82static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ 83static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
83 84
85struct idle_cpu {
86 struct cpuidle_state *state_table;
87
88 /*
89 * Hardware C-state auto-demotion may not always be optimal.
90 * Indicate which enable bits to clear here.
91 */
92 unsigned long auto_demotion_disable_flags;
93};
94
95static const struct idle_cpu *icpu;
84static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; 96static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
85static int intel_idle(struct cpuidle_device *dev, 97static int intel_idle(struct cpuidle_device *dev,
86 struct cpuidle_driver *drv, int index); 98 struct cpuidle_driver *drv, int index);
@@ -88,12 +100,6 @@ static int intel_idle(struct cpuidle_device *dev,
88static struct cpuidle_state *cpuidle_state_table; 100static struct cpuidle_state *cpuidle_state_table;
89 101
90/* 102/*
91 * Hardware C-state auto-demotion may not always be optimal.
92 * Indicate which enable bits to clear here.
93 */
94static unsigned long long auto_demotion_disable_flags;
95
96/*
97 * Set this flag for states where the HW flushes the TLB for us 103 * Set this flag for states where the HW flushes the TLB for us
98 * and so we don't need cross-calls to keep it consistent. 104 * and so we don't need cross-calls to keep it consistent.
99 * If this flag is set, SW flushes the TLB, so even if the 105 * If this flag is set, SW flushes the TLB, so even if the
@@ -319,27 +325,72 @@ static void auto_demotion_disable(void *dummy)
319 unsigned long long msr_bits; 325 unsigned long long msr_bits;
320 326
321 rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); 327 rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
322 msr_bits &= ~auto_demotion_disable_flags; 328 msr_bits &= ~(icpu->auto_demotion_disable_flags);
323 wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); 329 wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
324} 330}
325 331
332static const struct idle_cpu idle_cpu_nehalem = {
333 .state_table = nehalem_cstates,
334};
335
336static const struct idle_cpu idle_cpu_westmere = {
337 .state_table = nehalem_cstates,
338 .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
339};
340
341static const struct idle_cpu idle_cpu_atom = {
342 .state_table = atom_cstates,
343};
344
345static const struct idle_cpu idle_cpu_lincroft = {
346 .state_table = atom_cstates,
347 .auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE,
348};
349
350static const struct idle_cpu idle_cpu_snb = {
351 .state_table = snb_cstates,
352};
353
354#define ICPU(model, cpu) \
355 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
356
357static const struct x86_cpu_id intel_idle_ids[] = {
358 ICPU(0x1a, idle_cpu_nehalem),
359 ICPU(0x1e, idle_cpu_nehalem),
360 ICPU(0x1f, idle_cpu_nehalem),
361 ICPU(0x25, idle_cpu_westmere),
362 ICPU(0x2c, idle_cpu_westmere),
363 ICPU(0x2f, idle_cpu_westmere),
364 ICPU(0x1c, idle_cpu_atom),
365 ICPU(0x26, idle_cpu_lincroft),
366 ICPU(0x2f, idle_cpu_westmere),
367 ICPU(0x2a, idle_cpu_snb),
368 ICPU(0x2d, idle_cpu_snb),
369 {}
370};
371MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
372
326/* 373/*
327 * intel_idle_probe() 374 * intel_idle_probe()
328 */ 375 */
329static int intel_idle_probe(void) 376static int intel_idle_probe(void)
330{ 377{
331 unsigned int eax, ebx, ecx; 378 unsigned int eax, ebx, ecx;
379 const struct x86_cpu_id *id;
332 380
333 if (max_cstate == 0) { 381 if (max_cstate == 0) {
334 pr_debug(PREFIX "disabled\n"); 382 pr_debug(PREFIX "disabled\n");
335 return -EPERM; 383 return -EPERM;
336 } 384 }
337 385
338 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 386 id = x86_match_cpu(intel_idle_ids);
339 return -ENODEV; 387 if (!id) {
340 388 if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
341 if (!boot_cpu_has(X86_FEATURE_MWAIT)) 389 boot_cpu_data.x86 == 6)
390 pr_debug(PREFIX "does not run on family %d model %d\n",
391 boot_cpu_data.x86, boot_cpu_data.x86_model);
342 return -ENODEV; 392 return -ENODEV;
393 }
343 394
344 if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) 395 if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
345 return -ENODEV; 396 return -ENODEV;
@@ -353,43 +404,8 @@ static int intel_idle_probe(void)
353 404
354 pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); 405 pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
355 406
356 407 icpu = (const struct idle_cpu *)id->driver_data;
357 if (boot_cpu_data.x86 != 6) /* family 6 */ 408 cpuidle_state_table = icpu->state_table;
358 return -ENODEV;
359
360 switch (boot_cpu_data.x86_model) {
361
362 case 0x1A: /* Core i7, Xeon 5500 series */
363 case 0x1E: /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
364 case 0x1F: /* Core i7 and i5 Processor - Nehalem */
365 case 0x2E: /* Nehalem-EX Xeon */
366 case 0x2F: /* Westmere-EX Xeon */
367 case 0x25: /* Westmere */
368 case 0x2C: /* Westmere */
369 cpuidle_state_table = nehalem_cstates;
370 auto_demotion_disable_flags =
371 (NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE);
372 break;
373
374 case 0x1C: /* 28 - Atom Processor */
375 cpuidle_state_table = atom_cstates;
376 break;
377
378 case 0x26: /* 38 - Lincroft Atom Processor */
379 cpuidle_state_table = atom_cstates;
380 auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE;
381 break;
382
383 case 0x2A: /* SNB */
384 case 0x2D: /* SNB Xeon */
385 cpuidle_state_table = snb_cstates;
386 break;
387
388 default:
389 pr_debug(PREFIX "does not run on family %d model %d\n",
390 boot_cpu_data.x86, boot_cpu_data.x86_model);
391 return -ENODEV;
392 }
393 409
394 if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ 410 if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
395 lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; 411 lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
@@ -470,7 +486,7 @@ static int intel_idle_cpuidle_driver_init(void)
470 drv->state_count += 1; 486 drv->state_count += 1;
471 } 487 }
472 488
473 if (auto_demotion_disable_flags) 489 if (icpu->auto_demotion_disable_flags)
474 on_each_cpu(auto_demotion_disable, NULL, 1); 490 on_each_cpu(auto_demotion_disable, NULL, 1);
475 491
476 return 0; 492 return 0;
@@ -522,7 +538,7 @@ int intel_idle_cpu_init(int cpu)
522 return -EIO; 538 return -EIO;
523 } 539 }
524 540
525 if (auto_demotion_disable_flags) 541 if (icpu->auto_demotion_disable_flags)
526 smp_call_function_single(cpu, auto_demotion_disable, NULL, 1); 542 smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
527 543
528 return 0; 544 return 0;