Commit 32e95180 authored by Len Brown's avatar Len Brown

intel_idle: export both C1 and C1E

Here we disable HW promotion of C1 to C1E
and export both C1 and C1E and distinct C-states.

This allows a cpuidle governor to choose a lower latency
C-state than C1E when necessary to satisfy performance
and QOS constraints -- and still save power versus polling.
This also corrects the erroneous latency previously reported
for C1E -- it is 10usec, not 1usec.

Note that if you use "intel_idle.max_cstate=N",
then you must increment N by 1 to get the same behavior
after this change.
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent e022e7eb
...@@ -90,6 +90,7 @@ struct idle_cpu { ...@@ -90,6 +90,7 @@ struct idle_cpu {
* Indicate which enable bits to clear here. * Indicate which enable bits to clear here.
*/ */
unsigned long auto_demotion_disable_flags; unsigned long auto_demotion_disable_flags;
bool disable_promotion_to_c1e;
}; };
static const struct idle_cpu *icpu; static const struct idle_cpu *icpu;
...@@ -131,6 +132,13 @@ static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = { ...@@ -131,6 +132,13 @@ static struct cpuidle_state nehalem_cstates[CPUIDLE_STATE_MAX] = {
.exit_latency = 3, .exit_latency = 3,
.target_residency = 6, .target_residency = 6,
.enter = &intel_idle }, .enter = &intel_idle },
{
.name = "C1E-NHM",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{ {
.name = "C3-NHM", .name = "C3-NHM",
.desc = "MWAIT 0x10", .desc = "MWAIT 0x10",
...@@ -154,8 +162,15 @@ static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = { ...@@ -154,8 +162,15 @@ static struct cpuidle_state snb_cstates[CPUIDLE_STATE_MAX] = {
.name = "C1-SNB", .name = "C1-SNB",
.desc = "MWAIT 0x00", .desc = "MWAIT 0x00",
.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1, .exit_latency = 2,
.target_residency = 1, .target_residency = 2,
.enter = &intel_idle },
{
.name = "C1E-SNB",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle }, .enter = &intel_idle },
{ {
.name = "C3-SNB", .name = "C3-SNB",
...@@ -190,6 +205,13 @@ static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = { ...@@ -190,6 +205,13 @@ static struct cpuidle_state ivb_cstates[CPUIDLE_STATE_MAX] = {
.exit_latency = 1, .exit_latency = 1,
.target_residency = 1, .target_residency = 1,
.enter = &intel_idle }, .enter = &intel_idle },
{
.name = "C1E-IVB",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{ {
.name = "C3-IVB", .name = "C3-IVB",
.desc = "MWAIT 0x10", .desc = "MWAIT 0x10",
...@@ -223,6 +245,13 @@ static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { ...@@ -223,6 +245,13 @@ static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = {
.exit_latency = 2, .exit_latency = 2,
.target_residency = 2, .target_residency = 2,
.enter = &intel_idle }, .enter = &intel_idle },
{
.name = "C1E-HSW",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{ {
.name = "C3-HSW", .name = "C3-HSW",
.desc = "MWAIT 0x10", .desc = "MWAIT 0x10",
...@@ -250,11 +279,11 @@ static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = { ...@@ -250,11 +279,11 @@ static struct cpuidle_state hsw_cstates[CPUIDLE_STATE_MAX] = {
static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = { static struct cpuidle_state atom_cstates[CPUIDLE_STATE_MAX] = {
{ {
.name = "C1-ATM", .name = "C1E-ATM",
.desc = "MWAIT 0x00", .desc = "MWAIT 0x00",
.flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID, .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1, .exit_latency = 10,
.target_residency = 4, .target_residency = 20,
.enter = &intel_idle }, .enter = &intel_idle },
{ {
.name = "C2-ATM", .name = "C2-ATM",
...@@ -377,10 +406,19 @@ static void auto_demotion_disable(void *dummy) ...@@ -377,10 +406,19 @@ static void auto_demotion_disable(void *dummy)
msr_bits &= ~(icpu->auto_demotion_disable_flags); msr_bits &= ~(icpu->auto_demotion_disable_flags);
wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits); wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
} }
static void c1e_promotion_disable(void *dummy)
{
unsigned long long msr_bits;
rdmsrl(MSR_IA32_POWER_CTL, msr_bits);
msr_bits &= ~0x2;
wrmsrl(MSR_IA32_POWER_CTL, msr_bits);
}
static const struct idle_cpu idle_cpu_nehalem = { static const struct idle_cpu idle_cpu_nehalem = {
.state_table = nehalem_cstates, .state_table = nehalem_cstates,
.auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE, .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
.disable_promotion_to_c1e = true,
}; };
static const struct idle_cpu idle_cpu_atom = { static const struct idle_cpu idle_cpu_atom = {
...@@ -394,14 +432,17 @@ static const struct idle_cpu idle_cpu_lincroft = { ...@@ -394,14 +432,17 @@ static const struct idle_cpu idle_cpu_lincroft = {
static const struct idle_cpu idle_cpu_snb = { static const struct idle_cpu idle_cpu_snb = {
.state_table = snb_cstates, .state_table = snb_cstates,
.disable_promotion_to_c1e = true,
}; };
static const struct idle_cpu idle_cpu_ivb = { static const struct idle_cpu idle_cpu_ivb = {
.state_table = ivb_cstates, .state_table = ivb_cstates,
.disable_promotion_to_c1e = true,
}; };
static const struct idle_cpu idle_cpu_hsw = { static const struct idle_cpu idle_cpu_hsw = {
.state_table = hsw_cstates, .state_table = hsw_cstates,
.disable_promotion_to_c1e = true,
}; };
#define ICPU(model, cpu) \ #define ICPU(model, cpu) \
...@@ -544,6 +585,9 @@ static int intel_idle_cpuidle_driver_init(void) ...@@ -544,6 +585,9 @@ static int intel_idle_cpuidle_driver_init(void)
if (icpu->auto_demotion_disable_flags) if (icpu->auto_demotion_disable_flags)
on_each_cpu(auto_demotion_disable, NULL, 1); on_each_cpu(auto_demotion_disable, NULL, 1);
if (icpu->disable_promotion_to_c1e) /* each-cpu is redundant */
on_each_cpu(c1e_promotion_disable, NULL, 1);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment