diff options
author | Andi Kleen <ak@linux.intel.com> | 2012-01-25 18:09:07 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2012-01-26 19:48:11 -0500 |
commit | b66b8b9a4a79087dde1b358a016e5c8739ccf186 (patch) | |
tree | a78f20cafa051b74241c54eb09a4078148713d6d /drivers/idle/intel_idle.c | |
parent | 3bd391f056df61e928de1680ff4a3e7e07e5b399 (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/intel_idle.c')
-rw-r--r-- | drivers/idle/intel_idle.c | 116 |
1 files changed, 66 insertions, 50 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 20bce51c2e82..ef6a409ff1a9 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. */ |
82 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ | 83 | static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ |
83 | 84 | ||
85 | struct 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 | |||
95 | static const struct idle_cpu *icpu; | ||
84 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; | 96 | static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; |
85 | static int intel_idle(struct cpuidle_device *dev, | 97 | static 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, | |||
88 | static struct cpuidle_state *cpuidle_state_table; | 100 | static 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 | */ | ||
94 | static 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 | ||
332 | static const struct idle_cpu idle_cpu_nehalem = { | ||
333 | .state_table = nehalem_cstates, | ||
334 | }; | ||
335 | |||
336 | static 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 | |||
341 | static const struct idle_cpu idle_cpu_atom = { | ||
342 | .state_table = atom_cstates, | ||
343 | }; | ||
344 | |||
345 | static const struct idle_cpu idle_cpu_lincroft = { | ||
346 | .state_table = atom_cstates, | ||
347 | .auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE, | ||
348 | }; | ||
349 | |||
350 | static 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 | |||
357 | static 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 | }; | ||
371 | MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids); | ||
372 | |||
326 | /* | 373 | /* |
327 | * intel_idle_probe() | 374 | * intel_idle_probe() |
328 | */ | 375 | */ |
329 | static int intel_idle_probe(void) | 376 | static 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; |