diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-11 13:20:04 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-11 13:20:04 -0700 |
commit | eeb91e4f9d578a6a8cc25a9603d4d62f2ec00db5 (patch) | |
tree | 16301353dbdc0978ec9ab579168274dcfc8a7a0b /drivers/idle/intel_idle.c | |
parent | 40e9963e622cf28ecef258e3dddb04457b65681c (diff) | |
parent | 19ce7f3f31103d7a5b0e93ba9de3ebb4b9d66701 (diff) |
Merge tag 'pm+acpi-3.15-rc1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more ACPI and power management fixes and updates from Rafael Wysocki:
"This is PM and ACPI material that has emerged over the last two weeks
and one fix for a CPU hotplug regression introduced by the recent CPU
hotplug notifiers registration series.
Included are intel_idle and turbostat updates from Len Brown (these
have been in linux-next for quite some time), a new cpufreq driver for
powernv (that might spend some more time in linux-next, but BenH was
asking me so nicely to push it for 3.15 that I couldn't resist), some
cpufreq fixes and cleanups (including fixes for some silly breakage in
a couple of cpufreq drivers introduced during the 3.14 cycle),
assorted ACPI cleanups, wakeup framework documentation fixes, a new
sysfs attribute for cpuidle and a new command line argument for power
domains diagnostics.
Specifics:
- Fix for a recently introduced CPU hotplug regression in ARM KVM
from Ming Lei.
- Fixes for breakage in the at32ap, loongson2_cpufreq, and unicore32
cpufreq drivers introduced during the 3.14 cycle (-stable material)
from Chen Gang and Viresh Kumar.
- New powernv cpufreq driver from Vaidyanathan Srinivasan, with bits
from Gautham R Shenoy and Srivatsa S Bhat.
- Exynos cpufreq driver fix preventing it from being included into
multiplatform builds that aren't supported by it from Sachin Kamat.
- cpufreq cleanups related to the usage of the driver_data field in
struct cpufreq_frequency_table from Viresh Kumar.
- cpufreq ppc driver cleanup from Sachin Kamat.
- Intel BayTrail support for intel_idle and ACPI idle from Len Brown.
- Intel CPU model 54 (Atom N2000 series) support for intel_idle from
Jan Kiszka.
- intel_idle fix for Intel Ivy Town residency targets from Len Brown.
- turbostat updates (Intel Broadwell support and output cleanups)
from Len Brown.
- New cpuidle sysfs attribute for exporting C-states' target
residency information to user space from Daniel Lezcano.
- New kernel command line argument to prevent power domains enabled
by the bootloader from being turned off even if they are not in use
(for diagnostics purposes) from Tushar Behera.
- Fixes for wakeup sysfs attributes documentation from Geert
Uytterhoeven.
- New ACPI video blacklist entry for ThinkPad Helix from Stephen
Chandler Paul.
- Assorted ACPI cleanups and a Kconfig help update from Jonghwan
Choi, Zhihui Zhang, Hanjun Guo"
* tag 'pm+acpi-3.15-rc1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (28 commits)
ACPI: Update the ACPI spec information in Kconfig
arm, kvm: fix double lock on cpu_add_remove_lock
cpuidle: sysfs: Export target residency information
cpufreq: ppc: Remove duplicate inclusion of fsl_soc.h
cpufreq: create another field .flags in cpufreq_frequency_table
cpufreq: use kzalloc() to allocate memory for cpufreq_frequency_table
cpufreq: don't print value of .driver_data from core
cpufreq: ia64: don't set .driver_data to index
cpufreq: powernv: Select CPUFreq related Kconfig options for powernv
cpufreq: powernv: Use cpufreq_frequency_table.driver_data to store pstate ids
cpufreq: powernv: cpufreq driver for powernv platform
cpufreq: at32ap: don't declare local variable as static
cpufreq: loongson2_cpufreq: don't declare local variable as static
cpufreq: unicore32: fix typo issue for 'clk'
cpufreq: exynos: Disable on multiplatform build
PM / wakeup: Correct presence vs. emptiness of wakeup_* attributes
PM / domains: Add pd_ignore_unused to keep power domains enabled
ACPI / dock: Drop dock_device_ids[] table
ACPI / video: Favor native backlight interface for ThinkPad Helix
ACPI / thermal: Fix wrong variable usage in debug statement
...
Diffstat (limited to 'drivers/idle/intel_idle.c')
-rw-r--r-- | drivers/idle/intel_idle.c | 204 |
1 files changed, 198 insertions, 6 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 51493ed4643b..a43220c2e3d9 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -196,6 +196,53 @@ static struct cpuidle_state snb_cstates[] = { .enter = NULL } }; +static struct cpuidle_state byt_cstates[] = { + { + .name = "C1-BYT", + .desc = "MWAIT 0x00", + .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 1, + .enter = &intel_idle }, + { + .name = "C1E-BYT", + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 15, + .target_residency = 30, + .enter = &intel_idle }, + { + .name = "C6N-BYT", + .desc = "MWAIT 0x58", + .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 40, + .target_residency = 275, + .enter = &intel_idle }, + { + .name = "C6S-BYT", + .desc = "MWAIT 0x52", + .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 140, + .target_residency = 560, + .enter = &intel_idle }, + { + .name = "C7-BYT", + .desc = "MWAIT 0x60", + .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 1200, + .target_residency = 1500, + .enter = &intel_idle }, + { + .name = "C7S-BYT", + .desc = "MWAIT 0x64", + .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 10000, + .target_residency = 20000, + .enter = &intel_idle }, + { + .enter = NULL } +}; + static struct cpuidle_state ivb_cstates[] = { { .name = "C1-IVB", @@ -236,6 +283,105 @@ static struct cpuidle_state ivb_cstates[] = { .enter = NULL } }; +static struct cpuidle_state ivt_cstates[] = { + { + .name = "C1-IVT", + .desc = "MWAIT 0x00", + .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 1, + .enter = &intel_idle }, + { + .name = "C1E-IVT", + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 10, + .target_residency = 80, + .enter = &intel_idle }, + { + .name = "C3-IVT", + .desc = "MWAIT 0x10", + .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 59, + .target_residency = 156, + .enter = &intel_idle }, + { + .name = "C6-IVT", + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 82, + .target_residency = 300, + .enter = &intel_idle }, + { + .enter = NULL } +}; + +static struct cpuidle_state ivt_cstates_4s[] = { + { + .name = "C1-IVT-4S", + .desc = "MWAIT 0x00", + .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 1, + .enter = &intel_idle }, + { + .name = "C1E-IVT-4S", + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 10, + .target_residency = 250, + .enter = &intel_idle }, + { + .name = "C3-IVT-4S", + .desc = "MWAIT 0x10", + .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 59, + .target_residency = 300, + .enter = &intel_idle }, + { + .name = "C6-IVT-4S", + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 84, + .target_residency = 400, + .enter = &intel_idle }, + { + .enter = NULL } +}; + +static struct cpuidle_state ivt_cstates_8s[] = { + { + .name = "C1-IVT-8S", + .desc = "MWAIT 0x00", + .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 1, + .target_residency = 1, + .enter = &intel_idle }, + { + .name = "C1E-IVT-8S", + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID, + .exit_latency = 10, + .target_residency = 500, + .enter = &intel_idle }, + { + .name = "C3-IVT-8S", + .desc = "MWAIT 0x10", + .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 59, + .target_residency = 600, + .enter = &intel_idle }, + { + .name = "C6-IVT-8S", + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, + .exit_latency = 88, + .target_residency = 700, + .enter = &intel_idle }, + { + .enter = NULL } +}; + static struct cpuidle_state hsw_cstates[] = { { .name = "C1-HSW", @@ -464,11 +610,21 @@ static const struct idle_cpu idle_cpu_snb = { .disable_promotion_to_c1e = true, }; +static const struct idle_cpu idle_cpu_byt = { + .state_table = byt_cstates, + .disable_promotion_to_c1e = true, +}; + static const struct idle_cpu idle_cpu_ivb = { .state_table = ivb_cstates, .disable_promotion_to_c1e = true, }; +static const struct idle_cpu idle_cpu_ivt = { + .state_table = ivt_cstates, + .disable_promotion_to_c1e = true, +}; + static const struct idle_cpu idle_cpu_hsw = { .state_table = hsw_cstates, .disable_promotion_to_c1e = true, @@ -494,8 +650,10 @@ static const struct x86_cpu_id intel_idle_ids[] = { ICPU(0x2f, idle_cpu_nehalem), ICPU(0x2a, idle_cpu_snb), ICPU(0x2d, idle_cpu_snb), + ICPU(0x36, idle_cpu_atom), + ICPU(0x37, idle_cpu_byt), ICPU(0x3a, idle_cpu_ivb), - ICPU(0x3e, idle_cpu_ivb), + ICPU(0x3e, idle_cpu_ivt), ICPU(0x3c, idle_cpu_hsw), ICPU(0x3f, idle_cpu_hsw), ICPU(0x45, idle_cpu_hsw), @@ -572,6 +730,39 @@ static void intel_idle_cpuidle_devices_uninit(void) free_percpu(intel_idle_cpuidle_devices); return; } + +/* + * intel_idle_state_table_update() + * + * Update the default state_table for this CPU-id + * + * Currently used to access tuned IVT multi-socket targets + * Assumption: num_sockets == (max_package_num + 1) + */ +void intel_idle_state_table_update(void) +{ + /* IVT uses a different table for 1-2, 3-4, and > 4 sockets */ + if (boot_cpu_data.x86_model == 0x3e) { /* IVT */ + int cpu, package_num, num_sockets = 1; + + for_each_online_cpu(cpu) { + package_num = topology_physical_package_id(cpu); + if (package_num + 1 > num_sockets) { + num_sockets = package_num + 1; + + if (num_sockets > 4) + cpuidle_state_table = ivt_cstates_8s; + return; + } + } + + if (num_sockets > 2) + cpuidle_state_table = ivt_cstates_4s; + /* else, 1 and 2 socket systems use default ivt_cstates */ + } + return; +} + /* * intel_idle_cpuidle_driver_init() * allocate, initialize cpuidle_states @@ -581,10 +772,12 @@ static int __init intel_idle_cpuidle_driver_init(void) int cstate; struct cpuidle_driver *drv = &intel_idle_driver; + intel_idle_state_table_update(); + drv->state_count = 1; for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { - int num_substates, mwait_hint, mwait_cstate, mwait_substate; + int num_substates, mwait_hint, mwait_cstate; if (cpuidle_state_table[cstate].enter == NULL) break; @@ -597,14 +790,13 @@ static int __init intel_idle_cpuidle_driver_init(void) mwait_hint = flg2MWAIT(cpuidle_state_table[cstate].flags); mwait_cstate = MWAIT_HINT2CSTATE(mwait_hint); - mwait_substate = MWAIT_HINT2SUBSTATE(mwait_hint); - /* does the state exist in CPUID.MWAIT? */ + /* number of sub-states for this state in CPUID.MWAIT */ num_substates = (mwait_substates >> ((mwait_cstate + 1) * 4)) & MWAIT_SUBSTATE_MASK; - /* if sub-state in table is not enumerated by CPUID */ - if ((mwait_substate + 1) > num_substates) + /* if NO sub-states for this state in CPUID, skip it */ + if (num_substates == 0) continue; if (((mwait_cstate + 1) > 2) && |