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>
This commit is contained in:
parent
3bd391f056
commit
b66b8b9a4a
|
@ -62,6 +62,7 @@
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <asm/cpu_device_id.h>
|
||||||
#include <asm/mwait.h>
|
#include <asm/mwait.h>
|
||||||
#include <asm/msr.h>
|
#include <asm/msr.h>
|
||||||
|
|
||||||
|
@ -81,18 +82,23 @@ static unsigned int mwait_substates;
|
||||||
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
|
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
|
||||||
static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
|
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 struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
|
||||||
static int intel_idle(struct cpuidle_device *dev,
|
static int intel_idle(struct cpuidle_device *dev,
|
||||||
struct cpuidle_driver *drv, int index);
|
struct cpuidle_driver *drv, int index);
|
||||||
|
|
||||||
static struct cpuidle_state *cpuidle_state_table;
|
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
|
* 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.
|
* and so we don't need cross-calls to keep it consistent.
|
||||||
|
@ -319,27 +325,72 @@ static void auto_demotion_disable(void *dummy)
|
||||||
unsigned long long msr_bits;
|
unsigned long long msr_bits;
|
||||||
|
|
||||||
rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, 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);
|
wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct idle_cpu idle_cpu_nehalem = {
|
||||||
|
.state_table = nehalem_cstates,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct idle_cpu idle_cpu_westmere = {
|
||||||
|
.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_westmere),
|
||||||
|
ICPU(0x2c, idle_cpu_westmere),
|
||||||
|
ICPU(0x2f, idle_cpu_westmere),
|
||||||
|
ICPU(0x1c, idle_cpu_atom),
|
||||||
|
ICPU(0x26, idle_cpu_lincroft),
|
||||||
|
ICPU(0x2f, idle_cpu_westmere),
|
||||||
|
ICPU(0x2a, idle_cpu_snb),
|
||||||
|
ICPU(0x2d, idle_cpu_snb),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* intel_idle_probe()
|
* intel_idle_probe()
|
||||||
*/
|
*/
|
||||||
static int intel_idle_probe(void)
|
static int intel_idle_probe(void)
|
||||||
{
|
{
|
||||||
unsigned int eax, ebx, ecx;
|
unsigned int eax, ebx, ecx;
|
||||||
|
const struct x86_cpu_id *id;
|
||||||
|
|
||||||
if (max_cstate == 0) {
|
if (max_cstate == 0) {
|
||||||
pr_debug(PREFIX "disabled\n");
|
pr_debug(PREFIX "disabled\n");
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
|
id = x86_match_cpu(intel_idle_ids);
|
||||||
return -ENODEV;
|
if (!id) {
|
||||||
|
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
|
||||||
if (!boot_cpu_has(X86_FEATURE_MWAIT))
|
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;
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
|
if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -353,43 +404,8 @@ static int intel_idle_probe(void)
|
||||||
|
|
||||||
pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
|
pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
|
||||||
|
|
||||||
|
icpu = (const struct idle_cpu *)id->driver_data;
|
||||||
if (boot_cpu_data.x86 != 6) /* family 6 */
|
cpuidle_state_table = icpu->state_table;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
|
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
|
||||||
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
|
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
|
||||||
|
@ -470,7 +486,7 @@ static int intel_idle_cpuidle_driver_init(void)
|
||||||
drv->state_count += 1;
|
drv->state_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (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);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -522,7 +538,7 @@ int intel_idle_cpu_init(int cpu)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto_demotion_disable_flags)
|
if (icpu->auto_demotion_disable_flags)
|
||||||
smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
|
smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue