Commit 9515fdf1 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-dj.bkbits.net/cpufreq

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents f48c54a3 2aebc5b1
...@@ -120,6 +120,21 @@ config X86_SPEEDSTEP_CENTRINO ...@@ -120,6 +120,21 @@ config X86_SPEEDSTEP_CENTRINO
If in doubt, say N. If in doubt, say N.
config X86_SPEEDSTEP_CENTRINO_TABLE
bool
depends on X86_SPEEDSTEP_CENTRINO
default y
config X86_SPEEDSTEP_CENTRINO_ACPI
bool "Use ACPI tables to decode valid frequency/voltage pairs (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on ((X86_SPEEDSTEP_CENTRINO = "m" && ACPI_PROCESSOR) || (X86_SPEEDSTEP_CENTRINO = "y" && ACPI_PROCESSOR = "y"))
help
Use primarily the information provided in the BIOS ACPI tables
to determine valid CPU frequency and voltage pairings.
If in doubt, say Y.
config X86_SPEEDSTEP_ICH config X86_SPEEDSTEP_ICH
tristate "Intel Speedstep on ICH-M chipsets (ioport interface)" tristate "Intel Speedstep on ICH-M chipsets (ioport interface)"
depends on CPU_FREQ_TABLE depends on CPU_FREQ_TABLE
...@@ -161,6 +176,16 @@ config X86_SPEEDSTEP_LIB ...@@ -161,6 +176,16 @@ config X86_SPEEDSTEP_LIB
depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) depends on (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD) default (X86_SPEEDSTEP_ICH || X86_SPEEDSTEP_SMI || X86_P4_CLOCKMOD)
config X86_SPEEDSTEP_RELAXED_CAP_CHECK
bool "Relaxed speedstep capability checks"
depends on (X86_SPEEDSTEP_SMI || X86_SPEEDSTEP_ICH)
help
Don't perform all checks for a speedstep capable system which would
normally be done. Some ancient or strange systems, though speedstep
capable, don't always indicate that they are speedstep capable. This
option let's the probing code bypass some of those checks if the
parameter "relaxed_check=1" is passed to the module.
config X86_LONGRUN config X86_LONGRUN
tristate "Transmeta LongRun" tristate "Transmeta LongRun"
depends on CPU_FREQ depends on CPU_FREQ
......
...@@ -166,6 +166,7 @@ static void elanfreq_set_cpu_state (unsigned int state) { ...@@ -166,6 +166,7 @@ static void elanfreq_set_cpu_state (unsigned int state) {
/** /**
* elanfreq_validatespeed: test if frequency range is valid * elanfreq_validatespeed: test if frequency range is valid
* @policy: the policy to validate
* *
* This function checks if a given frequency range in kHz is valid * This function checks if a given frequency range in kHz is valid
* for the hardware supported by the driver. * for the hardware supported by the driver.
......
...@@ -458,7 +458,7 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy) ...@@ -458,7 +458,7 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy)
return 0; return 0;
} }
static int longhaul_cpu_exit(struct cpufreq_policy *policy) static int __exit longhaul_cpu_exit(struct cpufreq_policy *policy)
{ {
cpufreq_frequency_table_put_attr(policy->cpu); cpufreq_frequency_table_put_attr(policy->cpu);
return 0; return 0;
......
...@@ -33,7 +33,7 @@ static unsigned int longrun_low_freq, longrun_high_freq; ...@@ -33,7 +33,7 @@ static unsigned int longrun_low_freq, longrun_high_freq;
* Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
* and MSR_TMTA_LONGRUN_CTRL * and MSR_TMTA_LONGRUN_CTRL
*/ */
static void longrun_get_policy(struct cpufreq_policy *policy) static void __init longrun_get_policy(struct cpufreq_policy *policy)
{ {
u32 msr_lo, msr_hi; u32 msr_lo, msr_hi;
...@@ -57,7 +57,7 @@ static void longrun_get_policy(struct cpufreq_policy *policy) ...@@ -57,7 +57,7 @@ static void longrun_get_policy(struct cpufreq_policy *policy)
/** /**
* longrun_set_policy - sets a new CPUFreq policy * longrun_set_policy - sets a new CPUFreq policy
* @policy - new policy * @policy: new policy
* *
* Sets a new CPUFreq policy on LongRun-capable processors. This function * Sets a new CPUFreq policy on LongRun-capable processors. This function
* has to be called with cpufreq_driver locked. * has to be called with cpufreq_driver locked.
...@@ -106,6 +106,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy) ...@@ -106,6 +106,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
/** /**
* longrun_verify_poliy - verifies a new CPUFreq policy * longrun_verify_poliy - verifies a new CPUFreq policy
* @policy: the policy to verify
* *
* Validates a new CPUFreq policy. This function has to be called with * Validates a new CPUFreq policy. This function has to be called with
* cpufreq_driver locked. * cpufreq_driver locked.
...@@ -130,6 +131,8 @@ static int longrun_verify_policy(struct cpufreq_policy *policy) ...@@ -130,6 +131,8 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
/** /**
* longrun_determine_freqs - determines the lowest and highest possible core frequency * longrun_determine_freqs - determines the lowest and highest possible core frequency
* @low_freq: an int to put the lowest frequency into
* @high_freq: an int to put the highest frequency into
* *
* Determines the lowest and highest possible core frequencies on this CPU. * Determines the lowest and highest possible core frequencies on this CPU.
* This is necessary to calculate the performance percentage according to * This is necessary to calculate the performance percentage according to
...@@ -142,6 +145,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, ...@@ -142,6 +145,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
u32 msr_lo, msr_hi; u32 msr_lo, msr_hi;
u32 save_lo, save_hi; u32 save_lo, save_hi;
u32 eax, ebx, ecx, edx; u32 eax, ebx, ecx, edx;
u32 try_hi;
struct cpuinfo_x86 *c = cpu_data; struct cpuinfo_x86 *c = cpu_data;
if (!low_freq || !high_freq) if (!low_freq || !high_freq)
...@@ -184,12 +188,14 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, ...@@ -184,12 +188,14 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
* upper limit to make the calculation more accurate. * upper limit to make the calculation more accurate.
*/ */
cpuid(0x80860007, &eax, &ebx, &ecx, &edx); cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
if (ecx > 90) { /* try decreasing in 10% steps, some processors react only
/* set to 0 to 80 perf_pctg */ * on some barrier values */
for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -=10) {
/* set to 0 to try_hi perf_pctg */
msr_lo &= 0xFFFFFF80; msr_lo &= 0xFFFFFF80;
msr_hi &= 0xFFFFFF80; msr_hi &= 0xFFFFFF80;
msr_lo |= 0; msr_lo |= 0;
msr_hi |= 80; msr_hi |= try_hi;
wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
/* read out current core MHz and current perf_pctg */ /* read out current core MHz and current perf_pctg */
......
...@@ -181,21 +181,24 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -181,21 +181,24 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{ {
if ((c->x86 == 0x06) && (c->x86_model == 0x09)) { if ((c->x86 == 0x06) && (c->x86_model == 0x09)) {
/* Pentium M */ /* Pentium M */
printk(KERN_DEBUG PFX "Warning: Pentium M detected. The speedstep_centrino module\n"); printk(KERN_WARNING PFX "Warning: Pentium M detected. "
printk(KERN_DEBUG PFX "offers voltage scaling in addition of frequency scaling. You\n"); "The speedstep_centrino module offers voltage scaling"
printk(KERN_DEBUG PFX "should use that instead of p4-clockmod, if possible.\n"); " in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n");
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
} }
if (c->x86 != 0xF) { if (c->x86 != 0xF) {
printk(KERN_DEBUG PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <linux@brodo.de>\n"); printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. Please send an e-mail to <linux@brodo.de>\n");
return 0; return 0;
} }
if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) { if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) {
printk(KERN_DEBUG PFX "Warning: Pentium 4-M detected. The speedstep-ich or acpi cpufreq \n"); printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
printk(KERN_DEBUG PFX "modules offers voltage scaling in addition of frequency scaling. You\n"); "The speedstep-ich or acpi cpufreq modules offer "
printk(KERN_DEBUG PFX "should use either one instead of p4-clockmod, if possible.\n"); "voltage scaling in addition of frequency scaling. "
"You should use either one instead of p4-clockmod, "
"if possible.\n");
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M); return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M);
} }
......
...@@ -118,7 +118,9 @@ static int powernow_k6_verify(struct cpufreq_policy *policy) ...@@ -118,7 +118,9 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
/** /**
* powernow_k6_setpolicy - sets a new CPUFreq policy * powernow_k6_setpolicy - sets a new CPUFreq policy
* @policy - new policy * @policy: new policy
* @target_freq: the target frequency
* @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
* *
* sets a new CPUFreq policy * sets a new CPUFreq policy
*/ */
......
...@@ -98,18 +98,20 @@ static int check_powernow(void) ...@@ -98,18 +98,20 @@ static int check_powernow(void)
return 0; return 0;
} }
if ((c->x86_model == 6) && (c->x86_mask == 0)) {
printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n");
have_a0 = 1;
}
/* Get maximum capabilities */ /* Get maximum capabilities */
maxei = cpuid_eax (0x80000000); maxei = cpuid_eax (0x80000000);
if (maxei < 0x80000007) { /* Any powernow info ? */ if (maxei < 0x80000007) { /* Any powernow info ? */
#ifdef MODULE
printk (KERN_INFO PFX "No powernow capabilities detected\n"); printk (KERN_INFO PFX "No powernow capabilities detected\n");
#endif
return 0; return 0;
} }
if ((c->x86_model == 6) && (c->x86_mask == 0)) {
printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n");
have_a0 = 1;
}
cpuid(0x80000007, &eax, &ebx, &ecx, &edx); cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
......
This diff is collapsed.
/* /*
* (c) 2003 Advanced Micro Devices, Inc. * (c) 2003, 2004 Advanced Micro Devices, Inc.
* Your use of this code is subject to the terms and conditions of the * Your use of this code is subject to the terms and conditions of the
* GNU general public license version 2. See "../../../COPYING" or * GNU general public license version 2. See "COPYING" or
* http://www.gnu.org/licenses/gpl.html * http://www.gnu.org/licenses/gpl.html
*/ */
struct powernow_k8_data {
unsigned int cpu;
u32 numps; /* number of p-states */
u32 batps; /* number of p-states supported on battery */
/* these values are constant when the PSB is used to determine
* vid/fid pairings, but are modified during the ->target() call
* when ACPI is used */
u32 rvo; /* ramp voltage offset */
u32 irt; /* isochronous relief time */
u32 vidmvs; /* usable value calculated from mvs */
u32 vstable; /* voltage stabilization time, units 20 us */
u32 plllock; /* pll lock time, units 1 us */
/* keep track of the current fid / vid */
u32 currvid;
u32 currfid;
/* the powernow_table includes all frequency and vid/fid pairings:
* fid are the lower 8 bits of the index, vid are the upper 8 bits.
* frequency is in kHz */
struct cpufreq_frequency_table *powernow_table;
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
/* the acpi table needs to be kept. it's only available if ACPI was
* used to determine valid frequency/vid/fid states */
struct acpi_processor_performance acpi_data;
#endif
};
/* processor's cpuid instruction support */ /* processor's cpuid instruction support */
#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */ #define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */
#define CPUID_F1_FAM 0x00000f00 /* family mask */ #define CPUID_XFAM_MOD 0x0ff00ff0 /* extended fam, fam + model */
#define CPUID_F1_XFAM 0x0ff00000 /* extended family mask */ #define ATHLON64_XFAM_MOD 0x00000f40 /* extended fam, fam + model */
#define CPUID_F1_MOD 0x000000f0 /* model mask */ #define OPTERON_XFAM_MOD 0x00000f50 /* extended fam, fam + model */
#define CPUID_F1_STEP 0x0000000f /* stepping level mask */
#define CPUID_XFAM_MOD 0x0ff00ff0 /* xtended fam, fam + model */
#define ATHLON64_XFAM_MOD 0x00000f40 /* xtended fam, fam + model */
#define OPTERON_XFAM_MOD 0x00000f50 /* xtended fam, fam + model */
#define ATHLON64_REV_C0 8
#define CPUID_GET_MAX_CAPABILITIES 0x80000000 #define CPUID_GET_MAX_CAPABILITIES 0x80000000
#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 #define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
#define P_STATE_TRANSITION_CAPABLE 6 #define P_STATE_TRANSITION_CAPABLE 6
...@@ -47,10 +74,23 @@ ...@@ -47,10 +74,23 @@
#define MSR_S_HI_MAX_WORKING_VID 0x001f0000 #define MSR_S_HI_MAX_WORKING_VID 0x001f0000
#define MSR_S_HI_START_VID 0x00001f00 #define MSR_S_HI_START_VID 0x00001f00
#define MSR_S_HI_CURRENT_VID 0x0000001f #define MSR_S_HI_CURRENT_VID 0x0000001f
#define MSR_C_HI_STP_GNT_BENIGN 0x00000001
/*
* There are restrictions frequencies have to follow:
* - only 1 entry in the low fid table ( <=1.4GHz )
* - lowest entry in the high fid table must be >= 2 * the entry in the
* low fid table
* - lowest entry in the high fid table must be a <= 200MHz + 2 * the entry
* in the low fid table
* - the parts can only step at 200 MHz intervals, so 1.9 GHz is never valid
* - lowest frequency must be >= interprocessor hypertransport link speed
* (only applies to MP systems obviously)
*/
/* fids (frequency identifiers) are arranged in 2 tables - lo and hi */ /* fids (frequency identifiers) are arranged in 2 tables - lo and hi */
#define LO_FID_TABLE_TOP 6 #define LO_FID_TABLE_TOP 6 /* fid values marking the boundary */
#define HI_FID_TABLE_BOTTOM 8 #define HI_FID_TABLE_BOTTOM 8 /* between the low and high tables */
#define LO_VCOFREQ_TABLE_TOP 1400 /* corresponding vco frequency values */ #define LO_VCOFREQ_TABLE_TOP 1400 /* corresponding vco frequency values */
#define HI_VCOFREQ_TABLE_BOTTOM 1600 #define HI_VCOFREQ_TABLE_BOTTOM 1600
...@@ -58,14 +98,12 @@ ...@@ -58,14 +98,12 @@
#define MIN_FREQ_RESOLUTION 200 /* fids jump by 2 matching freq jumps by 200 */ #define MIN_FREQ_RESOLUTION 200 /* fids jump by 2 matching freq jumps by 200 */
#define MAX_FID 0x2a /* Spec only gives FID values as far as 5 GHz */ #define MAX_FID 0x2a /* Spec only gives FID values as far as 5 GHz */
#define LEAST_VID 0x1e /* Lowest (numerically highest) useful vid value */ #define LEAST_VID 0x1e /* Lowest (numerically highest) useful vid value */
#define MIN_FREQ 800 /* Min and max freqs, per spec */ #define MIN_FREQ 800 /* Min and max freqs, per spec */
#define MAX_FREQ 5000 #define MAX_FREQ 5000
#define INVALID_FID_MASK 0xffffffc1 /* not a valid fid if these bits are set */ #define INVALID_FID_MASK 0xffffffc1 /* not a valid fid if these bits are set */
#define INVALID_VID_MASK 0xffffffe0 /* not a valid vid if these bits are set */ #define INVALID_VID_MASK 0xffffffe0 /* not a valid vid if these bits are set */
#define STOP_GRANT_5NS 1 /* min poss memory access latency for voltage change */ #define STOP_GRANT_5NS 1 /* min poss memory access latency for voltage change */
...@@ -73,18 +111,35 @@ ...@@ -73,18 +111,35 @@
#define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */ #define PLL_LOCK_CONVERSION (1000/5) /* ms to ns, then divide by clock period */
#define MAXIMUM_VID_STEPS 1 /* Current cpus only allow a single step of 25mV */ #define MAXIMUM_VID_STEPS 1 /* Current cpus only allow a single step of 25mV */
#define VST_UNITS_20US 20 /* Voltage Stabalization Time is in units of 20us */ #define VST_UNITS_20US 20 /* Voltage Stabalization Time is in units of 20us */
/* /*
Version 1.4 of the PSB table. This table is constructed by BIOS and is * Most values of interest are enocoded in a single field of the _PSS
to tell the OS's power management driver which VIDs and FIDs are * entries: the "control" value.
supported by this particular processor. This information is obtained from */
the data sheets for each processor model by the system vendor and
incorporated into the BIOS. #define IRT_SHIFT 30
If the data in the PSB / PST is wrong, then this driver will program the #define RVO_SHIFT 28
wrong values into hardware, which is very likely to lead to a crash. #define PLL_L_SHIFT 20
*/ #define MVS_SHIFT 18
#define VST_SHIFT 11
#define VID_SHIFT 6
#define IRT_MASK 3
#define RVO_MASK 3
#define PLL_L_MASK 0x7f
#define MVS_MASK 3
#define VST_MASK 0x7f
#define VID_MASK 0x1f
#define FID_MASK 0x3f
/*
* Version 1.4 of the PSB table. This table is constructed by BIOS and is
* to tell the OS's power management driver which VIDs and FIDs are
* supported by this particular processor.
* If the data in the PSB / PST is wrong, then this driver will program the
* wrong values into hardware, which is very likely to lead to a crash.
*/
#define PSB_ID_STRING "AMDK7PNOW!" #define PSB_ID_STRING "AMDK7PNOW!"
#define PSB_ID_STRING_LEN 10 #define PSB_ID_STRING_LEN 10
...@@ -117,6 +172,8 @@ struct pst_s { ...@@ -117,6 +172,8 @@ struct pst_s {
#define dprintk(msg...) do { } while(0) #define dprintk(msg...) do { } while(0)
#endif #endif
static inline int core_voltage_pre_transition(u32 reqvid); static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid);
static inline int core_voltage_post_transition(u32 reqvid); static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid);
static inline int core_frequency_transition(u32 reqfid); static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/config.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -46,7 +47,9 @@ struct cpu_model ...@@ -46,7 +47,9 @@ struct cpu_model
}; };
/* Operating points for current CPU */ /* Operating points for current CPU */
static const struct cpu_model *centrino_model; static struct cpu_model *centrino_model;
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE
/* Computes the correct form for IA32_PERF_CTL MSR for a particular /* Computes the correct form for IA32_PERF_CTL MSR for a particular
frequency/voltage operating point; frequency in MHz, volts in mV. frequency/voltage operating point; frequency in MHz, volts in mV.
...@@ -172,7 +175,7 @@ static struct cpufreq_frequency_table op_1700[] = ...@@ -172,7 +175,7 @@ static struct cpufreq_frequency_table op_1700[] =
/* CPU models, their operating frequency range, and freq/voltage /* CPU models, their operating frequency range, and freq/voltage
operating points */ operating points */
static const struct cpu_model models[] = static struct cpu_model models[] =
{ {
_CPU( 900, " 900"), _CPU( 900, " 900"),
CPU(1000), CPU(1000),
...@@ -187,6 +190,48 @@ static const struct cpu_model models[] = ...@@ -187,6 +190,48 @@ static const struct cpu_model models[] =
}; };
#undef CPU #undef CPU
static int centrino_cpu_init_table(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu];
struct cpu_model *model;
if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV;
/* Only Intel Pentium M stepping 5 for now - add new CPUs as
they appear after making sure they use PERF_CTL in the same
way. */
if (cpu->x86_vendor != X86_VENDOR_INTEL ||
cpu->x86 != 6 ||
cpu->x86_model != 9 ||
cpu->x86_mask != 5) {
printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
"send /proc/cpuinfo to " MAINTAINER "\n");
return -ENODEV;
}
for(model = models; model->model_name != NULL; model++)
if (strcmp(cpu->x86_model_id, model->model_name) == 0)
break;
if (model->model_name == NULL) {
printk(KERN_INFO PFX "no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id);
return -ENOENT;
}
centrino_model = model;
printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq);
return 0;
}
#else
static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; }
#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */
/* Extract clock in kHz from PERF_CTL value */ /* Extract clock in kHz from PERF_CTL value */
static unsigned extract_clock(unsigned msr) static unsigned extract_clock(unsigned msr)
{ {
...@@ -203,12 +248,147 @@ static unsigned get_cur_freq(void) ...@@ -203,12 +248,147 @@ static unsigned get_cur_freq(void)
return extract_clock(l); return extract_clock(l);
} }
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
static struct acpi_processor_performance p;
#include <linux/acpi.h>
#include <acpi/processor.h>
#define ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP 0x1
/*
* centrino_cpu_init_acpi - register with ACPI P-States library
*
* Register with the ACPI P-States library (part of drivers/acpi/processor.c)
* in order to determine correct frequency and voltage pairings by reading
* the _PSS of the ACPI DSDT or SSDT tables.
*/
static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
{
union acpi_object arg0 = {ACPI_TYPE_BUFFER};
u32 arg0_buf[3];
struct acpi_object_list arg_list = {1, &arg0};
unsigned long cur_freq;
int result = 0, i;
/* _PDC settings */
arg0.buffer.length = 12;
arg0.buffer.pointer = (u8 *) arg0_buf;
arg0_buf[0] = ACPI_PDC_REVISION_ID;
arg0_buf[1] = 1;
arg0_buf[2] = ACPI_PDC_CAPABILITY_ENHANCED_SPEEDSTEP;
p.pdc = &arg_list;
/* register with ACPI core */
if (acpi_processor_register_performance(&p, 0))
return -EIO;
/* verify the acpi_data */
if (p.state_count <= 1) {
printk(KERN_DEBUG "No P-States\n");
result = -ENODEV;
goto err_unreg;
}
if ((p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
(p.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
printk(KERN_DEBUG "Invalid control/status registers\n");
result = -EIO;
goto err_unreg;
}
for (i=0; i<p.state_count; i++) {
if (p.states[i].control != p.states[i].status) {
printk(KERN_DEBUG "Different control and status values\n");
result = -EINVAL;
goto err_unreg;
}
if (!p.states[i].core_frequency) {
printk(KERN_DEBUG "Zero core frequency\n");
result = -EINVAL;
goto err_unreg;
}
if (extract_clock(p.states[i].control) !=
(p.states[i].core_frequency * 1000)) {
printk(KERN_DEBUG "Invalid encoded frequency\n");
result = -EINVAL;
goto err_unreg;
}
}
centrino_model = kmalloc(sizeof(struct cpu_model), GFP_KERNEL);
if (!centrino_model) {
result = -ENOMEM;
goto err_unreg;
}
memset(centrino_model, 0, sizeof(struct cpu_model));
centrino_model->model_name=NULL;
centrino_model->max_freq = p.states[0].core_frequency * 1000;
centrino_model->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
(p.state_count + 1), GFP_KERNEL);
if (!centrino_model->op_points) {
result = -ENOMEM;
goto err_kfree;
}
cur_freq = get_cur_freq();
for (i=0; i<p.state_count; i++) {
centrino_model->op_points[i].index = p.states[i].control;
centrino_model->op_points[i].frequency = p.states[i].core_frequency * 1000;
if (cur_freq == centrino_model->op_points[i].frequency)
p.state = i;
}
centrino_model->op_points[p.state_count].frequency = CPUFREQ_TABLE_END;
return 0;
err_kfree:
kfree(centrino_model);
err_unreg:
acpi_processor_unregister_performance(&p, 0);
return (result);
}
#else
static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; }
#endif
static int centrino_cpu_init(struct cpufreq_policy *policy) static int centrino_cpu_init(struct cpufreq_policy *policy)
{ {
unsigned freq; unsigned freq;
unsigned l, h;
int ret;
if (policy->cpu != 0)
return -ENODEV;
if (centrino_cpu_init_acpi(policy)) {
if (centrino_cpu_init_table(policy)) {
return -ENODEV;
}
}
/* Check to see if Enhanced SpeedStep is enabled, and try to
enable it if not. */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (policy->cpu != 0 || centrino_model == NULL) if (!(l & (1<<16))) {
l |= (1<<16);
wrmsr(MSR_IA32_MISC_ENABLE, l, h);
/* check to see if it stuck */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
return -ENODEV; return -ENODEV;
}
}
freq = get_cur_freq(); freq = get_cur_freq();
...@@ -219,12 +399,38 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -219,12 +399,38 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n", dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
policy->policy, policy->cur); policy->policy, policy->cur);
return cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); ret = cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points);
if (ret)
return (ret);
cpufreq_frequency_table_get_attr(centrino_model->op_points, policy->cpu);
return 0;
}
static int centrino_cpu_exit(struct cpufreq_policy *policy)
{
if (!centrino_model)
return -ENODEV;
cpufreq_frequency_table_put_attr(policy->cpu);
#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
if (!centrino_model->model_name) {
acpi_processor_unregister_performance(&p, 0);
kfree(centrino_model->op_points);
kfree(centrino_model);
}
#endif
centrino_model = NULL;
return 0;
} }
/** /**
* centrino_verify - verifies a new CPUFreq policy * centrino_verify - verifies a new CPUFreq policy
* @freq: new policy * @policy: new policy
* *
* Limit must be within this model's frequency range at least one * Limit must be within this model's frequency range at least one
* border included. * border included.
...@@ -237,6 +443,8 @@ static int centrino_verify (struct cpufreq_policy *policy) ...@@ -237,6 +443,8 @@ static int centrino_verify (struct cpufreq_policy *policy)
/** /**
* centrino_setpolicy - set a new CPUFreq policy * centrino_setpolicy - set a new CPUFreq policy
* @policy: new policy * @policy: new policy
* @target_freq: the target frequency
* @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
* *
* Sets a new CPUFreq policy. * Sets a new CPUFreq policy.
*/ */
...@@ -295,12 +503,19 @@ static int centrino_target (struct cpufreq_policy *policy, ...@@ -295,12 +503,19 @@ static int centrino_target (struct cpufreq_policy *policy,
return 0; return 0;
} }
static struct freq_attr* centrino_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static struct cpufreq_driver centrino_driver = { static struct cpufreq_driver centrino_driver = {
.name = "centrino", /* should be speedstep-centrino, .name = "centrino", /* should be speedstep-centrino,
but there's a 16 char limit */ but there's a 16 char limit */
.init = centrino_cpu_init, .init = centrino_cpu_init,
.exit = centrino_cpu_exit,
.verify = centrino_verify, .verify = centrino_verify,
.target = centrino_target, .target = centrino_target,
.attr = centrino_attr,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -322,55 +537,10 @@ static struct cpufreq_driver centrino_driver = { ...@@ -322,55 +537,10 @@ static struct cpufreq_driver centrino_driver = {
static int __init centrino_init(void) static int __init centrino_init(void)
{ {
struct cpuinfo_x86 *cpu = cpu_data; struct cpuinfo_x86 *cpu = cpu_data;
const struct cpu_model *model;
unsigned l, h;
if (!cpu_has(cpu, X86_FEATURE_EST)) if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV; return -ENODEV;
/* Only Intel Pentium M stepping 5 for now - add new CPUs as
they appear after making sure they use PERF_CTL in the same
way. */
if (cpu->x86_vendor != X86_VENDOR_INTEL ||
cpu->x86 != 6 ||
cpu->x86_model != 9 ||
cpu->x86_mask != 5) {
printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
"send /proc/cpuinfo to " MAINTAINER "\n");
return -ENODEV;
}
/* Check to see if Enhanced SpeedStep is enabled, and try to
enable it if not. */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
l |= (1<<16);
wrmsr(MSR_IA32_MISC_ENABLE, l, h);
/* check to see if it stuck */
rdmsr(MSR_IA32_MISC_ENABLE, l, h);
if (!(l & (1<<16))) {
printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n");
return -ENODEV;
}
}
for(model = models; model->model_name != NULL; model++)
if (strcmp(cpu->x86_model_id, model->model_name) == 0)
break;
if (model->model_name == NULL) {
printk(KERN_INFO PFX "no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id);
return -ENOENT;
}
centrino_model = model;
printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq);
return cpufreq_register_driver(&centrino_driver); return cpufreq_register_driver(&centrino_driver);
} }
...@@ -383,5 +553,5 @@ MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>"); ...@@ -383,5 +553,5 @@ MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
module_init(centrino_init); late_initcall(centrino_init);
module_exit(centrino_exit); module_exit(centrino_exit);
...@@ -67,6 +67,7 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { ...@@ -67,6 +67,7 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
/** /**
* speedstep_set_state - set the SpeedStep state * speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
* @notify: whether to call cpufreq_notify_transition for CPU speed changes
* *
* Tries to change the SpeedStep state. * Tries to change the SpeedStep state.
*/ */
...@@ -239,8 +240,10 @@ static unsigned int speedstep_detect_chipset (void) ...@@ -239,8 +240,10 @@ static unsigned int speedstep_detect_chipset (void)
/** /**
* speedstep_setpolicy - set a new CPUFreq policy * speedstep_target - set a new CPUFreq policy
* @policy: new policy * @policy: new policy
* @target_freq: the target frequency
* @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
* *
* Sets a new CPUFreq policy. * Sets a new CPUFreq policy.
*/ */
...@@ -261,7 +264,7 @@ static int speedstep_target (struct cpufreq_policy *policy, ...@@ -261,7 +264,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
/** /**
* speedstep_verify - verifies a new CPUFreq policy * speedstep_verify - verifies a new CPUFreq policy
* @freq: new policy * @policy: new policy
* *
* Limit must be within speedstep_low_freq and speedstep_high_freq, with * Limit must be within speedstep_low_freq and speedstep_high_freq, with
* at least one border included. * at least one border included.
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -30,6 +31,12 @@ ...@@ -30,6 +31,12 @@
#define dprintk(msg...) do { } while(0) #define dprintk(msg...) do { } while(0)
#endif #endif
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
static int relaxed_check = 0;
#else
#define relaxed_check 0
#endif
/********************************************************************* /*********************************************************************
* GET PROCESSOR CORE SPEED IN KHZ * * GET PROCESSOR CORE SPEED IN KHZ *
*********************************************************************/ *********************************************************************/
...@@ -120,7 +127,7 @@ static unsigned int pentiumM_get_frequency(void) ...@@ -120,7 +127,7 @@ static unsigned int pentiumM_get_frequency(void)
msr_tmp = (msr_lo >> 22) & 0x1f; msr_tmp = (msr_lo >> 22) & 0x1f;
dprintk(KERN_DEBUG "speedstep-lib: bits 22-26 are 0x%x\n", msr_tmp); dprintk(KERN_DEBUG "speedstep-lib: bits 22-26 are 0x%x\n", msr_tmp);
return (msr_tmp * 100 * 10000); return (msr_tmp * 100 * 1000);
} }
...@@ -210,7 +217,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -210,7 +217,7 @@ unsigned int speedstep_detect_processor (void)
ebx = cpuid_ebx(0x00000001); ebx = cpuid_ebx(0x00000001);
ebx &= 0x000000FF; ebx &= 0x000000FF;
dprintk(KERN_INFO "ebx value is %x, x86_mask is %x\n", ebx, c->86_mask); dprintk(KERN_INFO "ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
switch (c->x86_mask) { switch (c->x86_mask) {
case 4: case 4:
...@@ -265,6 +272,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -265,6 +272,7 @@ unsigned int speedstep_detect_processor (void)
ebx = cpuid_ebx(0x00000001); ebx = cpuid_ebx(0x00000001);
ebx &= 0x000000FF; ebx &= 0x000000FF;
if (ebx != 0x06) if (ebx != 0x06)
return 0; return 0;
...@@ -292,7 +300,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -292,7 +300,7 @@ unsigned int speedstep_detect_processor (void)
*/ */
rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi); dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
if ((msr_hi & (1<<18)) && (msr_hi & (3<<24))) { if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
if (c->x86_mask == 0x01) if (c->x86_mask == 0x01)
return SPEEDSTEP_PROCESSOR_PIII_C_EARLY; return SPEEDSTEP_PROCESSOR_PIII_C_EARLY;
else else
...@@ -362,6 +370,11 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -362,6 +370,11 @@ unsigned int speedstep_get_freqs(unsigned int processor,
} }
EXPORT_SYMBOL_GPL(speedstep_get_freqs); EXPORT_SYMBOL_GPL(speedstep_get_freqs);
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
module_param(relaxed_check, int, 0444);
MODULE_PARM_DESC(relaxed_check, "Don't do all checks for speedstep capability.");
#endif
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers."); MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE ("GPL");
...@@ -90,10 +90,12 @@ static int speedstep_smi_ownership (void) ...@@ -90,10 +90,12 @@ static int speedstep_smi_ownership (void)
/** /**
* speedstep_smi_get_freqs - get SpeedStep preferred & current freq. * speedstep_smi_get_freqs - get SpeedStep preferred & current freq.
* @low: the low frequency value is placed here
* @high: the high frequency value is placed here
*
* Only available on later SpeedStep-enabled systems, returns false results or * Only available on later SpeedStep-enabled systems, returns false results or
* even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing * even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
* shows that the latter occurs if !(ist_info.event & 0xFFFF). * shows that the latter occurs if !(ist_info.event & 0xFFFF).
*
*/ */
static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high) static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
{ {
...@@ -141,6 +143,7 @@ static int speedstep_get_state (void) ...@@ -141,6 +143,7 @@ static int speedstep_get_state (void)
/** /**
* speedstep_set_state - set the SpeedStep state * speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
* @notify: whether to call cpufreq_notify_transition
* *
*/ */
static void speedstep_set_state (unsigned int state, unsigned int notify) static void speedstep_set_state (unsigned int state, unsigned int notify)
...@@ -224,7 +227,7 @@ static int speedstep_target (struct cpufreq_policy *policy, ...@@ -224,7 +227,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
/** /**
* speedstep_verify - verifies a new CPUFreq policy * speedstep_verify - verifies a new CPUFreq policy
* @freq: new policy * @policy: new policy
* *
* Limit must be within speedstep_low_freq and speedstep_high_freq, with * Limit must be within speedstep_low_freq and speedstep_high_freq, with
* at least one border included. * at least one border included.
......
...@@ -509,14 +509,11 @@ static int cpufreq_resume(struct sys_device * sysdev) ...@@ -509,14 +509,11 @@ static int cpufreq_resume(struct sys_device * sysdev)
*/ */
ret = cpufreq_driver->target(cpu_policy, cpu_policy->cur, CPUFREQ_RELATION_H); ret = cpufreq_driver->target(cpu_policy, cpu_policy->cur, CPUFREQ_RELATION_H);
if (ret) { if (ret)
printk(KERN_ERR "cpufreq: resume failed in ->setpolicy/target step on CPU %u\n", cpu_policy->cpu); printk(KERN_ERR "cpufreq: resume failed in ->setpolicy/target step on CPU %u\n", cpu_policy->cpu);
goto out;
}
out: out:
cpufreq_cpu_put(cpu_policy); cpufreq_cpu_put(cpu_policy);
return ret; return ret;
} }
...@@ -963,6 +960,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition); ...@@ -963,6 +960,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
int cpufreq_register_driver(struct cpufreq_driver *driver_data) int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{ {
unsigned long flags; unsigned long flags;
int ret;
if (!driver_data || !driver_data->verify || !driver_data->init || if (!driver_data || !driver_data->verify || !driver_data->init ||
((!driver_data->setpolicy) && (!driver_data->target))) ((!driver_data->setpolicy) && (!driver_data->target)))
...@@ -976,7 +974,28 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -976,7 +974,28 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data; cpufreq_driver = driver_data;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
return sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver); ret = sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver);
if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
ret = -ENODEV;
/* check for at least one working CPU */
for (i=0; i<NR_CPUS; i++)
if (cpufreq_cpu_data[i])
ret = 0;
/* if all ->init() calls failed, unregister */
if (ret) {
sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
}
}
return (ret);
} }
EXPORT_SYMBOL_GPL(cpufreq_register_driver); EXPORT_SYMBOL_GPL(cpufreq_register_driver);
......
...@@ -175,6 +175,7 @@ struct freq_attr; ...@@ -175,6 +175,7 @@ struct freq_attr;
struct cpufreq_driver { struct cpufreq_driver {
struct module *owner; struct module *owner;
char name[CPUFREQ_NAME_LEN]; char name[CPUFREQ_NAME_LEN];
u8 flags;
/* needed by all drivers */ /* needed by all drivers */
int (*init) (struct cpufreq_policy *policy); int (*init) (struct cpufreq_policy *policy);
...@@ -192,6 +193,11 @@ struct cpufreq_driver { ...@@ -192,6 +193,11 @@ struct cpufreq_driver {
struct freq_attr **attr; struct freq_attr **attr;
}; };
/* flags */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
all ->init() calls failed */
int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
......
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