Commit ada19a31 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq: (35 commits)
  [CPUFREQ] Prevent p4-clockmod from auto-binding to the ondemand governor.
  [CPUFREQ] Make cpufreq-nforce2 less obnoxious
  [CPUFREQ] p4-clockmod reports wrong frequency.
  [CPUFREQ] powernow-k8: Use a common exit path.
  [CPUFREQ] Change link order of x86 cpufreq modules
  [CPUFREQ] conservative: remove 10x from def_sampling_rate
  [CPUFREQ] conservative: fixup governor to function more like ondemand logic
  [CPUFREQ] conservative: fix dbs_cpufreq_notifier so freq is not locked
  [CPUFREQ] conservative: amend author's email address
  [CPUFREQ] Use swap() in longhaul.c
  [CPUFREQ] checkpatch cleanups for acpi-cpufreq
  [CPUFREQ] powernow-k8: Only print error message once, not per core.
  [CPUFREQ] ondemand/conservative: sanitize sampling_rate restrictions
  [CPUFREQ] ondemand/conservative: deprecate sampling_rate{min,max}
  [CPUFREQ] powernow-k8: Always compile powernow-k8 driver with ACPI support
  [CPUFREQ] Introduce /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_transition_latency
  [CPUFREQ] checkpatch cleanups for powernow-k8
  [CPUFREQ] checkpatch cleanups for ondemand governor.
  [CPUFREQ] checkpatch cleanups for powernow-k7
  [CPUFREQ] checkpatch cleanups for speedstep related drivers.
  ...
parents 8d80ce80 36e8abf3
...@@ -117,10 +117,28 @@ accessible parameters: ...@@ -117,10 +117,28 @@ accessible parameters:
sampling_rate: measured in uS (10^-6 seconds), this is how often you sampling_rate: measured in uS (10^-6 seconds), this is how often you
want the kernel to look at the CPU usage and to make decisions on want the kernel to look at the CPU usage and to make decisions on
what to do about the frequency. Typically this is set to values of what to do about the frequency. Typically this is set to values of
around '10000' or more. around '10000' or more. It's default value is (cmp. with users-guide.txt):
transition_latency * 1000
show_sampling_rate_(min|max): the minimum and maximum sampling rates The lowest value you can set is:
available that you may set 'sampling_rate' to. transition_latency * 100 or it may get restricted to a value where it
makes not sense for the kernel anymore to poll that often which depends
on your HZ config variable (HZ=1000: max=20000us, HZ=250: max=5000).
Be aware that transition latency is in ns and sampling_rate is in us, so you
get the same sysfs value by default.
Sampling rate should always get adjusted considering the transition latency
To set the sampling rate 750 times as high as the transition latency
in the bash (as said, 1000 is default), do:
echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \
>ondemand/sampling_rate
show_sampling_rate_(min|max): THIS INTERFACE IS DEPRECATED, DON'T USE IT.
You can use wider ranges now and the general
cpuinfo_transition_latency variable (cmp. with user-guide.txt) can be
used to obtain exactly the same info:
show_sampling_rate_min = transtition_latency * 500 / 1000
show_sampling_rate_max = transtition_latency * 500000 / 1000
(divided by 1000 is to illustrate that sampling rate is in us and
transition latency is exported ns).
up_threshold: defines what the average CPU usage between the samplings up_threshold: defines what the average CPU usage between the samplings
of 'sampling_rate' needs to be for the kernel to make a decision on of 'sampling_rate' needs to be for the kernel to make a decision on
......
...@@ -152,6 +152,18 @@ cpuinfo_min_freq : this file shows the minimum operating ...@@ -152,6 +152,18 @@ cpuinfo_min_freq : this file shows the minimum operating
frequency the processor can run at(in kHz) frequency the processor can run at(in kHz)
cpuinfo_max_freq : this file shows the maximum operating cpuinfo_max_freq : this file shows the maximum operating
frequency the processor can run at(in kHz) frequency the processor can run at(in kHz)
cpuinfo_transition_latency The time it takes on this CPU to
switch between two frequencies in nano
seconds. If unknown or known to be
that high that the driver does not
work with the ondemand governor, -1
(CPUFREQ_ETERNAL) will be returned.
Using this information can be useful
to choose an appropriate polling
frequency for a kernel governor or
userspace daemon. Make sure to not
switch the frequency too often
resulting in performance loss.
scaling_driver : this file shows what cpufreq driver is scaling_driver : this file shows what cpufreq driver is
used to set the frequency on this CPU used to set the frequency on this CPU
......
...@@ -11,8 +11,8 @@ unsigned long native_calibrate_tsc(void); ...@@ -11,8 +11,8 @@ unsigned long native_calibrate_tsc(void);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
extern int timer_ack; extern int timer_ack;
#endif
extern int recalibrate_cpu_khz(void); extern int recalibrate_cpu_khz(void);
#endif /* CONFIG_X86_32 */
extern int no_timer_check; extern int no_timer_check;
......
...@@ -87,30 +87,15 @@ config X86_POWERNOW_K7_ACPI ...@@ -87,30 +87,15 @@ config X86_POWERNOW_K7_ACPI
config X86_POWERNOW_K8 config X86_POWERNOW_K8
tristate "AMD Opteron/Athlon64 PowerNow!" tristate "AMD Opteron/Athlon64 PowerNow!"
select CPU_FREQ_TABLE select CPU_FREQ_TABLE
depends on ACPI && ACPI_PROCESSOR
help help
This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors. This adds the CPUFreq driver for K8/K10 Opteron/Athlon64 processors.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called powernow-k8. module will be called powernow-k8.
For details, take a look at <file:Documentation/cpu-freq/>. For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
config X86_POWERNOW_K8_ACPI
bool
prompt "ACPI Support" if X86_32
depends on ACPI && X86_POWERNOW_K8 && ACPI_PROCESSOR
depends on !(X86_POWERNOW_K8 = y && ACPI_PROCESSOR = m)
default y
help
This provides access to the K8s Processor Performance States via ACPI.
This driver is probably required for CPUFreq to work with multi-socket and
SMP systems. It is not required on at least some single-socket yet
multi-core systems, even if SMP is enabled.
It is safe to say Y here.
config X86_GX_SUSPMOD config X86_GX_SUSPMOD
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation" tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
depends on X86_32 && PCI depends on X86_32 && PCI
......
# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
# K8 systems. ACPI is preferred to all other hardware-specific drivers.
# speedstep-* is preferred over p4-clockmod.
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
...@@ -10,7 +15,6 @@ obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o ...@@ -10,7 +15,6 @@ obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
/* /*
* acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $) * acpi-cpufreq.c - ACPI Processor P-States Driver
* *
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
...@@ -36,16 +36,18 @@ ...@@ -36,16 +36,18 @@
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#include <asm/io.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"acpi-cpufreq", msg)
MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
MODULE_DESCRIPTION("ACPI Processor P-States Driver"); MODULE_DESCRIPTION("ACPI Processor P-States Driver");
...@@ -95,7 +97,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) ...@@ -95,7 +97,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
perf = data->acpi_data; perf = data->acpi_data;
for (i=0; i<perf->state_count; i++) { for (i = 0; i < perf->state_count; i++) {
if (value == perf->states[i].status) if (value == perf->states[i].status)
return data->freq_table[i].frequency; return data->freq_table[i].frequency;
} }
...@@ -110,7 +112,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) ...@@ -110,7 +112,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
msr &= INTEL_MSR_RANGE; msr &= INTEL_MSR_RANGE;
perf = data->acpi_data; perf = data->acpi_data;
for (i=0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (msr == perf->states[data->freq_table[i].index].status) if (msr == perf->states[data->freq_table[i].index].status)
return data->freq_table[i].frequency; return data->freq_table[i].frequency;
} }
...@@ -138,15 +140,13 @@ struct io_addr { ...@@ -138,15 +140,13 @@ struct io_addr {
u8 bit_width; u8 bit_width;
}; };
typedef union {
struct msr_addr msr;
struct io_addr io;
} drv_addr_union;
struct drv_cmd { struct drv_cmd {
unsigned int type; unsigned int type;
const struct cpumask *mask; const struct cpumask *mask;
drv_addr_union addr; union {
struct msr_addr msr;
struct io_addr io;
} addr;
u32 val; u32 val;
}; };
...@@ -369,7 +369,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, ...@@ -369,7 +369,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
unsigned int cur_freq; unsigned int cur_freq;
unsigned int i; unsigned int i;
for (i=0; i<100; i++) { for (i = 0; i < 100; i++) {
cur_freq = extract_freq(get_cur_val(mask), data); cur_freq = extract_freq(get_cur_val(mask), data);
if (cur_freq == freq) if (cur_freq == freq)
return 1; return 1;
...@@ -494,7 +494,7 @@ acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) ...@@ -494,7 +494,7 @@ acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
unsigned long freq; unsigned long freq;
unsigned long freqn = perf->states[0].core_frequency * 1000; unsigned long freqn = perf->states[0].core_frequency * 1000;
for (i=0; i<(perf->state_count-1); i++) { for (i = 0; i < (perf->state_count-1); i++) {
freq = freqn; freq = freqn;
freqn = perf->states[i+1].core_frequency * 1000; freqn = perf->states[i+1].core_frequency * 1000;
if ((2 * cpu_khz) > (freqn + freq)) { if ((2 * cpu_khz) > (freqn + freq)) {
...@@ -673,7 +673,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -673,7 +673,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* detect transition latency */ /* detect transition latency */
policy->cpuinfo.transition_latency = 0; policy->cpuinfo.transition_latency = 0;
for (i=0; i<perf->state_count; i++) { for (i = 0; i < perf->state_count; i++) {
if ((perf->states[i].transition_latency * 1000) > if ((perf->states[i].transition_latency * 1000) >
policy->cpuinfo.transition_latency) policy->cpuinfo.transition_latency)
policy->cpuinfo.transition_latency = policy->cpuinfo.transition_latency =
...@@ -682,8 +682,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -682,8 +682,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
data->max_freq = perf->states[0].core_frequency * 1000; data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */ /* table init */
for (i=0; i<perf->state_count; i++) { for (i = 0; i < perf->state_count; i++) {
if (i>0 && perf->states[i].core_frequency >= if (i > 0 && perf->states[i].core_frequency >=
data->freq_table[valid_states-1].frequency / 1000) data->freq_table[valid_states-1].frequency / 1000)
continue; continue;
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* nforce2_chipset: * nforce2_chipset:
* FSB is changed using the chipset * FSB is changed using the chipset
*/ */
static struct pci_dev *nforce2_chipset_dev; static struct pci_dev *nforce2_dev;
/* fid: /* fid:
* multiplier * 10 * multiplier * 10
...@@ -56,7 +56,9 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)"); ...@@ -56,7 +56,9 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
MODULE_PARM_DESC(min_fsb, MODULE_PARM_DESC(min_fsb,
"Minimum FSB to use, if not defined: current FSB - 50"); "Minimum FSB to use, if not defined: current FSB - 50");
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "cpufreq-nforce2", msg) #define PFX "cpufreq-nforce2: "
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"cpufreq-nforce2", msg)
/** /**
* nforce2_calc_fsb - calculate FSB * nforce2_calc_fsb - calculate FSB
...@@ -118,11 +120,11 @@ static void nforce2_write_pll(int pll) ...@@ -118,11 +120,11 @@ static void nforce2_write_pll(int pll)
int temp; int temp;
/* Set the pll addr. to 0x00 */ /* Set the pll addr. to 0x00 */
pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLADR, 0); pci_write_config_dword(nforce2_dev, NFORCE2_PLLADR, 0);
/* Now write the value in all 64 registers */ /* Now write the value in all 64 registers */
for (temp = 0; temp <= 0x3f; temp++) for (temp = 0; temp <= 0x3f; temp++)
pci_write_config_dword(nforce2_chipset_dev, NFORCE2_PLLREG, pll); pci_write_config_dword(nforce2_dev, NFORCE2_PLLREG, pll);
return; return;
} }
...@@ -139,8 +141,8 @@ static unsigned int nforce2_fsb_read(int bootfsb) ...@@ -139,8 +141,8 @@ static unsigned int nforce2_fsb_read(int bootfsb)
u32 fsb, temp = 0; u32 fsb, temp = 0;
/* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */ /* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF,
0x01EF, PCI_ANY_ID, PCI_ANY_ID, NULL); PCI_ANY_ID, PCI_ANY_ID, NULL);
if (!nforce2_sub5) if (!nforce2_sub5)
return 0; return 0;
...@@ -148,13 +150,13 @@ static unsigned int nforce2_fsb_read(int bootfsb) ...@@ -148,13 +150,13 @@ static unsigned int nforce2_fsb_read(int bootfsb)
fsb /= 1000000; fsb /= 1000000;
/* Check if PLL register is already set */ /* Check if PLL register is already set */
pci_read_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8 *)&temp); pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
if (bootfsb || !temp) if (bootfsb || !temp)
return fsb; return fsb;
/* Use PLL register FSB value */ /* Use PLL register FSB value */
pci_read_config_dword(nforce2_chipset_dev, NFORCE2_PLLREG, &temp); pci_read_config_dword(nforce2_dev, NFORCE2_PLLREG, &temp);
fsb = nforce2_calc_fsb(temp); fsb = nforce2_calc_fsb(temp);
return fsb; return fsb;
...@@ -174,18 +176,18 @@ static int nforce2_set_fsb(unsigned int fsb) ...@@ -174,18 +176,18 @@ static int nforce2_set_fsb(unsigned int fsb)
int pll = 0; int pll = 0;
if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) { if ((fsb > max_fsb) || (fsb < NFORCE2_MIN_FSB)) {
printk(KERN_ERR "cpufreq: FSB %d is out of range!\n", fsb); printk(KERN_ERR PFX "FSB %d is out of range!\n", fsb);
return -EINVAL; return -EINVAL;
} }
tfsb = nforce2_fsb_read(0); tfsb = nforce2_fsb_read(0);
if (!tfsb) { if (!tfsb) {
printk(KERN_ERR "cpufreq: Error while reading the FSB\n"); printk(KERN_ERR PFX "Error while reading the FSB\n");
return -EINVAL; return -EINVAL;
} }
/* First write? Then set actual value */ /* First write? Then set actual value */
pci_read_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8 *)&temp); pci_read_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8 *)&temp);
if (!temp) { if (!temp) {
pll = nforce2_calc_pll(tfsb); pll = nforce2_calc_pll(tfsb);
...@@ -197,7 +199,7 @@ static int nforce2_set_fsb(unsigned int fsb) ...@@ -197,7 +199,7 @@ static int nforce2_set_fsb(unsigned int fsb)
/* Enable write access */ /* Enable write access */
temp = 0x01; temp = 0x01;
pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLENABLE, (u8)temp); pci_write_config_byte(nforce2_dev, NFORCE2_PLLENABLE, (u8)temp);
diff = tfsb - fsb; diff = tfsb - fsb;
...@@ -222,7 +224,7 @@ static int nforce2_set_fsb(unsigned int fsb) ...@@ -222,7 +224,7 @@ static int nforce2_set_fsb(unsigned int fsb)
} }
temp = 0x40; temp = 0x40;
pci_write_config_byte(nforce2_chipset_dev, NFORCE2_PLLADR, (u8)temp); pci_write_config_byte(nforce2_dev, NFORCE2_PLLADR, (u8)temp);
return 0; return 0;
} }
...@@ -244,7 +246,8 @@ static unsigned int nforce2_get(unsigned int cpu) ...@@ -244,7 +246,8 @@ static unsigned int nforce2_get(unsigned int cpu)
* nforce2_target - set a new CPUFreq policy * nforce2_target - set a new CPUFreq policy
* @policy: new policy * @policy: new policy
* @target_freq: the target frequency * @target_freq: the target frequency
* @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) * @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.
*/ */
...@@ -276,7 +279,7 @@ static int nforce2_target(struct cpufreq_policy *policy, ...@@ -276,7 +279,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
/* local_irq_save(flags); */ /* local_irq_save(flags); */
if (nforce2_set_fsb(target_fsb) < 0) if (nforce2_set_fsb(target_fsb) < 0)
printk(KERN_ERR "cpufreq: Changing FSB to %d failed\n", printk(KERN_ERR PFX "Changing FSB to %d failed\n",
target_fsb); target_fsb);
else else
dprintk("Changed FSB successfully to %d\n", dprintk("Changed FSB successfully to %d\n",
...@@ -327,8 +330,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) ...@@ -327,8 +330,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
/* FIX: Get FID from CPU */ /* FIX: Get FID from CPU */
if (!fid) { if (!fid) {
if (!cpu_khz) { if (!cpu_khz) {
printk(KERN_WARNING printk(KERN_WARNING PFX
"cpufreq: cpu_khz not set, can't calculate multiplier!\n"); "cpu_khz not set, can't calculate multiplier!\n");
return -ENODEV; return -ENODEV;
} }
...@@ -343,7 +346,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy) ...@@ -343,7 +346,7 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
} }
} }
printk(KERN_INFO "cpufreq: FSB currently at %i MHz, FID %d.%d\n", fsb, printk(KERN_INFO PFX "FSB currently at %i MHz, FID %d.%d\n", fsb,
fid / 10, fid % 10); fid / 10, fid % 10);
/* Set maximum FSB to FSB at boot time */ /* Set maximum FSB to FSB at boot time */
...@@ -392,17 +395,18 @@ static struct cpufreq_driver nforce2_driver = { ...@@ -392,17 +395,18 @@ static struct cpufreq_driver nforce2_driver = {
*/ */
static unsigned int nforce2_detect_chipset(void) static unsigned int nforce2_detect_chipset(void)
{ {
nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NFORCE2, PCI_DEVICE_ID_NVIDIA_NFORCE2,
PCI_ANY_ID, PCI_ANY_ID, NULL); PCI_ANY_ID, PCI_ANY_ID, NULL);
if (nforce2_chipset_dev == NULL) if (nforce2_dev == NULL)
return -ENODEV; return -ENODEV;
printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n", printk(KERN_INFO PFX "Detected nForce2 chipset revision %X\n",
nforce2_chipset_dev->revision); nforce2_dev->revision);
printk(KERN_INFO printk(KERN_INFO PFX
"cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n"); "FSB changing is maybe unstable and can lead to "
"crashes and data loss.\n");
return 0; return 0;
} }
...@@ -420,7 +424,7 @@ static int __init nforce2_init(void) ...@@ -420,7 +424,7 @@ static int __init nforce2_init(void)
/* detect chipset */ /* detect chipset */
if (nforce2_detect_chipset()) { if (nforce2_detect_chipset()) {
printk(KERN_ERR "cpufreq: No nForce2 chipset.\n"); printk(KERN_INFO PFX "No nForce2 chipset.\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -12,12 +12,12 @@ ...@@ -12,12 +12,12 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/timex.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/tsc.h> #include <asm/tsc.h>
#include <asm/timex.h>
#include <asm/io.h>
#include <asm/delay.h>
#define EPS_BRAND_C7M 0 #define EPS_BRAND_C7M 0
#define EPS_BRAND_C7 1 #define EPS_BRAND_C7 1
...@@ -184,7 +184,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -184,7 +184,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
break; break;
} }
switch(brand) { switch (brand) {
case EPS_BRAND_C7M: case EPS_BRAND_C7M:
printk(KERN_CONT "C7-M\n"); printk(KERN_CONT "C7-M\n");
break; break;
...@@ -218,17 +218,20 @@ static int eps_cpu_init(struct cpufreq_policy *policy) ...@@ -218,17 +218,20 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
/* Print voltage and multiplier */ /* Print voltage and multiplier */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi); rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
current_voltage = lo & 0xff; current_voltage = lo & 0xff;
printk(KERN_INFO "eps: Current voltage = %dmV\n", current_voltage * 16 + 700); printk(KERN_INFO "eps: Current voltage = %dmV\n",
current_voltage * 16 + 700);
current_multiplier = (lo >> 8) & 0xff; current_multiplier = (lo >> 8) & 0xff;
printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier); printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier);
/* Print limits */ /* Print limits */
max_voltage = hi & 0xff; max_voltage = hi & 0xff;
printk(KERN_INFO "eps: Highest voltage = %dmV\n", max_voltage * 16 + 700); printk(KERN_INFO "eps: Highest voltage = %dmV\n",
max_voltage * 16 + 700);
max_multiplier = (hi >> 8) & 0xff; max_multiplier = (hi >> 8) & 0xff;
printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier); printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier);
min_voltage = (hi >> 16) & 0xff; min_voltage = (hi >> 16) & 0xff;
printk(KERN_INFO "eps: Lowest voltage = %dmV\n", min_voltage * 16 + 700); printk(KERN_INFO "eps: Lowest voltage = %dmV\n",
min_voltage * 16 + 700);
min_multiplier = (hi >> 24) & 0xff; min_multiplier = (hi >> 24) & 0xff;
printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier); printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier);
...@@ -318,7 +321,7 @@ static int eps_cpu_exit(struct cpufreq_policy *policy) ...@@ -318,7 +321,7 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static struct freq_attr* eps_attr[] = { static struct freq_attr *eps_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -356,7 +359,7 @@ static void __exit eps_exit(void) ...@@ -356,7 +359,7 @@ static void __exit eps_exit(void)
cpufreq_unregister_driver(&eps_driver); cpufreq_unregister_driver(&eps_driver);
} }
MODULE_AUTHOR("Rafa Bilski <rafalbilski@interia.pl>"); MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's."); MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -184,7 +184,8 @@ static int elanfreq_target(struct cpufreq_policy *policy, ...@@ -184,7 +184,8 @@ static int elanfreq_target(struct cpufreq_policy *policy,
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, &elanfreq_table[0],
target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
elanfreq_set_cpu_state(newstate); elanfreq_set_cpu_state(newstate);
...@@ -301,7 +302,8 @@ static void __exit elanfreq_exit(void) ...@@ -301,7 +302,8 @@ static void __exit elanfreq_exit(void)
module_param(max_freq, int, 0444); module_param(max_freq, int, 0444);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>"); MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, "
"Sven Geggus <sven@geggus.net>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
module_init(elanfreq_init); module_init(elanfreq_init);
......
...@@ -79,8 +79,9 @@ ...@@ -79,8 +79,9 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/errno.h>
#include <asm/processor-cyrix.h> #include <asm/processor-cyrix.h>
#include <asm/errno.h>
/* PCI config registers, all at F0 */ /* PCI config registers, all at F0 */
#define PCI_PMER1 0x80 /* power management enable register 1 */ #define PCI_PMER1 0x80 /* power management enable register 1 */
...@@ -122,8 +123,8 @@ static struct gxfreq_params *gx_params; ...@@ -122,8 +123,8 @@ static struct gxfreq_params *gx_params;
static int stock_freq; static int stock_freq;
/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */ /* PCI bus clock - defaults to 30.000 if cpu_khz is not available */
static int pci_busclk = 0; static int pci_busclk;
module_param (pci_busclk, int, 0444); module_param(pci_busclk, int, 0444);
/* maximum duration for which the cpu may be suspended /* maximum duration for which the cpu may be suspended
* (32us * MAX_DURATION). If no parameter is given, this defaults * (32us * MAX_DURATION). If no parameter is given, this defaults
...@@ -132,7 +133,7 @@ module_param (pci_busclk, int, 0444); ...@@ -132,7 +133,7 @@ module_param (pci_busclk, int, 0444);
* is suspended -- processing power is just 0.39% of what it used to be, * is suspended -- processing power is just 0.39% of what it used to be,
* though. 781.25 kHz(!) for a 200 MHz processor -- wow. */ * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */
static int max_duration = 255; static int max_duration = 255;
module_param (max_duration, int, 0444); module_param(max_duration, int, 0444);
/* For the default policy, we want at least some processing power /* For the default policy, we want at least some processing power
* - let's say 5%. (min = maxfreq / POLICY_MIN_DIV) * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV)
...@@ -140,7 +141,8 @@ module_param (max_duration, int, 0444); ...@@ -140,7 +141,8 @@ module_param (max_duration, int, 0444);
#define POLICY_MIN_DIV 20 #define POLICY_MIN_DIV 20
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "gx-suspmod", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"gx-suspmod", msg)
/** /**
* we can detect a core multipiler from dir0_lsb * we can detect a core multipiler from dir0_lsb
...@@ -166,12 +168,20 @@ static int gx_freq_mult[16] = { ...@@ -166,12 +168,20 @@ static int gx_freq_mult[16] = {
* Low Level chipset interface * * Low Level chipset interface *
****************************************************************/ ****************************************************************/
static struct pci_device_id gx_chipset_tbl[] __initdata = { static struct pci_device_id gx_chipset_tbl[] __initdata = {
{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID }, PCI_ANY_ID, PCI_ANY_ID },
{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520,
PCI_ANY_ID, PCI_ANY_ID },
{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510,
PCI_ANY_ID, PCI_ANY_ID },
{ 0, }, { 0, },
}; };
static void gx_write_byte(int reg, int value)
{
pci_write_config_byte(gx_params->cs55x0, reg, value);
}
/** /**
* gx_detect_chipset: * gx_detect_chipset:
* *
...@@ -200,7 +210,8 @@ static __init struct pci_dev *gx_detect_chipset(void) ...@@ -200,7 +210,8 @@ static __init struct pci_dev *gx_detect_chipset(void)
/** /**
* gx_get_cpuspeed: * gx_get_cpuspeed:
* *
* Finds out at which efficient frequency the Cyrix MediaGX/NatSemi Geode CPU runs. * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi
* Geode CPU runs.
*/ */
static unsigned int gx_get_cpuspeed(unsigned int cpu) static unsigned int gx_get_cpuspeed(unsigned int cpu)
{ {
...@@ -217,17 +228,18 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu) ...@@ -217,17 +228,18 @@ static unsigned int gx_get_cpuspeed(unsigned int cpu)
* *
**/ **/
static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration, u8 *off_duration) static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration,
u8 *off_duration)
{ {
unsigned int i; unsigned int i;
u8 tmp_on, tmp_off; u8 tmp_on, tmp_off;
int old_tmp_freq = stock_freq; int old_tmp_freq = stock_freq;
int tmp_freq; int tmp_freq;
*off_duration=1; *off_duration = 1;
*on_duration=0; *on_duration = 0;
for (i=max_duration; i>0; i--) { for (i = max_duration; i > 0; i--) {
tmp_off = ((khz * i) / stock_freq) & 0xff; tmp_off = ((khz * i) / stock_freq) & 0xff;
tmp_on = i - tmp_off; tmp_on = i - tmp_off;
tmp_freq = (stock_freq * tmp_off) / i; tmp_freq = (stock_freq * tmp_off) / i;
...@@ -259,26 +271,34 @@ static void gx_set_cpuspeed(unsigned int khz) ...@@ -259,26 +271,34 @@ static void gx_set_cpuspeed(unsigned int khz)
freqs.cpu = 0; freqs.cpu = 0;
freqs.old = gx_get_cpuspeed(0); freqs.old = gx_get_cpuspeed(0);
new_khz = gx_validate_speed(khz, &gx_params->on_duration, &gx_params->off_duration); new_khz = gx_validate_speed(khz, &gx_params->on_duration,
&gx_params->off_duration);
freqs.new = new_khz; freqs.new = new_khz;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
local_irq_save(flags); local_irq_save(flags);
if (new_khz != stock_freq) { /* if new khz == 100% of CPU speed, it is special case */
if (new_khz != stock_freq) {
/* if new khz == 100% of CPU speed, it is special case */
switch (gx_params->cs55x0->device) { switch (gx_params->cs55x0->device) {
case PCI_DEVICE_ID_CYRIX_5530_LEGACY: case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP; pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
/* FIXME: need to test other values -- Zwane,Miura */ /* FIXME: need to test other values -- Zwane,Miura */
pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */ /* typical 2 to 4ms */
pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */ gx_write_byte(PCI_IRQTC, 4);
pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1); /* typical 50 to 100ms */
gx_write_byte(PCI_VIDTC, 100);
if (gx_params->cs55x0->revision < 0x10) { /* CS5530(rev 1.2, 1.3) */ gx_write_byte(PCI_PMER1, pmer1);
suscfg = gx_params->pci_suscfg | SUSMOD;
} else { /* CS5530A,B.. */ if (gx_params->cs55x0->revision < 0x10) {
suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE; /* CS5530(rev 1.2, 1.3) */
suscfg = gx_params->pci_suscfg|SUSMOD;
} else {
/* CS5530A,B.. */
suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE;
} }
break; break;
case PCI_DEVICE_ID_CYRIX_5520: case PCI_DEVICE_ID_CYRIX_5520:
...@@ -294,13 +314,13 @@ static void gx_set_cpuspeed(unsigned int khz) ...@@ -294,13 +314,13 @@ static void gx_set_cpuspeed(unsigned int khz)
suscfg = gx_params->pci_suscfg & ~(SUSMOD); suscfg = gx_params->pci_suscfg & ~(SUSMOD);
gx_params->off_duration = 0; gx_params->off_duration = 0;
gx_params->on_duration = 0; gx_params->on_duration = 0;
dprintk("suspend modulation disabled: cpu runs 100 percent speed.\n"); dprintk("suspend modulation disabled: cpu runs 100%% speed.\n");
} }
pci_write_config_byte(gx_params->cs55x0, PCI_MODOFF, gx_params->off_duration); gx_write_byte(PCI_MODOFF, gx_params->off_duration);
pci_write_config_byte(gx_params->cs55x0, PCI_MODON, gx_params->on_duration); gx_write_byte(PCI_MODON, gx_params->on_duration);
pci_write_config_byte(gx_params->cs55x0, PCI_SUSCFG, suscfg); gx_write_byte(PCI_SUSCFG, suscfg);
pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg); pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg);
local_irq_restore(flags); local_irq_restore(flags);
...@@ -334,7 +354,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy) ...@@ -334,7 +354,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
return -EINVAL; return -EINVAL;
policy->cpu = 0; policy->cpu = 0;
cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq); cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
stock_freq);
/* it needs to be assured that at least one supported frequency is /* it needs to be assured that at least one supported frequency is
* within policy->min and policy->max. If it is not, policy->max * within policy->min and policy->max. If it is not, policy->max
...@@ -354,7 +375,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy) ...@@ -354,7 +375,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
policy->max = tmp_freq; policy->max = tmp_freq;
if (policy->max < policy->min) if (policy->max < policy->min)
policy->max = policy->min; policy->max = policy->min;
cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq); cpufreq_verify_within_limits(policy, (stock_freq / max_duration),
stock_freq);
return 0; return 0;
} }
...@@ -398,18 +420,18 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) ...@@ -398,18 +420,18 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
return -ENODEV; return -ENODEV;
/* determine maximum frequency */ /* determine maximum frequency */
if (pci_busclk) { if (pci_busclk)
maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} else if (cpu_khz) { else if (cpu_khz)
maxfreq = cpu_khz; maxfreq = cpu_khz;
} else { else
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
}
stock_freq = maxfreq; stock_freq = maxfreq;
curfreq = gx_get_cpuspeed(0); curfreq = gx_get_cpuspeed(0);
dprintk("cpu max frequency is %d.\n", maxfreq); dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq); dprintk("cpu current frequency is %dkHz.\n", curfreq);
/* setup basic struct for cpufreq API */ /* setup basic struct for cpufreq API */
policy->cpu = 0; policy->cpu = 0;
...@@ -447,7 +469,8 @@ static int __init cpufreq_gx_init(void) ...@@ -447,7 +469,8 @@ static int __init cpufreq_gx_init(void)
struct pci_dev *gx_pci; struct pci_dev *gx_pci;
/* Test if we have the right hardware */ /* Test if we have the right hardware */
if ((gx_pci = gx_detect_chipset()) == NULL) gx_pci = gx_detect_chipset();
if (gx_pci == NULL)
return -ENODEV; return -ENODEV;
/* check whether module parameters are sane */ /* check whether module parameters are sane */
...@@ -468,9 +491,11 @@ static int __init cpufreq_gx_init(void) ...@@ -468,9 +491,11 @@ static int __init cpufreq_gx_init(void)
pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1)); pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1));
pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2)); pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration)); pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration)); pci_read_config_byte(params->cs55x0, PCI_MODOFF,
&(params->off_duration));
if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) { ret = cpufreq_register_driver(&gx_suspmod_driver);
if (ret) {
kfree(params); kfree(params);
return ret; /* register error! */ return ret; /* register error! */
} }
...@@ -485,9 +510,9 @@ static void __exit cpufreq_gx_exit(void) ...@@ -485,9 +510,9 @@ static void __exit cpufreq_gx_exit(void)
kfree(gx_params); kfree(gx_params);
} }
MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>"); MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
MODULE_DESCRIPTION ("Cpufreq driver for Cyrix MediaGX and NatSemi Geode"); MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
module_init(cpufreq_gx_init); module_init(cpufreq_gx_init);
module_exit(cpufreq_gx_exit); module_exit(cpufreq_gx_exit);
......
...@@ -30,12 +30,12 @@ ...@@ -30,12 +30,12 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/timex.h>
#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/timex.h>
#include <asm/io.h>
#include <asm/acpi.h>
#include <linux/acpi.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#include "longhaul.h" #include "longhaul.h"
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
#define USE_NORTHBRIDGE (1 << 2) #define USE_NORTHBRIDGE (1 << 2)
static int cpu_model; static int cpu_model;
static unsigned int numscales=16; static unsigned int numscales = 16;
static unsigned int fsb; static unsigned int fsb;
static const struct mV_pos *vrm_mV_table; static const struct mV_pos *vrm_mV_table;
...@@ -67,8 +67,8 @@ static const unsigned char *mV_vrm_table; ...@@ -67,8 +67,8 @@ static const unsigned char *mV_vrm_table;
static unsigned int highest_speed, lowest_speed; /* kHz */ static unsigned int highest_speed, lowest_speed; /* kHz */
static unsigned int minmult, maxmult; static unsigned int minmult, maxmult;
static int can_scale_voltage; static int can_scale_voltage;
static struct acpi_processor *pr = NULL; static struct acpi_processor *pr;
static struct acpi_processor_cx *cx = NULL; static struct acpi_processor_cx *cx;
static u32 acpi_regs_addr; static u32 acpi_regs_addr;
static u8 longhaul_flags; static u8 longhaul_flags;
static unsigned int longhaul_index; static unsigned int longhaul_index;
...@@ -78,12 +78,13 @@ static int scale_voltage; ...@@ -78,12 +78,13 @@ static int scale_voltage;
static int disable_acpi_c3; static int disable_acpi_c3;
static int revid_errata; static int revid_errata;
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"longhaul", msg)
/* Clock ratios multiplied by 10 */ /* Clock ratios multiplied by 10 */
static int clock_ratio[32]; static int mults[32];
static int eblcr_table[32]; static int eblcr[32];
static int longhaul_version; static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table; static struct cpufreq_frequency_table *longhaul_table;
...@@ -93,7 +94,7 @@ static char speedbuffer[8]; ...@@ -93,7 +94,7 @@ static char speedbuffer[8];
static char *print_speed(int speed) static char *print_speed(int speed)
{ {
if (speed < 1000) { if (speed < 1000) {
snprintf(speedbuffer, sizeof(speedbuffer),"%dMHz", speed); snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed);
return speedbuffer; return speedbuffer;
} }
...@@ -122,27 +123,28 @@ static unsigned int calc_speed(int mult) ...@@ -122,27 +123,28 @@ static unsigned int calc_speed(int mult)
static int longhaul_get_cpu_mult(void) static int longhaul_get_cpu_mult(void)
{ {
unsigned long invalue=0,lo, hi; unsigned long invalue = 0, lo, hi;
rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi);
invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22;
if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) { if (longhaul_version == TYPE_LONGHAUL_V2 ||
longhaul_version == TYPE_POWERSAVER) {
if (lo & (1<<27)) if (lo & (1<<27))
invalue+=16; invalue += 16;
} }
return eblcr_table[invalue]; return eblcr[invalue];
} }
/* For processor with BCR2 MSR */ /* For processor with BCR2 MSR */
static void do_longhaul1(unsigned int clock_ratio_index) static void do_longhaul1(unsigned int mults_index)
{ {
union msr_bcr2 bcr2; union msr_bcr2 bcr2;
rdmsrl(MSR_VIA_BCR2, bcr2.val); rdmsrl(MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */ /* Enable software clock multiplier */
bcr2.bits.ESOFTBF = 1; bcr2.bits.ESOFTBF = 1;
bcr2.bits.CLOCKMUL = clock_ratio_index & 0xff; bcr2.bits.CLOCKMUL = mults_index & 0xff;
/* Sync to timer tick */ /* Sync to timer tick */
safe_halt(); safe_halt();
...@@ -161,7 +163,7 @@ static void do_longhaul1(unsigned int clock_ratio_index) ...@@ -161,7 +163,7 @@ static void do_longhaul1(unsigned int clock_ratio_index)
/* For processor with Longhaul MSR */ /* For processor with Longhaul MSR */
static void do_powersaver(int cx_address, unsigned int clock_ratio_index, static void do_powersaver(int cx_address, unsigned int mults_index,
unsigned int dir) unsigned int dir)
{ {
union msr_longhaul longhaul; union msr_longhaul longhaul;
...@@ -173,11 +175,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index, ...@@ -173,11 +175,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
longhaul.bits.RevisionKey = longhaul.bits.RevisionID; longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
else else
longhaul.bits.RevisionKey = 0; longhaul.bits.RevisionKey = 0;
longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; longhaul.bits.SoftBusRatio = mults_index & 0xf;
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4;
/* Setup new voltage */ /* Setup new voltage */
if (can_scale_voltage) if (can_scale_voltage)
longhaul.bits.SoftVID = (clock_ratio_index >> 8) & 0x1f; longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f;
/* Sync to timer tick */ /* Sync to timer tick */
safe_halt(); safe_halt();
/* Raise voltage if necessary */ /* Raise voltage if necessary */
...@@ -240,14 +242,14 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index, ...@@ -240,14 +242,14 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
/** /**
* longhaul_set_cpu_frequency() * longhaul_set_cpu_frequency()
* @clock_ratio_index : bitpattern of the new multiplier. * @mults_index : bitpattern of the new multiplier.
* *
* Sets a new clock ratio. * Sets a new clock ratio.
*/ */
static void longhaul_setstate(unsigned int table_index) static void longhaul_setstate(unsigned int table_index)
{ {
unsigned int clock_ratio_index; unsigned int mults_index;
int speed, mult; int speed, mult;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
unsigned long flags; unsigned long flags;
...@@ -256,9 +258,9 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -256,9 +258,9 @@ static void longhaul_setstate(unsigned int table_index)
u32 bm_timeout = 1000; u32 bm_timeout = 1000;
unsigned int dir = 0; unsigned int dir = 0;
clock_ratio_index = longhaul_table[table_index].index; mults_index = longhaul_table[table_index].index;
/* Safety precautions */ /* Safety precautions */
mult = clock_ratio[clock_ratio_index & 0x1f]; mult = mults[mults_index & 0x1f];
if (mult == -1) if (mult == -1)
return; return;
speed = calc_speed(mult); speed = calc_speed(mult);
...@@ -274,7 +276,7 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -274,7 +276,7 @@ static void longhaul_setstate(unsigned int table_index)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n", dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000)); fsb, mult/10, mult%10, print_speed(speed/1000));
retry_loop: retry_loop:
preempt_disable(); preempt_disable();
...@@ -282,8 +284,8 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -282,8 +284,8 @@ static void longhaul_setstate(unsigned int table_index)
pic2_mask = inb(0xA1); pic2_mask = inb(0xA1);
pic1_mask = inb(0x21); /* works on C3. save mask. */ pic1_mask = inb(0x21); /* works on C3. save mask. */
outb(0xFF,0xA1); /* Overkill */ outb(0xFF, 0xA1); /* Overkill */
outb(0xFE,0x21); /* TMR0 only */ outb(0xFE, 0x21); /* TMR0 only */
/* Wait while PCI bus is busy. */ /* Wait while PCI bus is busy. */
if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
...@@ -312,7 +314,7 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -312,7 +314,7 @@ static void longhaul_setstate(unsigned int table_index)
* Software controlled multipliers only. * Software controlled multipliers only.
*/ */
case TYPE_LONGHAUL_V1: case TYPE_LONGHAUL_V1:
do_longhaul1(clock_ratio_index); do_longhaul1(mults_index);
break; break;
/* /*
...@@ -327,9 +329,9 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -327,9 +329,9 @@ static void longhaul_setstate(unsigned int table_index)
if (longhaul_flags & USE_ACPI_C3) { if (longhaul_flags & USE_ACPI_C3) {
/* Don't allow wakeup */ /* Don't allow wakeup */
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
do_powersaver(cx->address, clock_ratio_index, dir); do_powersaver(cx->address, mults_index, dir);
} else { } else {
do_powersaver(0, clock_ratio_index, dir); do_powersaver(0, mults_index, dir);
} }
break; break;
} }
...@@ -341,8 +343,8 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -341,8 +343,8 @@ static void longhaul_setstate(unsigned int table_index)
/* Enable bus master arbitration */ /* Enable bus master arbitration */
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
} }
outb(pic2_mask,0xA1); /* restore mask */ outb(pic2_mask, 0xA1); /* restore mask */
outb(pic1_mask,0x21); outb(pic1_mask, 0x21);
local_irq_restore(flags); local_irq_restore(flags);
preempt_enable(); preempt_enable();
...@@ -392,7 +394,8 @@ static void longhaul_setstate(unsigned int table_index) ...@@ -392,7 +394,8 @@ static void longhaul_setstate(unsigned int table_index)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
if (!bm_timeout) if (!bm_timeout)
printk(KERN_INFO PFX "Warning: Timeout while waiting for idle PCI bus.\n"); printk(KERN_INFO PFX "Warning: Timeout while waiting for "
"idle PCI bus.\n");
} }
/* /*
...@@ -458,31 +461,32 @@ static int __init longhaul_get_ranges(void) ...@@ -458,31 +461,32 @@ static int __init longhaul_get_ranges(void)
break; break;
} }
dprintk ("MinMult:%d.%dx MaxMult:%d.%dx\n", dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n",
minmult/10, minmult%10, maxmult/10, maxmult%10); minmult/10, minmult%10, maxmult/10, maxmult%10);
highest_speed = calc_speed(maxmult); highest_speed = calc_speed(maxmult);
lowest_speed = calc_speed(minmult); lowest_speed = calc_speed(minmult);
dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, dprintk("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb,
print_speed(lowest_speed/1000), print_speed(lowest_speed/1000),
print_speed(highest_speed/1000)); print_speed(highest_speed/1000));
if (lowest_speed == highest_speed) { if (lowest_speed == highest_speed) {
printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n"); printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n");
return -EINVAL; return -EINVAL;
} }
if (lowest_speed > highest_speed) { if (lowest_speed > highest_speed) {
printk (KERN_INFO PFX "nonsense! lowest (%d > %d) !\n", printk(KERN_INFO PFX "nonsense! lowest (%d > %d) !\n",
lowest_speed, highest_speed); lowest_speed, highest_speed);
return -EINVAL; return -EINVAL;
} }
longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL); longhaul_table = kmalloc((numscales + 1) * sizeof(*longhaul_table),
if(!longhaul_table) GFP_KERNEL);
if (!longhaul_table)
return -ENOMEM; return -ENOMEM;
for (j = 0; j < numscales; j++) { for (j = 0; j < numscales; j++) {
ratio = clock_ratio[j]; ratio = mults[j];
if (ratio == -1) if (ratio == -1)
continue; continue;
if (ratio > maxmult || ratio < minmult) if (ratio > maxmult || ratio < minmult)
...@@ -507,13 +511,10 @@ static int __init longhaul_get_ranges(void) ...@@ -507,13 +511,10 @@ static int __init longhaul_get_ranges(void)
} }
} }
if (min_i != j) { if (min_i != j) {
unsigned int temp; swap(longhaul_table[j].frequency,
temp = longhaul_table[j].frequency; longhaul_table[min_i].frequency);
longhaul_table[j].frequency = longhaul_table[min_i].frequency; swap(longhaul_table[j].index,
longhaul_table[min_i].frequency = temp; longhaul_table[min_i].index);
temp = longhaul_table[j].index;
longhaul_table[j].index = longhaul_table[min_i].index;
longhaul_table[min_i].index = temp;
} }
} }
...@@ -521,7 +522,7 @@ static int __init longhaul_get_ranges(void) ...@@ -521,7 +522,7 @@ static int __init longhaul_get_ranges(void)
/* Find index we are running on */ /* Find index we are running on */
for (j = 0; j < k; j++) { for (j = 0; j < k; j++) {
if (clock_ratio[longhaul_table[j].index & 0x1f] == mult) { if (mults[longhaul_table[j].index & 0x1f] == mult) {
longhaul_index = j; longhaul_index = j;
break; break;
} }
...@@ -559,20 +560,22 @@ static void __init longhaul_setup_voltagescaling(void) ...@@ -559,20 +560,22 @@ static void __init longhaul_setup_voltagescaling(void)
maxvid = vrm_mV_table[longhaul.bits.MaximumVID]; maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) { if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " printk(KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. "
"Voltage scaling disabled.\n", "Voltage scaling disabled.\n",
minvid.mV/1000, minvid.mV%1000, maxvid.mV/1000, maxvid.mV%1000); minvid.mV/1000, minvid.mV%1000,
maxvid.mV/1000, maxvid.mV%1000);
return; return;
} }
if (minvid.mV == maxvid.mV) { if (minvid.mV == maxvid.mV) {
printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are " printk(KERN_INFO PFX "Claims to support voltage scaling but "
"both %d.%03d. Voltage scaling disabled\n", "min & max are both %d.%03d. "
"Voltage scaling disabled\n",
maxvid.mV/1000, maxvid.mV%1000); maxvid.mV/1000, maxvid.mV%1000);
return; return;
} }
/* How many voltage steps */ /* How many voltage steps*/
numvscales = maxvid.pos - minvid.pos + 1; numvscales = maxvid.pos - minvid.pos + 1;
printk(KERN_INFO PFX printk(KERN_INFO PFX
"Max VID=%d.%03d " "Max VID=%d.%03d "
...@@ -586,7 +589,7 @@ static void __init longhaul_setup_voltagescaling(void) ...@@ -586,7 +589,7 @@ static void __init longhaul_setup_voltagescaling(void)
j = longhaul.bits.MinMHzBR; j = longhaul.bits.MinMHzBR;
if (longhaul.bits.MinMHzBR4) if (longhaul.bits.MinMHzBR4)
j += 16; j += 16;
min_vid_speed = eblcr_table[j]; min_vid_speed = eblcr[j];
if (min_vid_speed == -1) if (min_vid_speed == -1)
return; return;
switch (longhaul.bits.MinMHzFSB) { switch (longhaul.bits.MinMHzFSB) {
...@@ -617,7 +620,8 @@ static void __init longhaul_setup_voltagescaling(void) ...@@ -617,7 +620,8 @@ static void __init longhaul_setup_voltagescaling(void)
pos = minvid.pos; pos = minvid.pos;
longhaul_table[j].index |= mV_vrm_table[pos] << 8; longhaul_table[j].index |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]]; vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", speed, j, vid.mV); printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
speed, j, vid.mV);
j++; j++;
} }
...@@ -640,7 +644,8 @@ static int longhaul_target(struct cpufreq_policy *policy, ...@@ -640,7 +644,8 @@ static int longhaul_target(struct cpufreq_policy *policy,
unsigned int dir = 0; unsigned int dir = 0;
u8 vid, current_vid; u8 vid, current_vid;
if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index)) if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq,
relation, &table_index))
return -EINVAL; return -EINVAL;
/* Don't set same frequency again */ /* Don't set same frequency again */
...@@ -656,7 +661,8 @@ static int longhaul_target(struct cpufreq_policy *policy, ...@@ -656,7 +661,8 @@ static int longhaul_target(struct cpufreq_policy *policy,
* this in hardware, C3 is old and we need to do this * this in hardware, C3 is old and we need to do this
* in software. */ * in software. */
i = longhaul_index; i = longhaul_index;
current_vid = (longhaul_table[longhaul_index].index >> 8) & 0x1f; current_vid = (longhaul_table[longhaul_index].index >> 8);
current_vid &= 0x1f;
if (table_index > longhaul_index) if (table_index > longhaul_index)
dir = 1; dir = 1;
while (i != table_index) { while (i != table_index) {
...@@ -691,9 +697,9 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle, ...@@ -691,9 +697,9 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
{ {
struct acpi_device *d; struct acpi_device *d;
if ( acpi_bus_get_device(obj_handle, &d) ) { if (acpi_bus_get_device(obj_handle, &d))
return 0; return 0;
}
*return_value = acpi_driver_data(d); *return_value = acpi_driver_data(d);
return 1; return 1;
} }
...@@ -750,7 +756,7 @@ static int longhaul_setup_southbridge(void) ...@@ -750,7 +756,7 @@ static int longhaul_setup_southbridge(void)
/* Find VT8235 southbridge */ /* Find VT8235 southbridge */
dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
if (dev == NULL) if (dev == NULL)
/* Find VT8237 southbridge */ /* Find VT8237 southbridge */
dev = pci_get_device(PCI_VENDOR_ID_VIA, dev = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_8237, NULL); PCI_DEVICE_ID_VIA_8237, NULL);
if (dev != NULL) { if (dev != NULL) {
...@@ -769,7 +775,8 @@ static int longhaul_setup_southbridge(void) ...@@ -769,7 +775,8 @@ static int longhaul_setup_southbridge(void)
if (pci_cmd & 1 << 7) { if (pci_cmd & 1 << 7) {
pci_read_config_dword(dev, 0x88, &acpi_regs_addr); pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
acpi_regs_addr &= 0xff00; acpi_regs_addr &= 0xff00;
printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", acpi_regs_addr); printk(KERN_INFO PFX "ACPI I/O at 0x%x\n",
acpi_regs_addr);
} }
pci_dev_put(dev); pci_dev_put(dev);
...@@ -781,7 +788,7 @@ static int longhaul_setup_southbridge(void) ...@@ -781,7 +788,7 @@ static int longhaul_setup_southbridge(void)
static int __init longhaul_cpu_init(struct cpufreq_policy *policy) static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{ {
struct cpuinfo_x86 *c = &cpu_data(0); struct cpuinfo_x86 *c = &cpu_data(0);
char *cpuname=NULL; char *cpuname = NULL;
int ret; int ret;
u32 lo, hi; u32 lo, hi;
...@@ -791,8 +798,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -791,8 +798,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
cpu_model = CPU_SAMUEL; cpu_model = CPU_SAMUEL;
cpuname = "C3 'Samuel' [C5A]"; cpuname = "C3 'Samuel' [C5A]";
longhaul_version = TYPE_LONGHAUL_V1; longhaul_version = TYPE_LONGHAUL_V1;
memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio)); memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));
break; break;
case 7: case 7:
...@@ -803,10 +810,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -803,10 +810,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
cpuname = "C3 'Samuel 2' [C5B]"; cpuname = "C3 'Samuel 2' [C5B]";
/* Note, this is not a typo, early Samuel2's had /* Note, this is not a typo, early Samuel2's had
* Samuel1 ratios. */ * Samuel1 ratios. */
memcpy(clock_ratio, samuel1_clock_ratio, memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
sizeof(samuel1_clock_ratio)); memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));
memcpy(eblcr_table, samuel2_eblcr,
sizeof(samuel2_eblcr));
break; break;
case 1 ... 15: case 1 ... 15:
longhaul_version = TYPE_LONGHAUL_V1; longhaul_version = TYPE_LONGHAUL_V1;
...@@ -817,10 +822,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -817,10 +822,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
cpu_model = CPU_EZRA; cpu_model = CPU_EZRA;
cpuname = "C3 'Ezra' [C5C]"; cpuname = "C3 'Ezra' [C5C]";
} }
memcpy(clock_ratio, ezra_clock_ratio, memcpy(mults, ezra_mults, sizeof(ezra_mults));
sizeof(ezra_clock_ratio)); memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));
memcpy(eblcr_table, ezra_eblcr,
sizeof(ezra_eblcr));
break; break;
} }
break; break;
...@@ -829,18 +832,16 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -829,18 +832,16 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
cpu_model = CPU_EZRA_T; cpu_model = CPU_EZRA_T;
cpuname = "C3 'Ezra-T' [C5M]"; cpuname = "C3 'Ezra-T' [C5M]";
longhaul_version = TYPE_POWERSAVER; longhaul_version = TYPE_POWERSAVER;
numscales=32; numscales = 32;
memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio)); memcpy(mults, ezrat_mults, sizeof(ezrat_mults));
memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr)); memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));
break; break;
case 9: case 9:
longhaul_version = TYPE_POWERSAVER; longhaul_version = TYPE_POWERSAVER;
numscales = 32; numscales = 32;
memcpy(clock_ratio, memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
nehemiah_clock_ratio, memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
sizeof(nehemiah_clock_ratio));
memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
switch (c->x86_mask) { switch (c->x86_mask) {
case 0 ... 1: case 0 ... 1:
cpu_model = CPU_NEHEMIAH; cpu_model = CPU_NEHEMIAH;
...@@ -869,14 +870,14 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -869,14 +870,14 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
longhaul_version = TYPE_LONGHAUL_V1; longhaul_version = TYPE_LONGHAUL_V1;
} }
printk (KERN_INFO PFX "VIA %s CPU detected. ", cpuname); printk(KERN_INFO PFX "VIA %s CPU detected. ", cpuname);
switch (longhaul_version) { switch (longhaul_version) {
case TYPE_LONGHAUL_V1: case TYPE_LONGHAUL_V1:
case TYPE_LONGHAUL_V2: case TYPE_LONGHAUL_V2:
printk ("Longhaul v%d supported.\n", longhaul_version); printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version);
break; break;
case TYPE_POWERSAVER: case TYPE_POWERSAVER:
printk ("Powersaver supported.\n"); printk(KERN_CONT "Powersaver supported.\n");
break; break;
}; };
...@@ -940,7 +941,7 @@ static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) ...@@ -940,7 +941,7 @@ static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static struct freq_attr* longhaul_attr[] = { static struct freq_attr *longhaul_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -966,13 +967,15 @@ static int __init longhaul_init(void) ...@@ -966,13 +967,15 @@ static int __init longhaul_init(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (num_online_cpus() > 1) { if (num_online_cpus() > 1) {
printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n"); printk(KERN_ERR PFX "More than 1 CPU detected, "
"longhaul disabled.\n");
return -ENODEV; return -ENODEV;
} }
#endif #endif
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
if (cpu_has_apic) { if (cpu_has_apic) {
printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n"); printk(KERN_ERR PFX "APIC detected. Longhaul is currently "
"broken in this configuration.\n");
return -ENODEV; return -ENODEV;
} }
#endif #endif
...@@ -993,8 +996,8 @@ static void __exit longhaul_exit(void) ...@@ -993,8 +996,8 @@ static void __exit longhaul_exit(void)
{ {
int i; int i;
for (i=0; i < numscales; i++) { for (i = 0; i < numscales; i++) {
if (clock_ratio[i] == maxmult) { if (mults[i] == maxmult) {
longhaul_setstate(i); longhaul_setstate(i);
break; break;
} }
...@@ -1007,11 +1010,11 @@ static void __exit longhaul_exit(void) ...@@ -1007,11 +1010,11 @@ static void __exit longhaul_exit(void)
/* Even if BIOS is exporting ACPI C3 state, and it is used /* Even if BIOS is exporting ACPI C3 state, and it is used
* with success when CPU is idle, this state doesn't * with success when CPU is idle, this state doesn't
* trigger frequency transition in some cases. */ * trigger frequency transition in some cases. */
module_param (disable_acpi_c3, int, 0644); module_param(disable_acpi_c3, int, 0644);
MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support"); MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
/* Change CPU voltage with frequency. Very usefull to save /* Change CPU voltage with frequency. Very usefull to save
* power, but most VIA C3 processors aren't supporting it. */ * power, but most VIA C3 processors aren't supporting it. */
module_param (scale_voltage, int, 0644); module_param(scale_voltage, int, 0644);
MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
/* Force revision key to 0 for processors which doesn't /* Force revision key to 0 for processors which doesn't
* support voltage scaling, but are introducing itself as * support voltage scaling, but are introducing itself as
...@@ -1019,9 +1022,9 @@ MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor"); ...@@ -1019,9 +1022,9 @@ MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
module_param(revid_errata, int, 0644); module_param(revid_errata, int, 0644);
MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID"); MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
MODULE_AUTHOR ("Dave Jones <davej@redhat.com>"); MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
late_initcall(longhaul_init); late_initcall(longhaul_init);
module_exit(longhaul_exit); module_exit(longhaul_exit);
...@@ -49,14 +49,14 @@ union msr_longhaul { ...@@ -49,14 +49,14 @@ union msr_longhaul {
/* /*
* Clock ratio tables. Div/Mod by 10 to get ratio. * Clock ratio tables. Div/Mod by 10 to get ratio.
* The eblcr ones specify the ratio read from the CPU. * The eblcr values specify the ratio read from the CPU.
* The clock_ratio ones specify what to write to the CPU. * The mults values specify what to write to the CPU.
*/ */
/* /*
* VIA C3 Samuel 1 & Samuel 2 (stepping 0) * VIA C3 Samuel 1 & Samuel 2 (stepping 0)
*/ */
static const int __initdata samuel1_clock_ratio[16] = { static const int __initdata samuel1_mults[16] = {
-1, /* 0000 -> RESERVED */ -1, /* 0000 -> RESERVED */
30, /* 0001 -> 3.0x */ 30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */ 40, /* 0010 -> 4.0x */
...@@ -119,7 +119,7 @@ static const int __initdata samuel2_eblcr[16] = { ...@@ -119,7 +119,7 @@ static const int __initdata samuel2_eblcr[16] = {
/* /*
* VIA C3 Ezra * VIA C3 Ezra
*/ */
static const int __initdata ezra_clock_ratio[16] = { static const int __initdata ezra_mults[16] = {
100, /* 0000 -> 10.0x */ 100, /* 0000 -> 10.0x */
30, /* 0001 -> 3.0x */ 30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */ 40, /* 0010 -> 4.0x */
...@@ -160,7 +160,7 @@ static const int __initdata ezra_eblcr[16] = { ...@@ -160,7 +160,7 @@ static const int __initdata ezra_eblcr[16] = {
/* /*
* VIA C3 (Ezra-T) [C5M]. * VIA C3 (Ezra-T) [C5M].
*/ */
static const int __initdata ezrat_clock_ratio[32] = { static const int __initdata ezrat_mults[32] = {
100, /* 0000 -> 10.0x */ 100, /* 0000 -> 10.0x */
30, /* 0001 -> 3.0x */ 30, /* 0001 -> 3.0x */
40, /* 0010 -> 4.0x */ 40, /* 0010 -> 4.0x */
...@@ -235,7 +235,7 @@ static const int __initdata ezrat_eblcr[32] = { ...@@ -235,7 +235,7 @@ static const int __initdata ezrat_eblcr[32] = {
/* /*
* VIA C3 Nehemiah */ * VIA C3 Nehemiah */
static const int __initdata nehemiah_clock_ratio[32] = { static const int __initdata nehemiah_mults[32] = {
100, /* 0000 -> 10.0x */ 100, /* 0000 -> 10.0x */
-1, /* 0001 -> 16.0x */ -1, /* 0001 -> 16.0x */
40, /* 0010 -> 4.0x */ 40, /* 0010 -> 4.0x */
......
...@@ -11,12 +11,13 @@ ...@@ -11,12 +11,13 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/timex.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/timex.h>
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longrun", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"longrun", msg)
static struct cpufreq_driver longrun_driver; static struct cpufreq_driver longrun_driver;
...@@ -51,7 +52,7 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy) ...@@ -51,7 +52,7 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy)
msr_lo &= 0x0000007F; msr_lo &= 0x0000007F;
msr_hi &= 0x0000007F; msr_hi &= 0x0000007F;
if ( longrun_high_freq <= longrun_low_freq ) { if (longrun_high_freq <= longrun_low_freq) {
/* Assume degenerate Longrun table */ /* Assume degenerate Longrun table */
policy->min = policy->max = longrun_high_freq; policy->min = policy->max = longrun_high_freq;
} else { } else {
...@@ -79,7 +80,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy) ...@@ -79,7 +80,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
if (!policy) if (!policy)
return -EINVAL; return -EINVAL;
if ( longrun_high_freq <= longrun_low_freq ) { if (longrun_high_freq <= longrun_low_freq) {
/* Assume degenerate Longrun table */ /* Assume degenerate Longrun table */
pctg_lo = pctg_hi = 100; pctg_lo = pctg_hi = 100;
} else { } else {
...@@ -152,7 +153,7 @@ static unsigned int longrun_get(unsigned int cpu) ...@@ -152,7 +153,7 @@ static unsigned int longrun_get(unsigned int cpu)
cpuid(0x80860007, &eax, &ebx, &ecx, &edx); cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
dprintk("cpuid eax is %u\n", eax); dprintk("cpuid eax is %u\n", eax);
return (eax * 1000); return eax * 1000;
} }
/** /**
...@@ -196,7 +197,8 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, ...@@ -196,7 +197,8 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
*high_freq = msr_lo * 1000; /* to kHz */ *high_freq = msr_lo * 1000; /* to kHz */
dprintk("longrun table interface told %u - %u kHz\n", *low_freq, *high_freq); dprintk("longrun table interface told %u - %u kHz\n",
*low_freq, *high_freq);
if (*low_freq > *high_freq) if (*low_freq > *high_freq)
*low_freq = *high_freq; *low_freq = *high_freq;
...@@ -219,7 +221,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, ...@@ -219,7 +221,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
cpuid(0x80860007, &eax, &ebx, &ecx, &edx); cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
/* try decreasing in 10% steps, some processors react only /* try decreasing in 10% steps, some processors react only
* on some barrier values */ * on some barrier values */
for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -=10) { for (try_hi = 80; try_hi > 0 && ecx > 90; try_hi -= 10) {
/* set to 0 to try_hi perf_pctg */ /* set to 0 to try_hi perf_pctg */
msr_lo &= 0xFFFFFF80; msr_lo &= 0xFFFFFF80;
msr_hi &= 0xFFFFFF80; msr_hi &= 0xFFFFFF80;
...@@ -236,7 +238,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, ...@@ -236,7 +238,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
* eqals * eqals
* low_freq * ( 1 - perf_pctg) = (cur_freq - high_freq * perf_pctg) * low_freq * (1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
* *
* high_freq * perf_pctg is stored tempoarily into "ebx". * high_freq * perf_pctg is stored tempoarily into "ebx".
*/ */
...@@ -317,9 +319,10 @@ static void __exit longrun_exit(void) ...@@ -317,9 +319,10 @@ static void __exit longrun_exit(void)
} }
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe and Efficeon processors."); MODULE_DESCRIPTION("LongRun driver for Transmeta Crusoe and "
MODULE_LICENSE ("GPL"); "Efficeon processors.");
MODULE_LICENSE("GPL");
module_init(longrun_init); module_init(longrun_init);
module_exit(longrun_exit); module_exit(longrun_exit);
...@@ -27,15 +27,17 @@ ...@@ -27,15 +27,17 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/timex.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/timex.h> #include <asm/timer.h>
#include "speedstep-lib.h" #include "speedstep-lib.h"
#define PFX "p4-clockmod: " #define PFX "p4-clockmod: "
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "p4-clockmod", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"p4-clockmod", msg)
/* /*
* Duty Cycle (3bits), note DC_DISABLE is not specified in * Duty Cycle (3bits), note DC_DISABLE is not specified in
...@@ -58,7 +60,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) ...@@ -58,7 +60,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
{ {
u32 l, h; u32 l, h;
if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) if (!cpu_online(cpu) ||
(newstate > DC_DISABLE) || (newstate == DC_RESV))
return -EINVAL; return -EINVAL;
rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
...@@ -66,7 +69,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) ...@@ -66,7 +69,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
if (l & 0x01) if (l & 0x01)
dprintk("CPU#%d currently thermal throttled\n", cpu); dprintk("CPU#%d currently thermal throttled\n", cpu);
if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) if (has_N44_O17_errata[cpu] &&
(newstate == DC_25PT || newstate == DC_DFLT))
newstate = DC_38PT; newstate = DC_38PT;
rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
...@@ -112,7 +116,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, ...@@ -112,7 +116,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
int i; int i;
if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0],
target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
freqs.old = cpufreq_p4_get(policy->cpu); freqs.old = cpufreq_p4_get(policy->cpu);
...@@ -127,7 +132,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, ...@@ -127,7 +132,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
} }
/* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software /* run on each logical CPU,
* see section 13.15.3 of IA32 Intel Architecture Software
* Developer's Manual, Volume 3 * Developer's Manual, Volume 3
*/ */
for_each_cpu(i, policy->cpus) for_each_cpu(i, policy->cpus)
...@@ -153,28 +159,30 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -153,28 +159,30 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{ {
if (c->x86 == 0x06) { if (c->x86 == 0x06) {
if (cpu_has(c, X86_FEATURE_EST)) if (cpu_has(c, X86_FEATURE_EST))
printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. " printk(KERN_WARNING PFX "Warning: EST-capable CPU "
"The acpi-cpufreq module offers voltage scaling" "detected. The acpi-cpufreq module offers "
" in addition of frequency scaling. You should use " "voltage scaling in addition of frequency "
"that instead of p4-clockmod, if possible.\n"); "scaling. You should use that instead of "
"p4-clockmod, if possible.\n");
switch (c->x86_model) { switch (c->x86_model) {
case 0x0E: /* Core */ case 0x0E: /* Core */
case 0x0F: /* Core Duo */ case 0x0F: /* Core Duo */
case 0x16: /* Celeron Core */ case 0x16: /* Celeron Core */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PCORE); return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE);
case 0x0D: /* Pentium M (Dothan) */ case 0x0D: /* Pentium M (Dothan) */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
/* fall through */ /* fall through */
case 0x09: /* Pentium M (Banias) */ case 0x09: /* Pentium M (Banias) */
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); return speedstep_get_frequency(SPEEDSTEP_CPU_PM);
} }
} }
if (c->x86 != 0xF) { if (c->x86 != 0xF) {
if (!cpu_has(c, X86_FEATURE_EST)) if (!cpu_has(c, X86_FEATURE_EST))
printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. " printk(KERN_WARNING PFX "Unknown CPU. "
"Please send an e-mail to <cpufreq@vger.kernel.org>\n"); "Please send an e-mail to "
"<cpufreq@vger.kernel.org>\n");
return 0; return 0;
} }
...@@ -182,16 +190,16 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -182,16 +190,16 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
* throttling is active or not. */ * throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) { if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4M) {
printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
"The speedstep-ich or acpi cpufreq modules offer " "The speedstep-ich or acpi cpufreq modules offer "
"voltage scaling in addition of frequency scaling. " "voltage scaling in addition of frequency scaling. "
"You should use either one instead of p4-clockmod, " "You should use either one instead of p4-clockmod, "
"if possible.\n"); "if possible.\n");
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M); return speedstep_get_frequency(SPEEDSTEP_CPU_P4M);
} }
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4D); return speedstep_get_frequency(SPEEDSTEP_CPU_P4D);
} }
...@@ -217,14 +225,20 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) ...@@ -217,14 +225,20 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
dprintk("has errata -- disabling low frequencies\n"); dprintk("has errata -- disabling low frequencies\n");
} }
if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D &&
c->x86_model < 2) {
/* switch to maximum frequency and measure result */
cpufreq_p4_setdc(policy->cpu, DC_DISABLE);
recalibrate_cpu_khz();
}
/* get max frequency */ /* get max frequency */
stock_freq = cpufreq_p4_get_frequency(c); stock_freq = cpufreq_p4_get_frequency(c);
if (!stock_freq) if (!stock_freq)
return -EINVAL; return -EINVAL;
/* table init */ /* table init */
for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { for (i = 1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
if ((i<2) && (has_N44_O17_errata[policy->cpu])) if ((i < 2) && (has_N44_O17_errata[policy->cpu]))
p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
else else
p4clockmod_table[i].frequency = (stock_freq * i)/8; p4clockmod_table[i].frequency = (stock_freq * i)/8;
...@@ -232,7 +246,10 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) ...@@ -232,7 +246,10 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu); cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
policy->cpuinfo.transition_latency = 1000000; /* assumed */
/* the transition latency is set to be 1 higher than the maximum
* transition latency of the ondemand governor */
policy->cpuinfo.transition_latency = 10000001;
policy->cur = stock_freq; policy->cur = stock_freq;
return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]); return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]);
...@@ -258,12 +275,12 @@ static unsigned int cpufreq_p4_get(unsigned int cpu) ...@@ -258,12 +275,12 @@ static unsigned int cpufreq_p4_get(unsigned int cpu)
l = DC_DISABLE; l = DC_DISABLE;
if (l != DC_DISABLE) if (l != DC_DISABLE)
return (stock_freq * l / 8); return stock_freq * l / 8;
return stock_freq; return stock_freq;
} }
static struct freq_attr* p4clockmod_attr[] = { static struct freq_attr *p4clockmod_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -298,9 +315,10 @@ static int __init cpufreq_p4_init(void) ...@@ -298,9 +315,10 @@ static int __init cpufreq_p4_init(void)
ret = cpufreq_register_driver(&p4clockmod_driver); ret = cpufreq_register_driver(&p4clockmod_driver);
if (!ret) if (!ret)
printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n"); printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock "
"Modulation available\n");
return (ret); return ret;
} }
...@@ -310,9 +328,9 @@ static void __exit cpufreq_p4_exit(void) ...@@ -310,9 +328,9 @@ static void __exit cpufreq_p4_exit(void)
} }
MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>"); MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); MODULE_DESCRIPTION("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
late_initcall(cpufreq_p4_init); late_initcall(cpufreq_p4_init);
module_exit(cpufreq_p4_exit); module_exit(cpufreq_p4_exit);
/* /*
* This file was based upon code in Powertweak Linux (http://powertweak.sf.net) * This file was based upon code in Powertweak Linux (http://powertweak.sf.net)
* (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pänkälä, Dominik Brodowski. * (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pänkälä,
* Dominik Brodowski.
* *
* Licensed under the terms of the GNU GPL License version 2. * Licensed under the terms of the GNU GPL License version 2.
* *
...@@ -13,14 +14,15 @@ ...@@ -13,14 +14,15 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/msr.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/msr.h>
#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long #define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
as it is unused */ as it is unused */
#define PFX "powernow-k6: "
static unsigned int busfreq; /* FSB, in 10 kHz */ static unsigned int busfreq; /* FSB, in 10 kHz */
static unsigned int max_multiplier; static unsigned int max_multiplier;
...@@ -47,8 +49,8 @@ static struct cpufreq_frequency_table clock_ratio[] = { ...@@ -47,8 +49,8 @@ static struct cpufreq_frequency_table clock_ratio[] = {
*/ */
static int powernow_k6_get_cpu_multiplier(void) static int powernow_k6_get_cpu_multiplier(void)
{ {
u64 invalue = 0; u64 invalue = 0;
u32 msrval; u32 msrval;
msrval = POWERNOW_IOPORT + 0x1; msrval = POWERNOW_IOPORT + 0x1;
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
...@@ -68,12 +70,12 @@ static int powernow_k6_get_cpu_multiplier(void) ...@@ -68,12 +70,12 @@ static int powernow_k6_get_cpu_multiplier(void)
*/ */
static void powernow_k6_set_state(unsigned int best_i) static void powernow_k6_set_state(unsigned int best_i)
{ {
unsigned long outvalue = 0, invalue = 0; unsigned long outvalue = 0, invalue = 0;
unsigned long msrval; unsigned long msrval;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
if (clock_ratio[best_i].index > max_multiplier) { if (clock_ratio[best_i].index > max_multiplier) {
printk(KERN_ERR "cpufreq: invalid target frequency\n"); printk(KERN_ERR PFX "invalid target frequency\n");
return; return;
} }
...@@ -119,7 +121,8 @@ static int powernow_k6_verify(struct cpufreq_policy *policy) ...@@ -119,7 +121,8 @@ 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 * @target_freq: the target frequency
* @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) * @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
*/ */
...@@ -127,9 +130,10 @@ static int powernow_k6_target(struct cpufreq_policy *policy, ...@@ -127,9 +130,10 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
if (cpufreq_frequency_table_target(policy, &clock_ratio[0], target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, &clock_ratio[0],
target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
powernow_k6_set_state(newstate); powernow_k6_set_state(newstate);
...@@ -140,7 +144,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy, ...@@ -140,7 +144,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
static int powernow_k6_cpu_init(struct cpufreq_policy *policy) static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{ {
unsigned int i; unsigned int i, f;
int result; int result;
if (policy->cpu != 0) if (policy->cpu != 0)
...@@ -152,10 +156,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) ...@@ -152,10 +156,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
/* table init */ /* table init */
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
if (clock_ratio[i].index > max_multiplier) f = clock_ratio[i].index;
if (f > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID; clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
else else
clock_ratio[i].frequency = busfreq * clock_ratio[i].index; clock_ratio[i].frequency = busfreq * f;
} }
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
...@@ -185,7 +190,9 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy) ...@@ -185,7 +190,9 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
static unsigned int powernow_k6_get(unsigned int cpu) static unsigned int powernow_k6_get(unsigned int cpu)
{ {
return busfreq * powernow_k6_get_cpu_multiplier(); unsigned int ret;
ret = (busfreq * powernow_k6_get_cpu_multiplier());
return ret;
} }
static struct freq_attr *powernow_k6_attr[] = { static struct freq_attr *powernow_k6_attr[] = {
...@@ -221,7 +228,7 @@ static int __init powernow_k6_init(void) ...@@ -221,7 +228,7 @@ static int __init powernow_k6_init(void)
return -ENODEV; return -ENODEV;
if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) { if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
printk("cpufreq: PowerNow IOPORT region already used.\n"); printk(KERN_INFO PFX "PowerNow IOPORT region already used.\n");
return -EIO; return -EIO;
} }
...@@ -246,7 +253,8 @@ static void __exit powernow_k6_exit(void) ...@@ -246,7 +253,8 @@ static void __exit powernow_k6_exit(void)
} }
MODULE_AUTHOR("Arjan van de Ven, Dave Jones <davej@redhat.com>, Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR("Arjan van de Ven, Dave Jones <davej@redhat.com>, "
"Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors."); MODULE_DESCRIPTION("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
* Licensed under the terms of the GNU GPL License version 2. * Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by AMD. * Based upon datasheets & sample CPUs kindly provided by AMD.
* *
* Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt. * Errata 5:
* - We cli/sti on stepping A0 CPUs around the FID/VID transition. * CPU may fail to execute a FID/VID change in presence of interrupt.
* Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect. * - We cli/sti on stepping A0 CPUs around the FID/VID transition.
* - We disable half multipliers if ACPI is used on A0 stepping CPUs. * Errata 15:
* CPU with half frequency multipliers may hang upon wakeup from disconnect.
* - We disable half multipliers if ACPI is used on A0 stepping CPUs.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -20,11 +22,11 @@ ...@@ -20,11 +22,11 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/timex.h>
#include <linux/io.h>
#include <asm/timer.h> /* Needed for recalibrate_cpu_khz() */
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/timer.h>
#include <asm/timex.h>
#include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#ifdef CONFIG_X86_POWERNOW_K7_ACPI #ifdef CONFIG_X86_POWERNOW_K7_ACPI
...@@ -58,9 +60,9 @@ struct pst_s { ...@@ -58,9 +60,9 @@ struct pst_s {
union powernow_acpi_control_t { union powernow_acpi_control_t {
struct { struct {
unsigned long fid:5, unsigned long fid:5,
vid:5, vid:5,
sgtc:20, sgtc:20,
res1:2; res1:2;
} bits; } bits;
unsigned long val; unsigned long val;
}; };
...@@ -94,14 +96,15 @@ static struct cpufreq_frequency_table *powernow_table; ...@@ -94,14 +96,15 @@ static struct cpufreq_frequency_table *powernow_table;
static unsigned int can_scale_bus; static unsigned int can_scale_bus;
static unsigned int can_scale_vid; static unsigned int can_scale_vid;
static unsigned int minimum_speed=-1; static unsigned int minimum_speed = -1;
static unsigned int maximum_speed; static unsigned int maximum_speed;
static unsigned int number_scales; static unsigned int number_scales;
static unsigned int fsb; static unsigned int fsb;
static unsigned int latency; static unsigned int latency;
static char have_a0; static char have_a0;
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k7", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"powernow-k7", msg)
static int check_fsb(unsigned int fsbspeed) static int check_fsb(unsigned int fsbspeed)
{ {
...@@ -109,7 +112,7 @@ static int check_fsb(unsigned int fsbspeed) ...@@ -109,7 +112,7 @@ static int check_fsb(unsigned int fsbspeed)
unsigned int f = fsb / 1000; unsigned int f = fsb / 1000;
delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed; delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
return (delta < 5); return delta < 5;
} }
static int check_powernow(void) static int check_powernow(void)
...@@ -117,24 +120,26 @@ static int check_powernow(void) ...@@ -117,24 +120,26 @@ static int check_powernow(void)
struct cpuinfo_x86 *c = &cpu_data(0); struct cpuinfo_x86 *c = &cpu_data(0);
unsigned int maxei, eax, ebx, ecx, edx; unsigned int maxei, eax, ebx, ecx, edx;
if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 !=6)) { if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) {
#ifdef MODULE #ifdef MODULE
printk (KERN_INFO PFX "This module only works with AMD K7 CPUs\n"); printk(KERN_INFO PFX "This module only works with "
"AMD K7 CPUs\n");
#endif #endif
return 0; return 0;
} }
/* 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 #ifdef MODULE
printk (KERN_INFO PFX "No powernow capabilities detected\n"); printk(KERN_INFO PFX "No powernow capabilities detected\n");
#endif #endif
return 0; return 0;
} }
if ((c->x86_model == 6) && (c->x86_mask == 0)) { if ((c->x86_model == 6) && (c->x86_mask == 0)) {
printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n"); printk(KERN_INFO PFX "K7 660[A0] core detected, "
"enabling errata workarounds\n");
have_a0 = 1; have_a0 = 1;
} }
...@@ -144,37 +149,42 @@ static int check_powernow(void) ...@@ -144,37 +149,42 @@ static int check_powernow(void)
if (!(edx & (1 << 1 | 1 << 2))) if (!(edx & (1 << 1 | 1 << 2)))
return 0; return 0;
printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
if (edx & 1 << 1) { if (edx & 1 << 1) {
printk ("frequency"); printk("frequency");
can_scale_bus=1; can_scale_bus = 1;
} }
if ((edx & (1 << 1 | 1 << 2)) == 0x6) if ((edx & (1 << 1 | 1 << 2)) == 0x6)
printk (" and "); printk(" and ");
if (edx & 1 << 2) { if (edx & 1 << 2) {
printk ("voltage"); printk("voltage");
can_scale_vid=1; can_scale_vid = 1;
} }
printk (".\n"); printk(".\n");
return 1; return 1;
} }
static void invalidate_entry(unsigned int entry)
{
powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
}
static int get_ranges (unsigned char *pst) static int get_ranges(unsigned char *pst)
{ {
unsigned int j; unsigned int j;
unsigned int speed; unsigned int speed;
u8 fid, vid; u8 fid, vid;
powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
(number_scales + 1)), GFP_KERNEL);
if (!powernow_table) if (!powernow_table)
return -ENOMEM; return -ENOMEM;
for (j=0 ; j < number_scales; j++) { for (j = 0 ; j < number_scales; j++) {
fid = *pst++; fid = *pst++;
powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10; powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
...@@ -182,10 +192,10 @@ static int get_ranges (unsigned char *pst) ...@@ -182,10 +192,10 @@ static int get_ranges (unsigned char *pst)
speed = powernow_table[j].frequency; speed = powernow_table[j].frequency;
if ((fid_codes[fid] % 10)==5) { if ((fid_codes[fid] % 10) == 5) {
#ifdef CONFIG_X86_POWERNOW_K7_ACPI #ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (have_a0 == 1) if (have_a0 == 1)
powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; invalidate_entry(j);
#endif #endif
} }
...@@ -197,7 +207,7 @@ static int get_ranges (unsigned char *pst) ...@@ -197,7 +207,7 @@ static int get_ranges (unsigned char *pst)
vid = *pst++; vid = *pst++;
powernow_table[j].index |= (vid << 8); /* upper 8 bits */ powernow_table[j].index |= (vid << 8); /* upper 8 bits */
dprintk (" FID: 0x%x (%d.%dx [%dMHz]) " dprintk(" FID: 0x%x (%d.%dx [%dMHz]) "
"VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
fid_codes[fid] % 10, speed/1000, vid, fid_codes[fid] % 10, speed/1000, vid,
mobile_vid_table[vid]/1000, mobile_vid_table[vid]/1000,
...@@ -214,13 +224,13 @@ static void change_FID(int fid) ...@@ -214,13 +224,13 @@ static void change_FID(int fid)
{ {
union msr_fidvidctl fidvidctl; union msr_fidvidctl fidvidctl;
rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
if (fidvidctl.bits.FID != fid) { if (fidvidctl.bits.FID != fid) {
fidvidctl.bits.SGTC = latency; fidvidctl.bits.SGTC = latency;
fidvidctl.bits.FID = fid; fidvidctl.bits.FID = fid;
fidvidctl.bits.VIDC = 0; fidvidctl.bits.VIDC = 0;
fidvidctl.bits.FIDC = 1; fidvidctl.bits.FIDC = 1;
wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
} }
} }
...@@ -229,18 +239,18 @@ static void change_VID(int vid) ...@@ -229,18 +239,18 @@ static void change_VID(int vid)
{ {
union msr_fidvidctl fidvidctl; union msr_fidvidctl fidvidctl;
rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); rdmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
if (fidvidctl.bits.VID != vid) { if (fidvidctl.bits.VID != vid) {
fidvidctl.bits.SGTC = latency; fidvidctl.bits.SGTC = latency;
fidvidctl.bits.VID = vid; fidvidctl.bits.VID = vid;
fidvidctl.bits.FIDC = 0; fidvidctl.bits.FIDC = 0;
fidvidctl.bits.VIDC = 1; fidvidctl.bits.VIDC = 1;
wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); wrmsrl(MSR_K7_FID_VID_CTL, fidvidctl.val);
} }
} }
static void change_speed (unsigned int index) static void change_speed(unsigned int index)
{ {
u8 fid, vid; u8 fid, vid;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
...@@ -257,7 +267,7 @@ static void change_speed (unsigned int index) ...@@ -257,7 +267,7 @@ static void change_speed (unsigned int index)
freqs.cpu = 0; freqs.cpu = 0;
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
cfid = fidvidstatus.bits.CFID; cfid = fidvidstatus.bits.CFID;
freqs.old = fsb * fid_codes[cfid] / 10; freqs.old = fsb * fid_codes[cfid] / 10;
...@@ -321,12 +331,14 @@ static int powernow_acpi_init(void) ...@@ -321,12 +331,14 @@ static int powernow_acpi_init(void)
goto err1; goto err1;
} }
if (acpi_processor_perf->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { if (acpi_processor_perf->control_register.space_id !=
ACPI_ADR_SPACE_FIXED_HARDWARE) {
retval = -ENODEV; retval = -ENODEV;
goto err2; goto err2;
} }
if (acpi_processor_perf->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) { if (acpi_processor_perf->status_register.space_id !=
ACPI_ADR_SPACE_FIXED_HARDWARE) {
retval = -ENODEV; retval = -ENODEV;
goto err2; goto err2;
} }
...@@ -338,7 +350,8 @@ static int powernow_acpi_init(void) ...@@ -338,7 +350,8 @@ static int powernow_acpi_init(void)
goto err2; goto err2;
} }
powernow_table = kzalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL); powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
(number_scales + 1)), GFP_KERNEL);
if (!powernow_table) { if (!powernow_table) {
retval = -ENOMEM; retval = -ENOMEM;
goto err2; goto err2;
...@@ -352,7 +365,7 @@ static int powernow_acpi_init(void) ...@@ -352,7 +365,7 @@ static int powernow_acpi_init(void)
unsigned int speed, speed_mhz; unsigned int speed, speed_mhz;
pc.val = (unsigned long) state->control; pc.val = (unsigned long) state->control;
dprintk ("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n", dprintk("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
i, i,
(u32) state->core_frequency, (u32) state->core_frequency,
(u32) state->power, (u32) state->power,
...@@ -381,12 +394,12 @@ static int powernow_acpi_init(void) ...@@ -381,12 +394,12 @@ static int powernow_acpi_init(void)
if (speed % 1000 > 0) if (speed % 1000 > 0)
speed_mhz++; speed_mhz++;
if ((fid_codes[fid] % 10)==5) { if ((fid_codes[fid] % 10) == 5) {
if (have_a0 == 1) if (have_a0 == 1)
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; invalidate_entry(i);
} }
dprintk (" FID: 0x%x (%d.%dx [%dMHz]) " dprintk(" FID: 0x%x (%d.%dx [%dMHz]) "
"VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10, "VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
fid_codes[fid] % 10, speed_mhz, vid, fid_codes[fid] % 10, speed_mhz, vid,
mobile_vid_table[vid]/1000, mobile_vid_table[vid]/1000,
...@@ -422,7 +435,8 @@ static int powernow_acpi_init(void) ...@@ -422,7 +435,8 @@ static int powernow_acpi_init(void)
err05: err05:
kfree(acpi_processor_perf); kfree(acpi_processor_perf);
err0: err0:
printk(KERN_WARNING PFX "ACPI perflib can not be used in this platform\n"); printk(KERN_WARNING PFX "ACPI perflib can not be used on "
"this platform\n");
acpi_processor_perf = NULL; acpi_processor_perf = NULL;
return retval; return retval;
} }
...@@ -435,7 +449,14 @@ static int powernow_acpi_init(void) ...@@ -435,7 +449,14 @@ static int powernow_acpi_init(void)
} }
#endif #endif
static int powernow_decode_bios (int maxfid, int startvid) static void print_pst_entry(struct pst_s *pst, unsigned int j)
{
dprintk("PST:%d (@%p)\n", j, pst);
dprintk(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
}
static int powernow_decode_bios(int maxfid, int startvid)
{ {
struct psb_s *psb; struct psb_s *psb;
struct pst_s *pst; struct pst_s *pst;
...@@ -446,61 +467,67 @@ static int powernow_decode_bios (int maxfid, int startvid) ...@@ -446,61 +467,67 @@ static int powernow_decode_bios (int maxfid, int startvid)
etuple = cpuid_eax(0x80000001); etuple = cpuid_eax(0x80000001);
for (i=0xC0000; i < 0xffff0 ; i+=16) { for (i = 0xC0000; i < 0xffff0 ; i += 16) {
p = phys_to_virt(i); p = phys_to_virt(i);
if (memcmp(p, "AMDK7PNOW!", 10) == 0){ if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
dprintk ("Found PSB header at %p\n", p); dprintk("Found PSB header at %p\n", p);
psb = (struct psb_s *) p; psb = (struct psb_s *) p;
dprintk ("Table version: 0x%x\n", psb->tableversion); dprintk("Table version: 0x%x\n", psb->tableversion);
if (psb->tableversion != 0x12) { if (psb->tableversion != 0x12) {
printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n"); printk(KERN_INFO PFX "Sorry, only v1.2 tables"
" supported right now\n");
return -ENODEV; return -ENODEV;
} }
dprintk ("Flags: 0x%x\n", psb->flags); dprintk("Flags: 0x%x\n", psb->flags);
if ((psb->flags & 1)==0) { if ((psb->flags & 1) == 0)
dprintk ("Mobile voltage regulator\n"); dprintk("Mobile voltage regulator\n");
} else { else
dprintk ("Desktop voltage regulator\n"); dprintk("Desktop voltage regulator\n");
}
latency = psb->settlingtime; latency = psb->settlingtime;
if (latency < 100) { if (latency < 100) {
printk(KERN_INFO PFX "BIOS set settling time to %d microseconds. " printk(KERN_INFO PFX "BIOS set settling time "
"Should be at least 100. Correcting.\n", latency); "to %d microseconds. "
"Should be at least 100. "
"Correcting.\n", latency);
latency = 100; latency = 100;
} }
dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime); dprintk("Settling Time: %d microseconds.\n",
dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst); psb->settlingtime);
dprintk("Has %d PST tables. (Only dumping ones "
"relevant to this CPU).\n",
psb->numpst);
p += sizeof (struct psb_s); p += sizeof(struct psb_s);
pst = (struct pst_s *) p; pst = (struct pst_s *) p;
for (j=0; j<psb->numpst; j++) { for (j = 0; j < psb->numpst; j++) {
pst = (struct pst_s *) p; pst = (struct pst_s *) p;
number_scales = pst->numpstates; number_scales = pst->numpstates;
if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) && if ((etuple == pst->cpuid) &&
(maxfid==pst->maxfid) && (startvid==pst->startvid)) check_fsb(pst->fsbspeed) &&
{ (maxfid == pst->maxfid) &&
dprintk ("PST:%d (@%p)\n", j, pst); (startvid == pst->startvid)) {
dprintk (" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n", print_pst_entry(pst, j);
pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid); p = (char *)pst + sizeof(struct pst_s);
ret = get_ranges(p);
ret = get_ranges ((char *) pst + sizeof (struct pst_s));
return ret; return ret;
} else { } else {
unsigned int k; unsigned int k;
p = (char *) pst + sizeof (struct pst_s); p = (char *)pst + sizeof(struct pst_s);
for (k=0; k<number_scales; k++) for (k = 0; k < number_scales; k++)
p+=2; p += 2;
} }
} }
printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple); printk(KERN_INFO PFX "No PST tables match this cpuid "
printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n"); "(0x%x)\n", etuple);
printk(KERN_INFO PFX "This is indicative of a broken "
"BIOS.\n");
return -EINVAL; return -EINVAL;
} }
...@@ -511,13 +538,14 @@ static int powernow_decode_bios (int maxfid, int startvid) ...@@ -511,13 +538,14 @@ static int powernow_decode_bios (int maxfid, int startvid)
} }
static int powernow_target (struct cpufreq_policy *policy, static int powernow_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int newstate; unsigned int newstate;
if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, powernow_table, target_freq,
relation, &newstate))
return -EINVAL; return -EINVAL;
change_speed(newstate); change_speed(newstate);
...@@ -526,7 +554,7 @@ static int powernow_target (struct cpufreq_policy *policy, ...@@ -526,7 +554,7 @@ static int powernow_target (struct cpufreq_policy *policy,
} }
static int powernow_verify (struct cpufreq_policy *policy) static int powernow_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, powernow_table); return cpufreq_frequency_table_verify(policy, powernow_table);
} }
...@@ -566,18 +594,23 @@ static unsigned int powernow_get(unsigned int cpu) ...@@ -566,18 +594,23 @@ static unsigned int powernow_get(unsigned int cpu)
if (cpu) if (cpu)
return 0; return 0;
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
cfid = fidvidstatus.bits.CFID; cfid = fidvidstatus.bits.CFID;
return (fsb * fid_codes[cfid] / 10); return fsb * fid_codes[cfid] / 10;
} }
static int __init acer_cpufreq_pst(const struct dmi_system_id *d) static int __init acer_cpufreq_pst(const struct dmi_system_id *d)
{ {
printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident); printk(KERN_WARNING PFX
printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n"); "%s laptop with broken PST tables in BIOS detected.\n",
printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n"); d->ident);
printk(KERN_WARNING PFX
"You need to downgrade to 3A21 (09/09/2002), or try a newer "
"BIOS than 3A71 (01/20/2003)\n");
printk(KERN_WARNING PFX
"cpufreq scaling has been disabled as a result of this.\n");
return 0; return 0;
} }
...@@ -598,7 +631,7 @@ static struct dmi_system_id __initdata powernow_dmi_table[] = { ...@@ -598,7 +631,7 @@ static struct dmi_system_id __initdata powernow_dmi_table[] = {
{ } { }
}; };
static int __init powernow_cpu_init (struct cpufreq_policy *policy) static int __init powernow_cpu_init(struct cpufreq_policy *policy)
{ {
union msr_fidvidstatus fidvidstatus; union msr_fidvidstatus fidvidstatus;
int result; int result;
...@@ -606,7 +639,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -606,7 +639,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
if (policy->cpu != 0) if (policy->cpu != 0)
return -ENODEV; return -ENODEV;
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
recalibrate_cpu_khz(); recalibrate_cpu_khz();
...@@ -618,19 +651,21 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -618,19 +651,21 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
dprintk("FSB: %3dMHz\n", fsb/1000); dprintk("FSB: %3dMHz\n", fsb/1000);
if (dmi_check_system(powernow_dmi_table) || acpi_force) { if (dmi_check_system(powernow_dmi_table) || acpi_force) {
printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); printk(KERN_INFO PFX "PSB/PST known to be broken. "
"Trying ACPI instead\n");
result = powernow_acpi_init(); result = powernow_acpi_init();
} else { } else {
result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID); result = powernow_decode_bios(fidvidstatus.bits.MFID,
fidvidstatus.bits.SVID);
if (result) { if (result) {
printk (KERN_INFO PFX "Trying ACPI perflib\n"); printk(KERN_INFO PFX "Trying ACPI perflib\n");
maximum_speed = 0; maximum_speed = 0;
minimum_speed = -1; minimum_speed = -1;
latency = 0; latency = 0;
result = powernow_acpi_init(); result = powernow_acpi_init();
if (result) { if (result) {
printk (KERN_INFO PFX "ACPI and legacy methods failed\n"); printk(KERN_INFO PFX
printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.html\n"); "ACPI and legacy methods failed\n");
} }
} else { } else {
/* SGTC use the bus clock as timer */ /* SGTC use the bus clock as timer */
...@@ -642,10 +677,11 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -642,10 +677,11 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
if (result) if (result)
return result; return result;
printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", printk(KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
minimum_speed/1000, maximum_speed/1000); minimum_speed/1000, maximum_speed/1000);
policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency); policy->cpuinfo.transition_latency =
cpufreq_scale(2000000UL, fsb, latency);
policy->cur = powernow_get(0); policy->cur = powernow_get(0);
...@@ -654,7 +690,8 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -654,7 +690,8 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
return cpufreq_frequency_table_cpuinfo(policy, powernow_table); return cpufreq_frequency_table_cpuinfo(policy, powernow_table);
} }
static int powernow_cpu_exit (struct cpufreq_policy *policy) { static int powernow_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_put_attr(policy->cpu); cpufreq_frequency_table_put_attr(policy->cpu);
#ifdef CONFIG_X86_POWERNOW_K7_ACPI #ifdef CONFIG_X86_POWERNOW_K7_ACPI
...@@ -669,7 +706,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) { ...@@ -669,7 +706,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) {
return 0; return 0;
} }
static struct freq_attr* powernow_table_attr[] = { static struct freq_attr *powernow_table_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -685,15 +722,15 @@ static struct cpufreq_driver powernow_driver = { ...@@ -685,15 +722,15 @@ static struct cpufreq_driver powernow_driver = {
.attr = powernow_table_attr, .attr = powernow_table_attr,
}; };
static int __init powernow_init (void) static int __init powernow_init(void)
{ {
if (check_powernow()==0) if (check_powernow() == 0)
return -ENODEV; return -ENODEV;
return cpufreq_register_driver(&powernow_driver); return cpufreq_register_driver(&powernow_driver);
} }
static void __exit powernow_exit (void) static void __exit powernow_exit(void)
{ {
cpufreq_unregister_driver(&powernow_driver); cpufreq_unregister_driver(&powernow_driver);
} }
...@@ -701,9 +738,9 @@ static void __exit powernow_exit (void) ...@@ -701,9 +738,9 @@ static void __exit powernow_exit (void)
module_param(acpi_force, int, 0444); module_param(acpi_force, int, 0444);
MODULE_PARM_DESC(acpi_force, "Force ACPI to be used."); MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
MODULE_AUTHOR ("Dave Jones <davej@redhat.com>"); MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
late_initcall(powernow_init); late_initcall(powernow_init);
module_exit(powernow_exit); module_exit(powernow_exit);
......
...@@ -33,16 +33,14 @@ ...@@ -33,16 +33,14 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/sched.h> /* for current / set_cpus_allowed() */ #include <linux/sched.h> /* for current / set_cpus_allowed() */
#include <linux/io.h>
#include <linux/delay.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/io.h>
#include <asm/delay.h>
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#endif
#define PFX "powernow-k8: " #define PFX "powernow-k8: "
#define VERSION "version 2.20.00" #define VERSION "version 2.20.00"
...@@ -71,7 +69,8 @@ static u32 find_khz_freq_from_fid(u32 fid) ...@@ -71,7 +69,8 @@ static u32 find_khz_freq_from_fid(u32 fid)
return 1000 * find_freq_from_fid(fid); return 1000 * find_freq_from_fid(fid);
} }
static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, u32 pstate) static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data,
u32 pstate)
{ {
return data[pstate].frequency; return data[pstate].frequency;
} }
...@@ -186,7 +185,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) ...@@ -186,7 +185,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
return 1; return 1;
} }
lo = fid | (data->currvid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID; lo = fid;
lo |= (data->currvid << MSR_C_LO_VID_SHIFT);
lo |= MSR_C_LO_INIT_FID_VID;
dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n", dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
fid, lo, data->plllock * PLL_LOCK_CONVERSION); fid, lo, data->plllock * PLL_LOCK_CONVERSION);
...@@ -194,7 +195,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) ...@@ -194,7 +195,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
do { do {
wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
if (i++ > 100) { if (i++ > 100) {
printk(KERN_ERR PFX "Hardware error - pending bit very stuck - no further pstate changes possible\n"); printk(KERN_ERR PFX
"Hardware error - pending bit very stuck - "
"no further pstate changes possible\n");
return 1; return 1;
} }
} while (query_current_values_with_pending_wait(data)); } while (query_current_values_with_pending_wait(data));
...@@ -202,14 +205,16 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid) ...@@ -202,14 +205,16 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
count_off_irt(data); count_off_irt(data);
if (savevid != data->currvid) { if (savevid != data->currvid) {
printk(KERN_ERR PFX "vid change on fid trans, old 0x%x, new 0x%x\n", printk(KERN_ERR PFX
savevid, data->currvid); "vid change on fid trans, old 0x%x, new 0x%x\n",
savevid, data->currvid);
return 1; return 1;
} }
if (fid != data->currfid) { if (fid != data->currfid) {
printk(KERN_ERR PFX "fid trans failed, fid 0x%x, curr 0x%x\n", fid, printk(KERN_ERR PFX
data->currfid); "fid trans failed, fid 0x%x, curr 0x%x\n", fid,
data->currfid);
return 1; return 1;
} }
...@@ -228,7 +233,9 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) ...@@ -228,7 +233,9 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
return 1; return 1;
} }
lo = data->currfid | (vid << MSR_C_LO_VID_SHIFT) | MSR_C_LO_INIT_FID_VID; lo = data->currfid;
lo |= (vid << MSR_C_LO_VID_SHIFT);
lo |= MSR_C_LO_INIT_FID_VID;
dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n", dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
vid, lo, STOP_GRANT_5NS); vid, lo, STOP_GRANT_5NS);
...@@ -236,20 +243,24 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) ...@@ -236,20 +243,24 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
do { do {
wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
if (i++ > 100) { if (i++ > 100) {
printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n"); printk(KERN_ERR PFX "internal error - pending bit "
"very stuck - no further pstate "
"changes possible\n");
return 1; return 1;
} }
} while (query_current_values_with_pending_wait(data)); } while (query_current_values_with_pending_wait(data));
if (savefid != data->currfid) { if (savefid != data->currfid) {
printk(KERN_ERR PFX "fid changed on vid trans, old 0x%x new 0x%x\n", printk(KERN_ERR PFX "fid changed on vid trans, old "
"0x%x new 0x%x\n",
savefid, data->currfid); savefid, data->currfid);
return 1; return 1;
} }
if (vid != data->currvid) { if (vid != data->currvid) {
printk(KERN_ERR PFX "vid trans failed, vid 0x%x, curr 0x%x\n", vid, printk(KERN_ERR PFX "vid trans failed, vid 0x%x, "
data->currvid); "curr 0x%x\n",
vid, data->currvid);
return 1; return 1;
} }
...@@ -261,7 +272,8 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid) ...@@ -261,7 +272,8 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
* Decreasing vid codes represent increasing voltages: * Decreasing vid codes represent increasing voltages:
* vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off. * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off.
*/ */
static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid, u32 step) static int decrease_vid_code_by_step(struct powernow_k8_data *data,
u32 reqvid, u32 step)
{ {
if ((data->currvid - reqvid) > step) if ((data->currvid - reqvid) > step)
reqvid = data->currvid - step; reqvid = data->currvid - step;
...@@ -283,7 +295,8 @@ static int transition_pstate(struct powernow_k8_data *data, u32 pstate) ...@@ -283,7 +295,8 @@ static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
} }
/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */ /* Change Opteron/Athlon64 fid and vid, by the 3 phases. */
static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 reqvid) static int transition_fid_vid(struct powernow_k8_data *data,
u32 reqfid, u32 reqvid)
{ {
if (core_voltage_pre_transition(data, reqvid)) if (core_voltage_pre_transition(data, reqvid))
return 1; return 1;
...@@ -298,7 +311,8 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req ...@@ -298,7 +311,8 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req
return 1; return 1;
if ((reqfid != data->currfid) || (reqvid != data->currvid)) { if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x\n", printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, "
"curr 0x%x 0x%x\n",
smp_processor_id(), smp_processor_id(),
reqfid, reqvid, data->currfid, data->currvid); reqfid, reqvid, data->currfid, data->currvid);
return 1; return 1;
...@@ -311,13 +325,15 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req ...@@ -311,13 +325,15 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req
} }
/* Phase 1 - core voltage transition ... setup voltage */ /* Phase 1 - core voltage transition ... setup voltage */
static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid) static int core_voltage_pre_transition(struct powernow_k8_data *data,
u32 reqvid)
{ {
u32 rvosteps = data->rvo; u32 rvosteps = data->rvo;
u32 savefid = data->currfid; u32 savefid = data->currfid;
u32 maxvid, lo; u32 maxvid, lo;
dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
"reqvid 0x%x, rvo 0x%x\n",
smp_processor_id(), smp_processor_id(),
data->currfid, data->currvid, reqvid, data->rvo); data->currfid, data->currvid, reqvid, data->rvo);
...@@ -340,7 +356,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -340,7 +356,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
} else { } else {
dprintk("ph1: changing vid for rvo, req 0x%x\n", dprintk("ph1: changing vid for rvo, req 0x%x\n",
data->currvid - 1); data->currvid - 1);
if (decrease_vid_code_by_step(data, data->currvid - 1, 1)) if (decrease_vid_code_by_step(data, data->currvid-1, 1))
return 1; return 1;
rvosteps--; rvosteps--;
} }
...@@ -350,7 +366,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -350,7 +366,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
return 1; return 1;
if (savefid != data->currfid) { if (savefid != data->currfid) {
printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", data->currfid); printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n",
data->currfid);
return 1; return 1;
} }
...@@ -363,20 +380,24 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -363,20 +380,24 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
/* Phase 2 - core frequency transition */ /* Phase 2 - core frequency transition */
static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
{ {
u32 vcoreqfid, vcocurrfid, vcofiddiff, fid_interval, savevid = data->currvid; u32 vcoreqfid, vcocurrfid, vcofiddiff;
u32 fid_interval, savevid = data->currvid;
if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { if ((reqfid < HI_FID_TABLE_BOTTOM) &&
printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n", (data->currfid < HI_FID_TABLE_BOTTOM)) {
reqfid, data->currfid); printk(KERN_ERR PFX "ph2: illegal lo-lo transition "
"0x%x 0x%x\n", reqfid, data->currfid);
return 1; return 1;
} }
if (data->currfid == reqfid) { if (data->currfid == reqfid) {
printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", data->currfid); printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n",
data->currfid);
return 0; return 0;
} }
dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n", dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
"reqfid 0x%x\n",
smp_processor_id(), smp_processor_id(),
data->currfid, data->currvid, reqfid); data->currfid, data->currvid, reqfid);
...@@ -390,14 +411,14 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) ...@@ -390,14 +411,14 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
if (reqfid > data->currfid) { if (reqfid > data->currfid) {
if (data->currfid > LO_FID_TABLE_TOP) { if (data->currfid > LO_FID_TABLE_TOP) {
if (write_new_fid(data, data->currfid + fid_interval)) { if (write_new_fid(data,
data->currfid + fid_interval))
return 1; return 1;
}
} else { } else {
if (write_new_fid if (write_new_fid
(data, 2 + convert_fid_to_vco_fid(data->currfid))) { (data,
2 + convert_fid_to_vco_fid(data->currfid)))
return 1; return 1;
}
} }
} else { } else {
if (write_new_fid(data, data->currfid - fid_interval)) if (write_new_fid(data, data->currfid - fid_interval))
...@@ -417,7 +438,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) ...@@ -417,7 +438,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
if (data->currfid != reqfid) { if (data->currfid != reqfid) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x\n", "ph2: mismatch, failed fid transition, "
"curr 0x%x, req 0x%x\n",
data->currfid, reqfid); data->currfid, reqfid);
return 1; return 1;
} }
...@@ -435,7 +457,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid) ...@@ -435,7 +457,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
} }
/* Phase 3 - core voltage transition flow ... jump to the final vid. */ /* Phase 3 - core voltage transition flow ... jump to the final vid. */
static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid) static int core_voltage_post_transition(struct powernow_k8_data *data,
u32 reqvid)
{ {
u32 savefid = data->currfid; u32 savefid = data->currfid;
u32 savereqvid = reqvid; u32 savereqvid = reqvid;
...@@ -457,7 +480,8 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi ...@@ -457,7 +480,8 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi
if (data->currvid != reqvid) { if (data->currvid != reqvid) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"ph3: failed vid transition\n, req 0x%x, curr 0x%x", "ph3: failed vid transition\n, "
"req 0x%x, curr 0x%x",
reqvid, data->currvid); reqvid, data->currvid);
return 1; return 1;
} }
...@@ -508,7 +532,8 @@ static int check_supported_cpu(unsigned int cpu) ...@@ -508,7 +532,8 @@ static int check_supported_cpu(unsigned int cpu)
if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) { if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) { ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax); printk(KERN_INFO PFX
"Processor cpuid %x not supported\n", eax);
goto out; goto out;
} }
...@@ -520,8 +545,10 @@ static int check_supported_cpu(unsigned int cpu) ...@@ -520,8 +545,10 @@ static int check_supported_cpu(unsigned int cpu)
} }
cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) { if ((edx & P_STATE_TRANSITION_CAPABLE)
printk(KERN_INFO PFX "Power state transitions not supported\n"); != P_STATE_TRANSITION_CAPABLE) {
printk(KERN_INFO PFX
"Power state transitions not supported\n");
goto out; goto out;
} }
} else { /* must be a HW Pstate capable processor */ } else { /* must be a HW Pstate capable processor */
...@@ -539,7 +566,8 @@ static int check_supported_cpu(unsigned int cpu) ...@@ -539,7 +566,8 @@ static int check_supported_cpu(unsigned int cpu)
return rc; return rc;
} }
static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid) static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
u8 maxvid)
{ {
unsigned int j; unsigned int j;
u8 lastfid = 0xff; u8 lastfid = 0xff;
...@@ -550,12 +578,14 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 ...@@ -550,12 +578,14 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
j, pst[j].vid); j, pst[j].vid);
return -EINVAL; return -EINVAL;
} }
if (pst[j].vid < data->rvo) { /* vid + rvo >= 0 */ if (pst[j].vid < data->rvo) {
/* vid + rvo >= 0 */
printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate" printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate"
" %d\n", j); " %d\n", j);
return -ENODEV; return -ENODEV;
} }
if (pst[j].vid < maxvid + data->rvo) { /* vid + rvo >= maxvid */ if (pst[j].vid < maxvid + data->rvo) {
/* vid + rvo >= maxvid */
printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate" printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate"
" %d\n", j); " %d\n", j);
return -ENODEV; return -ENODEV;
...@@ -579,23 +609,31 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 ...@@ -579,23 +609,31 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
return -EINVAL; return -EINVAL;
} }
if (lastfid > LO_FID_TABLE_TOP) if (lastfid > LO_FID_TABLE_TOP)
printk(KERN_INFO FW_BUG PFX "first fid not from lo freq table\n"); printk(KERN_INFO FW_BUG PFX
"first fid not from lo freq table\n");
return 0; return 0;
} }
static void invalidate_entry(struct powernow_k8_data *data, unsigned int entry)
{
data->powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
}
static void print_basics(struct powernow_k8_data *data) static void print_basics(struct powernow_k8_data *data)
{ {
int j; int j;
for (j = 0; j < data->numps; j++) { for (j = 0; j < data->numps; j++) {
if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) { if (data->powernow_table[j].frequency !=
CPUFREQ_ENTRY_INVALID) {
if (cpu_family == CPU_HW_PSTATE) { if (cpu_family == CPU_HW_PSTATE) {
printk(KERN_INFO PFX " %d : pstate %d (%d MHz)\n", printk(KERN_INFO PFX
j, " %d : pstate %d (%d MHz)\n", j,
data->powernow_table[j].index, data->powernow_table[j].index,
data->powernow_table[j].frequency/1000); data->powernow_table[j].frequency/1000);
} else { } else {
printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x\n", printk(KERN_INFO PFX
" %d : fid 0x%x (%d MHz), vid 0x%x\n",
j, j,
data->powernow_table[j].index & 0xff, data->powernow_table[j].index & 0xff,
data->powernow_table[j].frequency/1000, data->powernow_table[j].frequency/1000,
...@@ -604,20 +642,25 @@ static void print_basics(struct powernow_k8_data *data) ...@@ -604,20 +642,25 @@ static void print_basics(struct powernow_k8_data *data)
} }
} }
if (data->batps) if (data->batps)
printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps); printk(KERN_INFO PFX "Only %d pstates on battery\n",
data->batps);
} }
static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid) static int fill_powernow_table(struct powernow_k8_data *data,
struct pst_s *pst, u8 maxvid)
{ {
struct cpufreq_frequency_table *powernow_table; struct cpufreq_frequency_table *powernow_table;
unsigned int j; unsigned int j;
if (data->batps) { /* use ACPI support to get full speed on mains power */ if (data->batps) {
printk(KERN_WARNING PFX "Only %d pstates usable (use ACPI driver for full range\n", data->batps); /* use ACPI support to get full speed on mains power */
printk(KERN_WARNING PFX
"Only %d pstates usable (use ACPI driver for full "
"range\n", data->batps);
data->numps = data->batps; data->numps = data->batps;
} }
for ( j=1; j<data->numps; j++ ) { for (j = 1; j < data->numps; j++) {
if (pst[j-1].fid >= pst[j].fid) { if (pst[j-1].fid >= pst[j].fid) {
printk(KERN_ERR PFX "PST out of sequence\n"); printk(KERN_ERR PFX "PST out of sequence\n");
return -EINVAL; return -EINVAL;
...@@ -640,9 +683,11 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, ...@@ -640,9 +683,11 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst,
} }
for (j = 0; j < data->numps; j++) { for (j = 0; j < data->numps; j++) {
int freq;
powernow_table[j].index = pst[j].fid; /* lower 8 bits */ powernow_table[j].index = pst[j].fid; /* lower 8 bits */
powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */ powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
powernow_table[j].frequency = find_khz_freq_from_fid(pst[j].fid); freq = find_khz_freq_from_fid(pst[j].fid);
powernow_table[j].frequency = freq;
} }
powernow_table[data->numps].frequency = CPUFREQ_TABLE_END; powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
powernow_table[data->numps].index = 0; powernow_table[data->numps].index = 0;
...@@ -658,7 +703,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, ...@@ -658,7 +703,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst,
print_basics(data); print_basics(data);
for (j = 0; j < data->numps; j++) for (j = 0; j < data->numps; j++)
if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid)) if ((pst[j].fid == data->currfid) &&
(pst[j].vid == data->currvid))
return 0; return 0;
dprintk("currfid/vid do not match PST, ignoring\n"); dprintk("currfid/vid do not match PST, ignoring\n");
...@@ -698,7 +744,8 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -698,7 +744,8 @@ static int find_psb_table(struct powernow_k8_data *data)
} }
data->vstable = psb->vstable; data->vstable = psb->vstable;
dprintk("voltage stabilization time: %d(*20us)\n", data->vstable); dprintk("voltage stabilization time: %d(*20us)\n",
data->vstable);
dprintk("flags2: 0x%x\n", psb->flags2); dprintk("flags2: 0x%x\n", psb->flags2);
data->rvo = psb->flags2 & 3; data->rvo = psb->flags2 & 3;
...@@ -713,11 +760,12 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -713,11 +760,12 @@ static int find_psb_table(struct powernow_k8_data *data)
dprintk("numpst: 0x%x\n", psb->num_tables); dprintk("numpst: 0x%x\n", psb->num_tables);
cpst = psb->num_tables; cpst = psb->num_tables;
if ((psb->cpuid == 0x00000fc0) || (psb->cpuid == 0x00000fe0) ){ if ((psb->cpuid == 0x00000fc0) ||
(psb->cpuid == 0x00000fe0)) {
thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); thiscpuid = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) { if ((thiscpuid == 0x00000fc0) ||
(thiscpuid == 0x00000fe0))
cpst = 1; cpst = 1;
}
} }
if (cpst != 1) { if (cpst != 1) {
printk(KERN_ERR FW_BUG PFX "numpst must be 1\n"); printk(KERN_ERR FW_BUG PFX "numpst must be 1\n");
...@@ -732,7 +780,8 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -732,7 +780,8 @@ static int find_psb_table(struct powernow_k8_data *data)
data->numps = psb->numps; data->numps = psb->numps;
dprintk("numpstates: 0x%x\n", data->numps); dprintk("numpstates: 0x%x\n", data->numps);
return fill_powernow_table(data, (struct pst_s *)(psb+1), maxvid); return fill_powernow_table(data,
(struct pst_s *)(psb+1), maxvid);
} }
/* /*
* If you see this message, complain to BIOS manufacturer. If * If you see this message, complain to BIOS manufacturer. If
...@@ -745,28 +794,31 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -745,28 +794,31 @@ static int find_psb_table(struct powernow_k8_data *data)
* BIOS and Kernel Developer's Guide, which is available on * BIOS and Kernel Developer's Guide, which is available on
* www.amd.com * www.amd.com
*/ */
printk(KERN_ERR PFX "BIOS error - no PSB or ACPI _PSS objects\n"); printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n");
return -ENODEV; return -ENODEV;
} }
#ifdef CONFIG_X86_POWERNOW_K8_ACPI static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data,
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) unsigned int index)
{ {
acpi_integer control;
if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE)) if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
return; return;
data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK; control = data->acpi_data.states[index].control; data->irt = (control
data->rvo = (data->acpi_data.states[index].control >> RVO_SHIFT) & RVO_MASK; >> IRT_SHIFT) & IRT_MASK; data->rvo = (control >>
data->exttype = (data->acpi_data.states[index].control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK; RVO_SHIFT) & RVO_MASK; data->exttype = (control
data->plllock = (data->acpi_data.states[index].control >> PLL_L_SHIFT) & PLL_L_MASK; >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
data->vidmvs = 1 << ((data->acpi_data.states[index].control >> MVS_SHIFT) & MVS_MASK); data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; data->vidmvs = 1
data->vstable = (data->acpi_data.states[index].control >> VST_SHIFT) & VST_MASK; << ((control >> MVS_SHIFT) & MVS_MASK); data->vstable =
} (control >> VST_SHIFT) & VST_MASK; }
static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
{ {
struct cpufreq_frequency_table *powernow_table; struct cpufreq_frequency_table *powernow_table;
int ret_val = -ENODEV; int ret_val = -ENODEV;
acpi_integer space_id;
if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
dprintk("register performance failed: bad ACPI data\n"); dprintk("register performance failed: bad ACPI data\n");
...@@ -779,11 +831,12 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) ...@@ -779,11 +831,12 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
goto err_out; goto err_out;
} }
if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) || space_id = data->acpi_data.control_register.space_id;
(data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { if ((space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
(space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
dprintk("Invalid control/status registers (%x - %x)\n", dprintk("Invalid control/status registers (%x - %x)\n",
data->acpi_data.control_register.space_id, data->acpi_data.control_register.space_id,
data->acpi_data.status_register.space_id); space_id);
goto err_out; goto err_out;
} }
...@@ -802,7 +855,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) ...@@ -802,7 +855,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
if (ret_val) if (ret_val)
goto err_out_mem; goto err_out_mem;
powernow_table[data->acpi_data.state_count].frequency = CPUFREQ_TABLE_END; powernow_table[data->acpi_data.state_count].frequency =
CPUFREQ_TABLE_END;
powernow_table[data->acpi_data.state_count].index = 0; powernow_table[data->acpi_data.state_count].index = 0;
data->powernow_table = powernow_table; data->powernow_table = powernow_table;
...@@ -830,13 +884,15 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) ...@@ -830,13 +884,15 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
err_out: err_out:
acpi_processor_unregister_performance(&data->acpi_data, data->cpu); acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
/* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */ /* data->acpi_data.state_count informs us at ->exit()
* whether ACPI was used */
data->acpi_data.state_count = 0; data->acpi_data.state_count = 0;
return ret_val; return ret_val;
} }
static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table) static int fill_powernow_table_pstate(struct powernow_k8_data *data,
struct cpufreq_frequency_table *powernow_table)
{ {
int i; int i;
u32 hi = 0, lo = 0; u32 hi = 0, lo = 0;
...@@ -848,84 +904,101 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpuf ...@@ -848,84 +904,101 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpuf
index = data->acpi_data.states[i].control & HW_PSTATE_MASK; index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
if (index > data->max_hw_pstate) { if (index > data->max_hw_pstate) {
printk(KERN_ERR PFX "invalid pstate %d - bad value %d.\n", i, index); printk(KERN_ERR PFX "invalid pstate %d - "
printk(KERN_ERR PFX "Please report to BIOS manufacturer\n"); "bad value %d.\n", i, index);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; printk(KERN_ERR PFX "Please report to BIOS "
"manufacturer\n");
invalidate_entry(data, i);
continue; continue;
} }
rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
if (!(hi & HW_PSTATE_VALID_MASK)) { if (!(hi & HW_PSTATE_VALID_MASK)) {
dprintk("invalid pstate %d, ignoring\n", index); dprintk("invalid pstate %d, ignoring\n", index);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; invalidate_entry(data, i);
continue; continue;
} }
powernow_table[i].index = index; powernow_table[i].index = index;
powernow_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; powernow_table[i].frequency =
data->acpi_data.states[i].core_frequency * 1000;
} }
return 0; return 0;
} }
static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table) static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
struct cpufreq_frequency_table *powernow_table)
{ {
int i; int i;
int cntlofreq = 0; int cntlofreq = 0;
for (i = 0; i < data->acpi_data.state_count; i++) { for (i = 0; i < data->acpi_data.state_count; i++) {
u32 fid; u32 fid;
u32 vid; u32 vid;
u32 freq, index;
acpi_integer status, control;
if (data->exttype) { if (data->exttype) {
fid = data->acpi_data.states[i].status & EXT_FID_MASK; status = data->acpi_data.states[i].status;
vid = (data->acpi_data.states[i].status >> VID_SHIFT) & EXT_VID_MASK; fid = status & EXT_FID_MASK;
vid = (status >> VID_SHIFT) & EXT_VID_MASK;
} else { } else {
fid = data->acpi_data.states[i].control & FID_MASK; control = data->acpi_data.states[i].control;
vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK; fid = control & FID_MASK;
vid = (control >> VID_SHIFT) & VID_MASK;
} }
dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
powernow_table[i].index = fid; /* lower 8 bits */ index = fid | (vid<<8);
powernow_table[i].index |= (vid << 8); /* upper 8 bits */ powernow_table[i].index = index;
powernow_table[i].frequency = find_khz_freq_from_fid(fid);
freq = find_khz_freq_from_fid(fid);
powernow_table[i].frequency = freq;
/* verify frequency is OK */ /* verify frequency is OK */
if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) || if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
(powernow_table[i].frequency < (MIN_FREQ * 1000))) { dprintk("invalid freq %u kHz, ignoring\n", freq);
dprintk("invalid freq %u kHz, ignoring\n", powernow_table[i].frequency); invalidate_entry(data, i);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
continue; continue;
} }
/* verify voltage is OK - BIOSs are using "off" to indicate invalid */ /* verify voltage is OK -
* BIOSs are using "off" to indicate invalid */
if (vid == VID_OFF) { if (vid == VID_OFF) {
dprintk("invalid vid %u, ignoring\n", vid); dprintk("invalid vid %u, ignoring\n", vid);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; invalidate_entry(data, i);
continue; continue;
} }
/* verify only 1 entry from the lo frequency table */ /* verify only 1 entry from the lo frequency table */
if (fid < HI_FID_TABLE_BOTTOM) { if (fid < HI_FID_TABLE_BOTTOM) {
if (cntlofreq) { if (cntlofreq) {
/* if both entries are the same, ignore this one ... */ /* if both entries are the same,
if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) || * ignore this one ... */
(powernow_table[i].index != powernow_table[cntlofreq].index)) { if ((freq != powernow_table[cntlofreq].frequency) ||
printk(KERN_ERR PFX "Too many lo freq table entries\n"); (index != powernow_table[cntlofreq].index)) {
printk(KERN_ERR PFX
"Too many lo freq table "
"entries\n");
return 1; return 1;
} }
dprintk("double low frequency table entry, ignoring it.\n"); dprintk("double low frequency table entry, "
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; "ignoring it.\n");
invalidate_entry(data, i);
continue; continue;
} else } else
cntlofreq = i; cntlofreq = i;
} }
if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) { if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n", printk(KERN_INFO PFX "invalid freq entries "
powernow_table[i].frequency, "%u kHz vs. %u kHz\n", freq,
(unsigned int) (data->acpi_data.states[i].core_frequency * 1000)); (unsigned int)
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; (data->acpi_data.states[i].core_frequency
* 1000));
invalidate_entry(data, i);
continue; continue;
} }
} }
...@@ -935,7 +1008,8 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpuf ...@@ -935,7 +1008,8 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpuf
static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
{ {
if (data->acpi_data.state_count) if (data->acpi_data.state_count)
acpi_processor_unregister_performance(&data->acpi_data, data->cpu); acpi_processor_unregister_performance(&data->acpi_data,
data->cpu);
free_cpumask_var(data->acpi_data.shared_cpu_map); free_cpumask_var(data->acpi_data.shared_cpu_map);
} }
...@@ -953,15 +1027,9 @@ static int get_transition_latency(struct powernow_k8_data *data) ...@@ -953,15 +1027,9 @@ static int get_transition_latency(struct powernow_k8_data *data)
return 1000 * max_latency; return 1000 * max_latency;
} }
#else
static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) { return -ENODEV; }
static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { return; }
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index) { return; }
static int get_transition_latency(struct powernow_k8_data *data) { return 0; }
#endif /* CONFIG_X86_POWERNOW_K8_ACPI */
/* Take a frequency, and issue the fid/vid transition command */ /* Take a frequency, and issue the fid/vid transition command */
static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned int index) static int transition_frequency_fidvid(struct powernow_k8_data *data,
unsigned int index)
{ {
u32 fid = 0; u32 fid = 0;
u32 vid = 0; u32 vid = 0;
...@@ -989,7 +1057,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i ...@@ -989,7 +1057,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i
return 0; return 0;
} }
if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { if ((fid < HI_FID_TABLE_BOTTOM) &&
(data->currfid < HI_FID_TABLE_BOTTOM)) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"ignoring illegal change in lo freq table-%x to 0x%x\n", "ignoring illegal change in lo freq table-%x to 0x%x\n",
data->currfid, fid); data->currfid, fid);
...@@ -1017,7 +1086,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i ...@@ -1017,7 +1086,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i
} }
/* Take a frequency, and issue the hardware pstate transition command */ /* Take a frequency, and issue the hardware pstate transition command */
static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned int index) static int transition_frequency_pstate(struct powernow_k8_data *data,
unsigned int index)
{ {
u32 pstate = 0; u32 pstate = 0;
int res, i; int res, i;
...@@ -1029,7 +1099,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i ...@@ -1029,7 +1099,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i
pstate = index & HW_PSTATE_MASK; pstate = index & HW_PSTATE_MASK;
if (pstate > data->max_hw_pstate) if (pstate > data->max_hw_pstate)
return 0; return 0;
freqs.old = find_khz_freq_from_pstate(data->powernow_table, data->currpstate); freqs.old = find_khz_freq_from_pstate(data->powernow_table,
data->currpstate);
freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate); freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
for_each_cpu_mask_nr(i, *(data->available_cores)) { for_each_cpu_mask_nr(i, *(data->available_cores)) {
...@@ -1048,7 +1119,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i ...@@ -1048,7 +1119,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i
} }
/* Driver entry point to switch to the target frequency */ /* Driver entry point to switch to the target frequency */
static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsigned relation) static int powernowk8_target(struct cpufreq_policy *pol,
unsigned targfreq, unsigned relation)
{ {
cpumask_t oldmask; cpumask_t oldmask;
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
...@@ -1087,14 +1159,18 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi ...@@ -1087,14 +1159,18 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
dprintk("targ: curr fid 0x%x, vid 0x%x\n", dprintk("targ: curr fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid); data->currfid, data->currvid);
if ((checkvid != data->currvid) || (checkfid != data->currfid)) { if ((checkvid != data->currvid) ||
(checkfid != data->currfid)) {
printk(KERN_INFO PFX printk(KERN_INFO PFX
"error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n", "error - out of sync, fix 0x%x 0x%x, "
checkfid, data->currfid, checkvid, data->currvid); "vid 0x%x 0x%x\n",
checkfid, data->currfid,
checkvid, data->currvid);
} }
} }
if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate)) if (cpufreq_frequency_table_target(pol, data->powernow_table,
targfreq, relation, &newstate))
goto err_out; goto err_out;
mutex_lock(&fidvid_mutex); mutex_lock(&fidvid_mutex);
...@@ -1114,7 +1190,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi ...@@ -1114,7 +1190,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
mutex_unlock(&fidvid_mutex); mutex_unlock(&fidvid_mutex);
if (cpu_family == CPU_HW_PSTATE) if (cpu_family == CPU_HW_PSTATE)
pol->cur = find_khz_freq_from_pstate(data->powernow_table, newstate); pol->cur = find_khz_freq_from_pstate(data->powernow_table,
newstate);
else else
pol->cur = find_khz_freq_from_fid(data->currfid); pol->cur = find_khz_freq_from_fid(data->currfid);
ret = 0; ret = 0;
...@@ -1141,6 +1218,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1141,6 +1218,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
struct powernow_k8_data *data; struct powernow_k8_data *data;
cpumask_t oldmask; cpumask_t oldmask;
int rc; int rc;
static int print_once;
if (!cpu_online(pol->cpu)) if (!cpu_online(pol->cpu))
return -ENODEV; return -ENODEV;
...@@ -1163,33 +1241,31 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1163,33 +1241,31 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
* an UP version, and is deprecated by AMD. * an UP version, and is deprecated by AMD.
*/ */
if (num_online_cpus() != 1) { if (num_online_cpus() != 1) {
#ifndef CONFIG_ACPI_PROCESSOR /*
printk(KERN_ERR PFX "ACPI Processor support is required " * Replace this one with print_once as soon as such a
"for SMP systems but is absent. Please load the " * thing gets introduced
"ACPI Processor module before starting this " */
"driver.\n"); if (!print_once) {
#else WARN_ONCE(1, KERN_ERR FW_BUG PFX "Your BIOS "
printk(KERN_ERR FW_BUG PFX "Your BIOS does not provide" "does not provide ACPI _PSS objects "
" ACPI _PSS objects in a way that Linux " "in a way that Linux understands. "
"understands. Please report this to the Linux " "Please report this to the Linux ACPI"
"ACPI maintainers and complain to your BIOS " " maintainers and complain to your "
"vendor.\n"); "BIOS vendor.\n");
#endif print_once++;
kfree(data); }
return -ENODEV; goto err_out;
} }
if (pol->cpu != 0) { if (pol->cpu != 0) {
printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for " printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
"CPU other than CPU0. Complain to your BIOS " "CPU other than CPU0. Complain to your BIOS "
"vendor.\n"); "vendor.\n");
kfree(data); goto err_out;
return -ENODEV;
} }
rc = find_psb_table(data); rc = find_psb_table(data);
if (rc) { if (rc)
kfree(data); goto err_out;
return -ENODEV;
}
/* Take a crude guess here. /* Take a crude guess here.
* That guess was in microseconds, so multiply with 1000 */ * That guess was in microseconds, so multiply with 1000 */
pol->cpuinfo.transition_latency = ( pol->cpuinfo.transition_latency = (
...@@ -1204,16 +1280,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1204,16 +1280,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
if (smp_processor_id() != pol->cpu) { if (smp_processor_id() != pol->cpu) {
printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu); printk(KERN_ERR PFX "limiting to cpu %u failed\n", pol->cpu);
goto err_out; goto err_out_unmask;
} }
if (pending_bit_stuck()) { if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing init, change pending bit set\n"); printk(KERN_ERR PFX "failing init, change pending bit set\n");
goto err_out; goto err_out_unmask;
} }
if (query_current_values_with_pending_wait(data)) if (query_current_values_with_pending_wait(data))
goto err_out; goto err_out_unmask;
if (cpu_family == CPU_OPTERON) if (cpu_family == CPU_OPTERON)
fidvid_msr_init(); fidvid_msr_init();
...@@ -1228,7 +1304,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1228,7 +1304,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
data->available_cores = pol->cpus; data->available_cores = pol->cpus;
if (cpu_family == CPU_HW_PSTATE) if (cpu_family == CPU_HW_PSTATE)
pol->cur = find_khz_freq_from_pstate(data->powernow_table, data->currpstate); pol->cur = find_khz_freq_from_pstate(data->powernow_table,
data->currpstate);
else else
pol->cur = find_khz_freq_from_fid(data->currfid); pol->cur = find_khz_freq_from_fid(data->currfid);
dprintk("policy current frequency %d kHz\n", pol->cur); dprintk("policy current frequency %d kHz\n", pol->cur);
...@@ -1245,7 +1322,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1245,7 +1322,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu); cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
if (cpu_family == CPU_HW_PSTATE) if (cpu_family == CPU_HW_PSTATE)
dprintk("cpu_init done, current pstate 0x%x\n", data->currpstate); dprintk("cpu_init done, current pstate 0x%x\n",
data->currpstate);
else else
dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n", dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid); data->currfid, data->currvid);
...@@ -1254,15 +1332,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1254,15 +1332,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
return 0; return 0;
err_out: err_out_unmask:
set_cpus_allowed_ptr(current, &oldmask); set_cpus_allowed_ptr(current, &oldmask);
powernow_k8_cpu_exit_acpi(data); powernow_k8_cpu_exit_acpi(data);
err_out:
kfree(data); kfree(data);
return -ENODEV; return -ENODEV;
} }
static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol) static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol)
{ {
struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
...@@ -1279,7 +1358,7 @@ static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol) ...@@ -1279,7 +1358,7 @@ static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
return 0; return 0;
} }
static unsigned int powernowk8_get (unsigned int cpu) static unsigned int powernowk8_get(unsigned int cpu)
{ {
struct powernow_k8_data *data; struct powernow_k8_data *data;
cpumask_t oldmask = current->cpus_allowed; cpumask_t oldmask = current->cpus_allowed;
...@@ -1315,7 +1394,7 @@ static unsigned int powernowk8_get (unsigned int cpu) ...@@ -1315,7 +1394,7 @@ static unsigned int powernowk8_get (unsigned int cpu)
return khz; return khz;
} }
static struct freq_attr* powernow_k8_attr[] = { static struct freq_attr *powernow_k8_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -1360,7 +1439,8 @@ static void __exit powernowk8_exit(void) ...@@ -1360,7 +1439,8 @@ static void __exit powernowk8_exit(void)
cpufreq_unregister_driver(&cpufreq_amd64_driver); cpufreq_unregister_driver(&cpufreq_amd64_driver);
} }
MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and Mark Langsdorf <mark.langsdorf@amd.com>"); MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and "
"Mark Langsdorf <mark.langsdorf@amd.com>");
MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver."); MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -45,11 +45,10 @@ struct powernow_k8_data { ...@@ -45,11 +45,10 @@ struct powernow_k8_data {
* frequency is in kHz */ * frequency is in kHz */
struct cpufreq_frequency_table *powernow_table; 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 /* the acpi table needs to be kept. it's only available if ACPI was
* used to determine valid frequency/vid/fid states */ * used to determine valid frequency/vid/fid states */
struct acpi_processor_performance acpi_data; struct acpi_processor_performance acpi_data;
#endif
/* we need to keep track of associated cores, but let cpufreq /* we need to keep track of associated cores, but let cpufreq
* handle hotplug events - so just point at cpufreq pol->cpus * handle hotplug events - so just point at cpufreq pol->cpus
* structure */ * structure */
...@@ -222,10 +221,8 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid); ...@@ -222,10 +221,8 @@ 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); static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[]) static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
......
...@@ -19,17 +19,19 @@ ...@@ -19,17 +19,19 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/timex.h>
#include <linux/io.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/timex.h>
#include <asm/io.h>
#define MMCR_BASE 0xfffef000 /* The default base address */ #define MMCR_BASE 0xfffef000 /* The default base address */
#define OFFS_CPUCTL 0x2 /* CPU Control Register */ #define OFFS_CPUCTL 0x2 /* CPU Control Register */
static __u8 __iomem *cpuctl; static __u8 __iomem *cpuctl;
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "sc520_freq", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"sc520_freq", msg)
#define PFX "sc520_freq: "
static struct cpufreq_frequency_table sc520_freq_table[] = { static struct cpufreq_frequency_table sc520_freq_table[] = {
{0x01, 100000}, {0x01, 100000},
...@@ -43,7 +45,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) ...@@ -43,7 +45,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
switch (clockspeed_reg & 0x03) { switch (clockspeed_reg & 0x03) {
default: default:
printk(KERN_ERR "sc520_freq: error: cpuctl register has unexpected value %02x\n", clockspeed_reg); printk(KERN_ERR PFX "error: cpuctl register has unexpected "
"value %02x\n", clockspeed_reg);
case 0x01: case 0x01:
return 100000; return 100000;
case 0x02: case 0x02:
...@@ -51,7 +54,7 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) ...@@ -51,7 +54,7 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
} }
} }
static void sc520_freq_set_cpu_state (unsigned int state) static void sc520_freq_set_cpu_state(unsigned int state)
{ {
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
...@@ -76,18 +79,19 @@ static void sc520_freq_set_cpu_state (unsigned int state) ...@@ -76,18 +79,19 @@ static void sc520_freq_set_cpu_state (unsigned int state)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}; };
static int sc520_freq_verify (struct cpufreq_policy *policy) static int sc520_freq_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]); return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]);
} }
static int sc520_freq_target (struct cpufreq_policy *policy, static int sc520_freq_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
if (cpufreq_frequency_table_target(policy, sc520_freq_table, target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, sc520_freq_table,
target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
sc520_freq_set_cpu_state(newstate); sc520_freq_set_cpu_state(newstate);
...@@ -116,7 +120,7 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy) ...@@ -116,7 +120,7 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table); result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
if (result) if (result)
return (result); return result;
cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu); cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
...@@ -131,7 +135,7 @@ static int sc520_freq_cpu_exit(struct cpufreq_policy *policy) ...@@ -131,7 +135,7 @@ static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
} }
static struct freq_attr* sc520_freq_attr[] = { static struct freq_attr *sc520_freq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -155,13 +159,13 @@ static int __init sc520_freq_init(void) ...@@ -155,13 +159,13 @@ static int __init sc520_freq_init(void)
int err; int err;
/* Test if we have the right hardware */ /* Test if we have the right hardware */
if(c->x86_vendor != X86_VENDOR_AMD || if (c->x86_vendor != X86_VENDOR_AMD ||
c->x86 != 4 || c->x86_model != 9) { c->x86 != 4 || c->x86_model != 9) {
dprintk("no Elan SC520 processor found!\n"); dprintk("no Elan SC520 processor found!\n");
return -ENODEV; return -ENODEV;
} }
cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
if(!cpuctl) { if (!cpuctl) {
printk(KERN_ERR "sc520_freq: error: failed to remap memory\n"); printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -39,7 +39,7 @@ static struct pci_dev *speedstep_chipset_dev; ...@@ -39,7 +39,7 @@ static struct pci_dev *speedstep_chipset_dev;
/* speedstep_processor /* speedstep_processor
*/ */
static unsigned int speedstep_processor = 0; static unsigned int speedstep_processor;
static u32 pmbase; static u32 pmbase;
...@@ -54,7 +54,8 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { ...@@ -54,7 +54,8 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
}; };
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-ich", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"speedstep-ich", msg)
/** /**
...@@ -62,7 +63,7 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { ...@@ -62,7 +63,7 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
* *
* Returns: -ENODEV if no register could be found * Returns: -ENODEV if no register could be found
*/ */
static int speedstep_find_register (void) static int speedstep_find_register(void)
{ {
if (!speedstep_chipset_dev) if (!speedstep_chipset_dev)
return -ENODEV; return -ENODEV;
...@@ -90,7 +91,7 @@ static int speedstep_find_register (void) ...@@ -90,7 +91,7 @@ static int speedstep_find_register (void)
* *
* Tries to change the SpeedStep state. * Tries to change the SpeedStep state.
*/ */
static void speedstep_set_state (unsigned int state) static void speedstep_set_state(unsigned int state)
{ {
u8 pm2_blk; u8 pm2_blk;
u8 value; u8 value;
...@@ -133,11 +134,11 @@ static void speedstep_set_state (unsigned int state) ...@@ -133,11 +134,11 @@ static void speedstep_set_state (unsigned int state)
dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
if (state == (value & 0x1)) { if (state == (value & 0x1))
dprintk("change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000)); dprintk("change to %u MHz succeeded\n",
} else { speedstep_get_frequency(speedstep_processor) / 1000);
printk (KERN_ERR "cpufreq: change failed - I/O error\n"); else
} printk(KERN_ERR "cpufreq: change failed - I/O error\n");
return; return;
} }
...@@ -149,7 +150,7 @@ static void speedstep_set_state (unsigned int state) ...@@ -149,7 +150,7 @@ static void speedstep_set_state (unsigned int state)
* Tries to activate the SpeedStep status and control registers. * Tries to activate the SpeedStep status and control registers.
* Returns -EINVAL on an unsupported chipset, and zero on success. * Returns -EINVAL on an unsupported chipset, and zero on success.
*/ */
static int speedstep_activate (void) static int speedstep_activate(void)
{ {
u16 value = 0; u16 value = 0;
...@@ -175,20 +176,18 @@ static int speedstep_activate (void) ...@@ -175,20 +176,18 @@ static int speedstep_activate (void)
* functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
* chipset, or zero on failure. * chipset, or zero on failure.
*/ */
static unsigned int speedstep_detect_chipset (void) static unsigned int speedstep_detect_chipset(void)
{ {
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801DB_12, PCI_DEVICE_ID_INTEL_82801DB_12,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_ANY_ID,
NULL); NULL);
if (speedstep_chipset_dev) if (speedstep_chipset_dev)
return 4; /* 4-M */ return 4; /* 4-M */
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801CA_12, PCI_DEVICE_ID_INTEL_82801CA_12,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_ANY_ID,
NULL); NULL);
if (speedstep_chipset_dev) if (speedstep_chipset_dev)
return 3; /* 3-M */ return 3; /* 3-M */
...@@ -196,8 +195,7 @@ static unsigned int speedstep_detect_chipset (void) ...@@ -196,8 +195,7 @@ static unsigned int speedstep_detect_chipset (void)
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801BA_10, PCI_DEVICE_ID_INTEL_82801BA_10,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_ANY_ID,
NULL); NULL);
if (speedstep_chipset_dev) { if (speedstep_chipset_dev) {
/* speedstep.c causes lockups on Dell Inspirons 8000 and /* speedstep.c causes lockups on Dell Inspirons 8000 and
...@@ -208,8 +206,7 @@ static unsigned int speedstep_detect_chipset (void) ...@@ -208,8 +206,7 @@ static unsigned int speedstep_detect_chipset (void)
hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL, hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_MC,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_ANY_ID,
NULL); NULL);
if (!hostbridge) if (!hostbridge)
...@@ -236,7 +233,7 @@ static unsigned int _speedstep_get(const struct cpumask *cpus) ...@@ -236,7 +233,7 @@ static unsigned int _speedstep_get(const struct cpumask *cpus)
cpus_allowed = current->cpus_allowed; cpus_allowed = current->cpus_allowed;
set_cpus_allowed_ptr(current, cpus); set_cpus_allowed_ptr(current, cpus);
speed = speedstep_get_processor_frequency(speedstep_processor); speed = speedstep_get_frequency(speedstep_processor);
set_cpus_allowed_ptr(current, &cpus_allowed); set_cpus_allowed_ptr(current, &cpus_allowed);
dprintk("detected %u kHz as current frequency\n", speed); dprintk("detected %u kHz as current frequency\n", speed);
return speed; return speed;
...@@ -251,11 +248,12 @@ static unsigned int speedstep_get(unsigned int cpu) ...@@ -251,11 +248,12 @@ static unsigned int speedstep_get(unsigned int cpu)
* speedstep_target - set a new CPUFreq policy * speedstep_target - set a new CPUFreq policy
* @policy: new policy * @policy: new policy
* @target_freq: the target frequency * @target_freq: the target frequency
* @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H) * @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.
*/ */
static int speedstep_target (struct cpufreq_policy *policy, static int speedstep_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
...@@ -264,7 +262,8 @@ static int speedstep_target (struct cpufreq_policy *policy, ...@@ -264,7 +262,8 @@ static int speedstep_target (struct cpufreq_policy *policy,
cpumask_t cpus_allowed; cpumask_t cpus_allowed;
int i; int i;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
freqs.old = _speedstep_get(policy->cpus); freqs.old = _speedstep_get(policy->cpus);
...@@ -308,7 +307,7 @@ static int speedstep_target (struct cpufreq_policy *policy, ...@@ -308,7 +307,7 @@ static int speedstep_target (struct cpufreq_policy *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.
*/ */
static int speedstep_verify (struct cpufreq_policy *policy) static int speedstep_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
} }
...@@ -344,7 +343,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -344,7 +343,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
return -EIO; return -EIO;
dprintk("currently at %s speed setting - %i MHz\n", dprintk("currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
? "low" : "high",
(speed / 1000)); (speed / 1000));
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
...@@ -352,9 +352,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -352,9 +352,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
if (result) if (result)
return (result); return result;
cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
return 0; return 0;
} }
...@@ -366,7 +366,7 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy) ...@@ -366,7 +366,7 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static struct freq_attr* speedstep_attr[] = { static struct freq_attr *speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -396,13 +396,15 @@ static int __init speedstep_init(void) ...@@ -396,13 +396,15 @@ static int __init speedstep_init(void)
/* detect processor */ /* detect processor */
speedstep_processor = speedstep_detect_processor(); speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor) { if (!speedstep_processor) {
dprintk("Intel(R) SpeedStep(TM) capable processor not found\n"); dprintk("Intel(R) SpeedStep(TM) capable processor "
"not found\n");
return -ENODEV; return -ENODEV;
} }
/* detect chipset */ /* detect chipset */
if (!speedstep_detect_chipset()) { if (!speedstep_detect_chipset()) {
dprintk("Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n"); dprintk("Intel(R) SpeedStep(TM) for this chipset not "
"(yet) available.\n");
return -ENODEV; return -ENODEV;
} }
...@@ -431,9 +433,11 @@ static void __exit speedstep_exit(void) ...@@ -431,9 +433,11 @@ static void __exit speedstep_exit(void)
} }
MODULE_AUTHOR ("Dave Jones <davej@redhat.com>, Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR("Dave Jones <davej@redhat.com>, "
MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges."); "Dominik Brodowski <linux@brodo.de>");
MODULE_LICENSE ("GPL"); MODULE_DESCRIPTION("Speedstep driver for Intel mobile processors on chipsets "
"with ICH-M southbridges.");
MODULE_LICENSE("GPL");
module_init(speedstep_init); module_init(speedstep_init);
module_exit(speedstep_exit); module_exit(speedstep_exit);
...@@ -16,12 +16,16 @@ ...@@ -16,12 +16,16 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/tsc.h>
#include "speedstep-lib.h" #include "speedstep-lib.h"
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-lib", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"speedstep-lib", msg)
#define PFX "speedstep-lib: "
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
static int relaxed_check = 0; static int relaxed_check;
#else #else
#define relaxed_check 0 #define relaxed_check 0
#endif #endif
...@@ -30,14 +34,14 @@ static int relaxed_check = 0; ...@@ -30,14 +34,14 @@ static int relaxed_check = 0;
* GET PROCESSOR CORE SPEED IN KHZ * * GET PROCESSOR CORE SPEED IN KHZ *
*********************************************************************/ *********************************************************************/
static unsigned int pentium3_get_frequency (unsigned int processor) static unsigned int pentium3_get_frequency(unsigned int processor)
{ {
/* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */ /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
struct { struct {
unsigned int ratio; /* Frequency Multiplier (x10) */ unsigned int ratio; /* Frequency Multiplier (x10) */
u8 bitmap; /* power on configuration bits u8 bitmap; /* power on configuration bits
[27, 25:22] (in MSR 0x2a) */ [27, 25:22] (in MSR 0x2a) */
} msr_decode_mult [] = { } msr_decode_mult[] = {
{ 30, 0x01 }, { 30, 0x01 },
{ 35, 0x05 }, { 35, 0x05 },
{ 40, 0x02 }, { 40, 0x02 },
...@@ -52,7 +56,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor) ...@@ -52,7 +56,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
{ 85, 0x26 }, { 85, 0x26 },
{ 90, 0x20 }, { 90, 0x20 },
{ 100, 0x2b }, { 100, 0x2b },
{ 0, 0xff } /* error or unknown value */ { 0, 0xff } /* error or unknown value */
}; };
/* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */ /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
...@@ -60,7 +64,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor) ...@@ -60,7 +64,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
unsigned int value; /* Front Side Bus speed in MHz */ unsigned int value; /* Front Side Bus speed in MHz */
u8 bitmap; /* power on configuration bits [18: 19] u8 bitmap; /* power on configuration bits [18: 19]
(in MSR 0x2a) */ (in MSR 0x2a) */
} msr_decode_fsb [] = { } msr_decode_fsb[] = {
{ 66, 0x0 }, { 66, 0x0 },
{ 100, 0x2 }, { 100, 0x2 },
{ 133, 0x1 }, { 133, 0x1 },
...@@ -85,7 +89,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor) ...@@ -85,7 +89,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
} }
/* decode the multiplier */ /* decode the multiplier */
if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY) { if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
dprintk("workaround for early PIIIs\n"); dprintk("workaround for early PIIIs\n");
msr_lo &= 0x03c00000; msr_lo &= 0x03c00000;
} else } else
...@@ -97,9 +101,10 @@ static unsigned int pentium3_get_frequency (unsigned int processor) ...@@ -97,9 +101,10 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
j++; j++;
} }
dprintk("speed is %u\n", (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100)); dprintk("speed is %u\n",
(msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100); return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100;
} }
...@@ -112,20 +117,23 @@ static unsigned int pentiumM_get_frequency(void) ...@@ -112,20 +117,23 @@ static unsigned int pentiumM_get_frequency(void)
/* see table B-2 of 24547212.pdf */ /* see table B-2 of 24547212.pdf */
if (msr_lo & 0x00040000) { if (msr_lo & 0x00040000) {
printk(KERN_DEBUG "speedstep-lib: PM - invalid FSB: 0x%x 0x%x\n", msr_lo, msr_tmp); printk(KERN_DEBUG PFX "PM - invalid FSB: 0x%x 0x%x\n",
msr_lo, msr_tmp);
return 0; return 0;
} }
msr_tmp = (msr_lo >> 22) & 0x1f; msr_tmp = (msr_lo >> 22) & 0x1f;
dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * 100 * 1000)); dprintk("bits 22-26 are 0x%x, speed is %u\n",
msr_tmp, (msr_tmp * 100 * 1000));
return (msr_tmp * 100 * 1000); return msr_tmp * 100 * 1000;
} }
static unsigned int pentium_core_get_frequency(void) static unsigned int pentium_core_get_frequency(void)
{ {
u32 fsb = 0; u32 fsb = 0;
u32 msr_lo, msr_tmp; u32 msr_lo, msr_tmp;
int ret;
rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp); rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp);
/* see table B-2 of 25366920.pdf */ /* see table B-2 of 25366920.pdf */
...@@ -153,12 +161,15 @@ static unsigned int pentium_core_get_frequency(void) ...@@ -153,12 +161,15 @@ static unsigned int pentium_core_get_frequency(void)
} }
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
msr_lo, msr_tmp);
msr_tmp = (msr_lo >> 22) & 0x1f; msr_tmp = (msr_lo >> 22) & 0x1f;
dprintk("bits 22-26 are 0x%x, speed is %u\n", msr_tmp, (msr_tmp * fsb)); dprintk("bits 22-26 are 0x%x, speed is %u\n",
msr_tmp, (msr_tmp * fsb));
return (msr_tmp * fsb); ret = (msr_tmp * fsb);
return ret;
} }
...@@ -167,6 +178,16 @@ static unsigned int pentium4_get_frequency(void) ...@@ -167,6 +178,16 @@ static unsigned int pentium4_get_frequency(void)
struct cpuinfo_x86 *c = &boot_cpu_data; struct cpuinfo_x86 *c = &boot_cpu_data;
u32 msr_lo, msr_hi, mult; u32 msr_lo, msr_hi, mult;
unsigned int fsb = 0; unsigned int fsb = 0;
unsigned int ret;
u8 fsb_code;
/* Pentium 4 Model 0 and 1 do not have the Core Clock Frequency
* to System Bus Frequency Ratio Field in the Processor Frequency
* Configuration Register of the MSR. Therefore the current
* frequency cannot be calculated and has to be measured.
*/
if (c->x86_model < 2)
return cpu_khz;
rdmsr(0x2c, msr_lo, msr_hi); rdmsr(0x2c, msr_lo, msr_hi);
...@@ -177,62 +198,61 @@ static unsigned int pentium4_get_frequency(void) ...@@ -177,62 +198,61 @@ static unsigned int pentium4_get_frequency(void)
* revision #12 in Table B-1: MSRs in the Pentium 4 and * revision #12 in Table B-1: MSRs in the Pentium 4 and
* Intel Xeon Processors, on page B-4 and B-5. * Intel Xeon Processors, on page B-4 and B-5.
*/ */
if (c->x86_model < 2) fsb_code = (msr_lo >> 16) & 0x7;
switch (fsb_code) {
case 0:
fsb = 100 * 1000; fsb = 100 * 1000;
else { break;
u8 fsb_code = (msr_lo >> 16) & 0x7; case 1:
switch (fsb_code) { fsb = 13333 * 10;
case 0: break;
fsb = 100 * 1000; case 2:
break; fsb = 200 * 1000;
case 1: break;
fsb = 13333 * 10;
break;
case 2:
fsb = 200 * 1000;
break;
}
} }
if (!fsb) if (!fsb)
printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n"); printk(KERN_DEBUG PFX "couldn't detect FSB speed. "
"Please send an e-mail to <linux@brodo.de>\n");
/* Multiplier. */ /* Multiplier. */
mult = msr_lo >> 24; mult = msr_lo >> 24;
dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult)); dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
fsb, mult, (fsb * mult));
return (fsb * mult); ret = (fsb * mult);
return ret;
} }
unsigned int speedstep_get_processor_frequency(unsigned int processor) unsigned int speedstep_get_frequency(unsigned int processor)
{ {
switch (processor) { switch (processor) {
case SPEEDSTEP_PROCESSOR_PCORE: case SPEEDSTEP_CPU_PCORE:
return pentium_core_get_frequency(); return pentium_core_get_frequency();
case SPEEDSTEP_PROCESSOR_PM: case SPEEDSTEP_CPU_PM:
return pentiumM_get_frequency(); return pentiumM_get_frequency();
case SPEEDSTEP_PROCESSOR_P4D: case SPEEDSTEP_CPU_P4D:
case SPEEDSTEP_PROCESSOR_P4M: case SPEEDSTEP_CPU_P4M:
return pentium4_get_frequency(); return pentium4_get_frequency();
case SPEEDSTEP_PROCESSOR_PIII_T: case SPEEDSTEP_CPU_PIII_T:
case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_CPU_PIII_C:
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY: case SPEEDSTEP_CPU_PIII_C_EARLY:
return pentium3_get_frequency(processor); return pentium3_get_frequency(processor);
default: default:
return 0; return 0;
}; };
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(speedstep_get_processor_frequency); EXPORT_SYMBOL_GPL(speedstep_get_frequency);
/********************************************************************* /*********************************************************************
* DETECT SPEEDSTEP-CAPABLE PROCESSOR * * DETECT SPEEDSTEP-CAPABLE PROCESSOR *
*********************************************************************/ *********************************************************************/
unsigned int speedstep_detect_processor (void) unsigned int speedstep_detect_processor(void)
{ {
struct cpuinfo_x86 *c = &cpu_data(0); struct cpuinfo_x86 *c = &cpu_data(0);
u32 ebx, msr_lo, msr_hi; u32 ebx, msr_lo, msr_hi;
...@@ -261,7 +281,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -261,7 +281,7 @@ unsigned int speedstep_detect_processor (void)
* sample has ebx = 0x0f, production has 0x0e. * sample has ebx = 0x0f, production has 0x0e.
*/ */
if ((ebx == 0x0e) || (ebx == 0x0f)) if ((ebx == 0x0e) || (ebx == 0x0f))
return SPEEDSTEP_PROCESSOR_P4M; return SPEEDSTEP_CPU_P4M;
break; break;
case 7: case 7:
/* /*
...@@ -272,7 +292,7 @@ unsigned int speedstep_detect_processor (void) ...@@ -272,7 +292,7 @@ unsigned int speedstep_detect_processor (void)
* samples are only of B-stepping... * samples are only of B-stepping...
*/ */
if (ebx == 0x0e) if (ebx == 0x0e)
return SPEEDSTEP_PROCESSOR_P4M; return SPEEDSTEP_CPU_P4M;
break; break;
case 9: case 9:
/* /*
...@@ -288,10 +308,13 @@ unsigned int speedstep_detect_processor (void) ...@@ -288,10 +308,13 @@ unsigned int speedstep_detect_processor (void)
* M-P4-Ms may have either ebx=0xe or 0xf [see above] * M-P4-Ms may have either ebx=0xe or 0xf [see above]
* M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf] * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf]
* also, M-P4M HTs have ebx=0x8, too * also, M-P4M HTs have ebx=0x8, too
* For now, they are distinguished by the model_id string * For now, they are distinguished by the model_id
* string
*/ */
if ((ebx == 0x0e) || (strstr(c->x86_model_id,"Mobile Intel(R) Pentium(R) 4") != NULL)) if ((ebx == 0x0e) ||
return SPEEDSTEP_PROCESSOR_P4M; (strstr(c->x86_model_id,
"Mobile Intel(R) Pentium(R) 4") != NULL))
return SPEEDSTEP_CPU_P4M;
break; break;
default: default:
break; break;
...@@ -301,7 +324,8 @@ unsigned int speedstep_detect_processor (void) ...@@ -301,7 +324,8 @@ unsigned int speedstep_detect_processor (void)
switch (c->x86_model) { switch (c->x86_model) {
case 0x0B: /* Intel PIII [Tualatin] */ case 0x0B: /* Intel PIII [Tualatin] */
/* cpuid_ebx(1) is 0x04 for desktop PIII, 0x06 for mobile PIII-M */ /* cpuid_ebx(1) is 0x04 for desktop PIII,
* 0x06 for mobile PIII-M */
ebx = cpuid_ebx(0x00000001); ebx = cpuid_ebx(0x00000001);
dprintk("ebx is %x\n", ebx); dprintk("ebx is %x\n", ebx);
...@@ -313,14 +337,15 @@ unsigned int speedstep_detect_processor (void) ...@@ -313,14 +337,15 @@ unsigned int speedstep_detect_processor (void)
/* So far all PIII-M processors support SpeedStep. See /* So far all PIII-M processors support SpeedStep. See
* Intel's 24540640.pdf of June 2003 * Intel's 24540640.pdf of June 2003
*/ */
return SPEEDSTEP_PROCESSOR_PIII_T; return SPEEDSTEP_CPU_PIII_T;
case 0x08: /* Intel PIII [Coppermine] */ case 0x08: /* Intel PIII [Coppermine] */
/* all mobile PIII Coppermines have FSB 100 MHz /* all mobile PIII Coppermines have FSB 100 MHz
* ==> sort out a few desktop PIIIs. */ * ==> sort out a few desktop PIIIs. */
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi); dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
msr_lo, msr_hi);
msr_lo &= 0x00c0000; msr_lo &= 0x00c0000;
if (msr_lo != 0x0080000) if (msr_lo != 0x0080000)
return 0; return 0;
...@@ -332,13 +357,15 @@ unsigned int speedstep_detect_processor (void) ...@@ -332,13 +357,15 @@ unsigned int speedstep_detect_processor (void)
* bit 56 or 57 is set * bit 56 or 57 is set
*/ */
rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi); dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) { msr_lo, msr_hi);
if ((msr_hi & (1<<18)) &&
(relaxed_check ? 1 : (msr_hi & (3<<24)))) {
if (c->x86_mask == 0x01) { if (c->x86_mask == 0x01) {
dprintk("early PIII version\n"); dprintk("early PIII version\n");
return SPEEDSTEP_PROCESSOR_PIII_C_EARLY; return SPEEDSTEP_CPU_PIII_C_EARLY;
} else } else
return SPEEDSTEP_PROCESSOR_PIII_C; return SPEEDSTEP_CPU_PIII_C;
} }
default: default:
...@@ -369,7 +396,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -369,7 +396,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
dprintk("trying to determine both speeds\n"); dprintk("trying to determine both speeds\n");
/* get current speed */ /* get current speed */
prev_speed = speedstep_get_processor_frequency(processor); prev_speed = speedstep_get_frequency(processor);
if (!prev_speed) if (!prev_speed)
return -EIO; return -EIO;
...@@ -379,7 +406,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -379,7 +406,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
/* switch to low state */ /* switch to low state */
set_state(SPEEDSTEP_LOW); set_state(SPEEDSTEP_LOW);
*low_speed = speedstep_get_processor_frequency(processor); *low_speed = speedstep_get_frequency(processor);
if (!*low_speed) { if (!*low_speed) {
ret = -EIO; ret = -EIO;
goto out; goto out;
...@@ -398,7 +425,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -398,7 +425,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
if (transition_latency) if (transition_latency)
do_gettimeofday(&tv2); do_gettimeofday(&tv2);
*high_speed = speedstep_get_processor_frequency(processor); *high_speed = speedstep_get_frequency(processor);
if (!*high_speed) { if (!*high_speed) {
ret = -EIO; ret = -EIO;
goto out; goto out;
...@@ -426,9 +453,12 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -426,9 +453,12 @@ unsigned int speedstep_get_freqs(unsigned int processor,
/* check if the latency measurement is too high or too low /* check if the latency measurement is too high or too low
* and set it to a safe value (500uSec) in that case * and set it to a safe value (500uSec) in that case
*/ */
if (*transition_latency > 10000000 || *transition_latency < 50000) { if (*transition_latency > 10000000 ||
printk (KERN_WARNING "speedstep: frequency transition measured seems out of " *transition_latency < 50000) {
"range (%u nSec), falling back to a safe one of %u nSec.\n", printk(KERN_WARNING PFX "frequency transition "
"measured seems out of range (%u "
"nSec), falling back to a safe one of"
"%u nSec.\n",
*transition_latency, 500000); *transition_latency, 500000);
*transition_latency = 500000; *transition_latency = 500000;
} }
...@@ -436,15 +466,16 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -436,15 +466,16 @@ unsigned int speedstep_get_freqs(unsigned int processor,
out: out:
local_irq_restore(flags); local_irq_restore(flags);
return (ret); return ret;
} }
EXPORT_SYMBOL_GPL(speedstep_get_freqs); EXPORT_SYMBOL_GPL(speedstep_get_freqs);
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK #ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
module_param(relaxed_check, int, 0444); module_param(relaxed_check, int, 0444);
MODULE_PARM_DESC(relaxed_check, "Don't do all checks for speedstep capability."); MODULE_PARM_DESC(relaxed_check,
"Don't do all checks for speedstep capability.");
#endif #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");
...@@ -12,17 +12,17 @@ ...@@ -12,17 +12,17 @@
/* processors */ /* processors */
#define SPEEDSTEP_PROCESSOR_PIII_C_EARLY 0x00000001 /* Coppermine core */ #define SPEEDSTEP_CPU_PIII_C_EARLY 0x00000001 /* Coppermine core */
#define SPEEDSTEP_PROCESSOR_PIII_C 0x00000002 /* Coppermine core */ #define SPEEDSTEP_CPU_PIII_C 0x00000002 /* Coppermine core */
#define SPEEDSTEP_PROCESSOR_PIII_T 0x00000003 /* Tualatin core */ #define SPEEDSTEP_CPU_PIII_T 0x00000003 /* Tualatin core */
#define SPEEDSTEP_PROCESSOR_P4M 0x00000004 /* P4-M */ #define SPEEDSTEP_CPU_P4M 0x00000004 /* P4-M */
/* the following processors are not speedstep-capable and are not auto-detected /* the following processors are not speedstep-capable and are not auto-detected
* in speedstep_detect_processor(). However, their speed can be detected using * in speedstep_detect_processor(). However, their speed can be detected using
* the speedstep_get_processor_frequency() call. */ * the speedstep_get_frequency() call. */
#define SPEEDSTEP_PROCESSOR_PM 0xFFFFFF03 /* Pentium M */ #define SPEEDSTEP_CPU_PM 0xFFFFFF03 /* Pentium M */
#define SPEEDSTEP_PROCESSOR_P4D 0xFFFFFF04 /* desktop P4 */ #define SPEEDSTEP_CPU_P4D 0xFFFFFF04 /* desktop P4 */
#define SPEEDSTEP_PROCESSOR_PCORE 0xFFFFFF05 /* Core */ #define SPEEDSTEP_CPU_PCORE 0xFFFFFF05 /* Core */
/* speedstep states -- only two of them */ /* speedstep states -- only two of them */
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
extern unsigned int speedstep_detect_processor (void); extern unsigned int speedstep_detect_processor (void);
/* detect the current speed (in khz) of the processor */ /* detect the current speed (in khz) of the processor */
extern unsigned int speedstep_get_processor_frequency(unsigned int processor); extern unsigned int speedstep_get_frequency(unsigned int processor);
/* detect the low and high speeds of the processor. The callback /* detect the low and high speeds of the processor. The callback
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h>
#include <asm/ist.h> #include <asm/ist.h>
#include <asm/io.h>
#include "speedstep-lib.h" #include "speedstep-lib.h"
...@@ -30,12 +30,12 @@ ...@@ -30,12 +30,12 @@
* If user gives it, these are used. * If user gives it, these are used.
* *
*/ */
static int smi_port = 0; static int smi_port;
static int smi_cmd = 0; static int smi_cmd;
static unsigned int smi_sig = 0; static unsigned int smi_sig;
/* info about the processor */ /* info about the processor */
static unsigned int speedstep_processor = 0; static unsigned int speedstep_processor;
/* /*
* There are only two frequency states for each processor. Values * There are only two frequency states for each processor. Values
...@@ -56,12 +56,13 @@ static struct cpufreq_frequency_table speedstep_freqs[] = { ...@@ -56,12 +56,13 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
* of DMA activity going on? */ * of DMA activity going on? */
#define SMI_TRIES 5 #define SMI_TRIES 5
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-smi", msg) #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
"speedstep-smi", msg)
/** /**
* speedstep_smi_ownership * speedstep_smi_ownership
*/ */
static int speedstep_smi_ownership (void) static int speedstep_smi_ownership(void)
{ {
u32 command, result, magic, dummy; u32 command, result, magic, dummy;
u32 function = GET_SPEEDSTEP_OWNER; u32 function = GET_SPEEDSTEP_OWNER;
...@@ -70,16 +71,18 @@ static int speedstep_smi_ownership (void) ...@@ -70,16 +71,18 @@ static int speedstep_smi_ownership (void)
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
magic = virt_to_phys(magic_data); magic = virt_to_phys(magic_data);
dprintk("trying to obtain ownership with command %x at port %x\n", command, smi_port); dprintk("trying to obtain ownership with command %x at port %x\n",
command, smi_port);
__asm__ __volatile__( __asm__ __volatile__(
"push %%ebp\n" "push %%ebp\n"
"out %%al, (%%dx)\n" "out %%al, (%%dx)\n"
"pop %%ebp\n" "pop %%ebp\n"
: "=D" (result), "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy), : "=D" (result),
"=S" (dummy) "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
"=S" (dummy)
: "a" (command), "b" (function), "c" (0), "d" (smi_port), : "a" (command), "b" (function), "c" (0), "d" (smi_port),
"D" (0), "S" (magic) "D" (0), "S" (magic)
: "memory" : "memory"
); );
...@@ -97,10 +100,10 @@ static int speedstep_smi_ownership (void) ...@@ -97,10 +100,10 @@ static int speedstep_smi_ownership (void)
* 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)
{ {
u32 command, result = 0, edi, high_mhz, low_mhz, dummy; u32 command, result = 0, edi, high_mhz, low_mhz, dummy;
u32 state=0; u32 state = 0;
u32 function = GET_SPEEDSTEP_FREQS; u32 function = GET_SPEEDSTEP_FREQS;
if (!(ist_info.event & 0xFFFF)) { if (!(ist_info.event & 0xFFFF)) {
...@@ -110,17 +113,25 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high) ...@@ -110,17 +113,25 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
dprintk("trying to determine frequencies with command %x at port %x\n", command, smi_port); dprintk("trying to determine frequencies with command %x at port %x\n",
command, smi_port);
__asm__ __volatile__( __asm__ __volatile__(
"push %%ebp\n" "push %%ebp\n"
"out %%al, (%%dx)\n" "out %%al, (%%dx)\n"
"pop %%ebp" "pop %%ebp"
: "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi), "=S" (dummy) : "=a" (result),
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0) "=b" (high_mhz),
"=c" (low_mhz),
"=d" (state), "=D" (edi), "=S" (dummy)
: "a" (command),
"b" (function),
"c" (state),
"d" (smi_port), "S" (0), "D" (0)
); );
dprintk("result %x, low_freq %u, high_freq %u\n", result, low_mhz, high_mhz); dprintk("result %x, low_freq %u, high_freq %u\n",
result, low_mhz, high_mhz);
/* abort if results are obviously incorrect... */ /* abort if results are obviously incorrect... */
if ((high_mhz + low_mhz) < 600) if ((high_mhz + low_mhz) < 600)
...@@ -137,26 +148,30 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high) ...@@ -137,26 +148,30 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
* @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * @state: processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
* *
*/ */
static int speedstep_get_state (void) static int speedstep_get_state(void)
{ {
u32 function=GET_SPEEDSTEP_STATE; u32 function = GET_SPEEDSTEP_STATE;
u32 result, state, edi, command, dummy; u32 result, state, edi, command, dummy;
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
dprintk("trying to determine current setting with command %x at port %x\n", command, smi_port); dprintk("trying to determine current setting with command %x "
"at port %x\n", command, smi_port);
__asm__ __volatile__( __asm__ __volatile__(
"push %%ebp\n" "push %%ebp\n"
"out %%al, (%%dx)\n" "out %%al, (%%dx)\n"
"pop %%ebp\n" "pop %%ebp\n"
: "=a" (result), "=b" (state), "=D" (edi), "=c" (dummy), "=d" (dummy), "=S" (dummy) : "=a" (result),
: "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0), "D" (0) "=b" (state), "=D" (edi),
"=c" (dummy), "=d" (dummy), "=S" (dummy)
: "a" (command), "b" (function), "c" (0),
"d" (smi_port), "S" (0), "D" (0)
); );
dprintk("state is %x, result is %x\n", state, result); dprintk("state is %x, result is %x\n", state, result);
return (state & 1); return state & 1;
} }
...@@ -165,11 +180,11 @@ static int speedstep_get_state (void) ...@@ -165,11 +180,11 @@ static int speedstep_get_state (void)
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
* *
*/ */
static void speedstep_set_state (unsigned int state) static void speedstep_set_state(unsigned int state)
{ {
unsigned int result = 0, command, new_state, dummy; unsigned int result = 0, command, new_state, dummy;
unsigned long flags; unsigned long flags;
unsigned int function=SET_SPEEDSTEP_STATE; unsigned int function = SET_SPEEDSTEP_STATE;
unsigned int retry = 0; unsigned int retry = 0;
if (state > 0x1) if (state > 0x1)
...@@ -180,11 +195,14 @@ static void speedstep_set_state (unsigned int state) ...@@ -180,11 +195,14 @@ static void speedstep_set_state (unsigned int state)
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff); command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
dprintk("trying to set frequency to state %u with command %x at port %x\n", state, command, smi_port); dprintk("trying to set frequency to state %u "
"with command %x at port %x\n",
state, command, smi_port);
do { do {
if (retry) { if (retry) {
dprintk("retry %u, previous result %u, waiting...\n", retry, result); dprintk("retry %u, previous result %u, waiting...\n",
retry, result);
mdelay(retry * 50); mdelay(retry * 50);
} }
retry++; retry++;
...@@ -192,20 +210,26 @@ static void speedstep_set_state (unsigned int state) ...@@ -192,20 +210,26 @@ static void speedstep_set_state (unsigned int state)
"push %%ebp\n" "push %%ebp\n"
"out %%al, (%%dx)\n" "out %%al, (%%dx)\n"
"pop %%ebp" "pop %%ebp"
: "=b" (new_state), "=D" (result), "=c" (dummy), "=a" (dummy), : "=b" (new_state), "=D" (result),
"=d" (dummy), "=S" (dummy) "=c" (dummy), "=a" (dummy),
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0) "=d" (dummy), "=S" (dummy)
: "a" (command), "b" (function), "c" (state),
"d" (smi_port), "S" (0), "D" (0)
); );
} while ((new_state != state) && (retry <= SMI_TRIES)); } while ((new_state != state) && (retry <= SMI_TRIES));
/* enable IRQs */ /* enable IRQs */
local_irq_restore(flags); local_irq_restore(flags);
if (new_state == state) { if (new_state == state)
dprintk("change to %u MHz succeeded after %u tries with result %u\n", (speedstep_freqs[new_state].frequency / 1000), retry, result); dprintk("change to %u MHz succeeded after %u tries "
} else { "with result %u\n",
printk(KERN_ERR "cpufreq: change to state %u failed with new_state %u and result %u\n", state, new_state, result); (speedstep_freqs[new_state].frequency / 1000),
} retry, result);
else
printk(KERN_ERR "cpufreq: change to state %u "
"failed with new_state %u and result %u\n",
state, new_state, result);
return; return;
} }
...@@ -219,13 +243,14 @@ static void speedstep_set_state (unsigned int state) ...@@ -219,13 +243,14 @@ static void speedstep_set_state (unsigned int state)
* *
* Sets a new CPUFreq policy/freq. * Sets a new CPUFreq policy/freq.
*/ */
static int speedstep_target (struct cpufreq_policy *policy, static int speedstep_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation) unsigned int target_freq, unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
freqs.old = speedstep_freqs[speedstep_get_state()].frequency; freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
...@@ -250,7 +275,7 @@ static int speedstep_target (struct cpufreq_policy *policy, ...@@ -250,7 +275,7 @@ static int speedstep_target (struct cpufreq_policy *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.
*/ */
static int speedstep_verify (struct cpufreq_policy *policy) static int speedstep_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]);
} }
...@@ -259,7 +284,8 @@ static int speedstep_verify (struct cpufreq_policy *policy) ...@@ -259,7 +284,8 @@ static int speedstep_verify (struct cpufreq_policy *policy)
static int speedstep_cpu_init(struct cpufreq_policy *policy) static int speedstep_cpu_init(struct cpufreq_policy *policy)
{ {
int result; int result;
unsigned int speed,state; unsigned int speed, state;
unsigned int *low, *high;
/* capability check */ /* capability check */
if (policy->cpu != 0) if (policy->cpu != 0)
...@@ -272,19 +298,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -272,19 +298,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
} }
/* detect low and high frequency */ /* detect low and high frequency */
result = speedstep_smi_get_freqs(&speedstep_freqs[SPEEDSTEP_LOW].frequency, low = &speedstep_freqs[SPEEDSTEP_LOW].frequency;
&speedstep_freqs[SPEEDSTEP_HIGH].frequency); high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency;
result = speedstep_smi_get_freqs(low, high);
if (result) { if (result) {
/* fall back to speedstep_lib.c dection mechanism: try both states out */ /* fall back to speedstep_lib.c dection mechanism:
dprintk("could not detect low and high frequencies by SMI call.\n"); * try both states out */
dprintk("could not detect low and high frequencies "
"by SMI call.\n");
result = speedstep_get_freqs(speedstep_processor, result = speedstep_get_freqs(speedstep_processor,
&speedstep_freqs[SPEEDSTEP_LOW].frequency, low, high,
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
NULL, NULL,
&speedstep_set_state); &speedstep_set_state);
if (result) { if (result) {
dprintk("could not detect two different speeds -- aborting.\n"); dprintk("could not detect two different speeds"
" -- aborting.\n");
return result; return result;
} else } else
dprintk("workaround worked.\n"); dprintk("workaround worked.\n");
...@@ -295,7 +325,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -295,7 +325,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
speed = speedstep_freqs[state].frequency; speed = speedstep_freqs[state].frequency;
dprintk("currently at %s speed setting - %i MHz\n", dprintk("currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
? "low" : "high",
(speed / 1000)); (speed / 1000));
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
...@@ -304,7 +335,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -304,7 +335,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs); result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
if (result) if (result)
return (result); return result;
cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu); cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
...@@ -321,7 +352,7 @@ static unsigned int speedstep_get(unsigned int cpu) ...@@ -321,7 +352,7 @@ static unsigned int speedstep_get(unsigned int cpu)
{ {
if (cpu) if (cpu)
return -ENODEV; return -ENODEV;
return speedstep_get_processor_frequency(speedstep_processor); return speedstep_get_frequency(speedstep_processor);
} }
...@@ -335,7 +366,7 @@ static int speedstep_resume(struct cpufreq_policy *policy) ...@@ -335,7 +366,7 @@ static int speedstep_resume(struct cpufreq_policy *policy)
return result; return result;
} }
static struct freq_attr* speedstep_attr[] = { static struct freq_attr *speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
}; };
...@@ -364,21 +395,23 @@ static int __init speedstep_init(void) ...@@ -364,21 +395,23 @@ static int __init speedstep_init(void)
speedstep_processor = speedstep_detect_processor(); speedstep_processor = speedstep_detect_processor();
switch (speedstep_processor) { switch (speedstep_processor) {
case SPEEDSTEP_PROCESSOR_PIII_T: case SPEEDSTEP_CPU_PIII_T:
case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_CPU_PIII_C:
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY: case SPEEDSTEP_CPU_PIII_C_EARLY:
break; break;
default: default:
speedstep_processor = 0; speedstep_processor = 0;
} }
if (!speedstep_processor) { if (!speedstep_processor) {
dprintk ("No supported Intel CPU detected.\n"); dprintk("No supported Intel CPU detected.\n");
return -ENODEV; return -ENODEV;
} }
dprintk("signature:0x%.8lx, command:0x%.8lx, event:0x%.8lx, perf_level:0x%.8lx.\n", dprintk("signature:0x%.8lx, command:0x%.8lx, "
ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level); "event:0x%.8lx, perf_level:0x%.8lx.\n",
ist_info.signature, ist_info.command,
ist_info.event, ist_info.perf_level);
/* Error if no IST-SMI BIOS or no PARM /* Error if no IST-SMI BIOS or no PARM
sig= 'ISGE' aka 'Intel Speedstep Gate E' */ sig= 'ISGE' aka 'Intel Speedstep Gate E' */
...@@ -416,17 +449,20 @@ static void __exit speedstep_exit(void) ...@@ -416,17 +449,20 @@ static void __exit speedstep_exit(void)
cpufreq_unregister_driver(&speedstep_driver); cpufreq_unregister_driver(&speedstep_driver);
} }
module_param(smi_port, int, 0444); module_param(smi_port, int, 0444);
module_param(smi_cmd, int, 0444); module_param(smi_cmd, int, 0444);
module_param(smi_sig, uint, 0444); module_param(smi_sig, uint, 0444);
MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value -- Intel's default setting is 0xb2"); MODULE_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value "
MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value -- Intel's default setting is 0x82"); "-- Intel's default setting is 0xb2");
MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the SMI interface."); MODULE_PARM_DESC(smi_cmd, "Override the BIOS-given IST command with this value "
"-- Intel's default setting is 0x82");
MODULE_PARM_DESC(smi_sig, "Set to 1 to fake the IST signature when using the "
"SMI interface.");
MODULE_AUTHOR ("Hiroshi Miura"); MODULE_AUTHOR("Hiroshi Miura");
MODULE_DESCRIPTION ("Speedstep driver for IST applet SMI interface."); MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface.");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
module_init(speedstep_init); module_init(speedstep_init);
module_exit(speedstep_exit); module_exit(speedstep_exit);
...@@ -543,8 +543,6 @@ unsigned long native_calibrate_tsc(void) ...@@ -543,8 +543,6 @@ unsigned long native_calibrate_tsc(void)
return tsc_pit_min; return tsc_pit_min;
} }
#ifdef CONFIG_X86_32
/* Only called from the Powernow K7 cpu freq driver */
int recalibrate_cpu_khz(void) int recalibrate_cpu_khz(void)
{ {
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
...@@ -566,7 +564,6 @@ int recalibrate_cpu_khz(void) ...@@ -566,7 +564,6 @@ int recalibrate_cpu_khz(void)
EXPORT_SYMBOL(recalibrate_cpu_khz); EXPORT_SYMBOL(recalibrate_cpu_khz);
#endif /* CONFIG_X86_32 */
/* Accelerators for sched_clock() /* Accelerators for sched_clock()
* convert from cycles(64bits) => nanoseconds (64bits) * convert from cycles(64bits) => nanoseconds (64bits)
......
...@@ -104,7 +104,8 @@ EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write); ...@@ -104,7 +104,8 @@ EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
/* internal prototypes */ /* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); static int __cpufreq_governor(struct cpufreq_policy *policy,
unsigned int event);
static unsigned int __cpufreq_get(unsigned int cpu); static unsigned int __cpufreq_get(unsigned int cpu);
static void handle_update(struct work_struct *work); static void handle_update(struct work_struct *work);
...@@ -128,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void) ...@@ -128,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void)
pure_initcall(init_cpufreq_transition_notifier_list); pure_initcall(init_cpufreq_transition_notifier_list);
static LIST_HEAD(cpufreq_governor_list); static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX (cpufreq_governor_mutex); static DEFINE_MUTEX(cpufreq_governor_mutex);
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{ {
...@@ -371,7 +372,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor) ...@@ -371,7 +372,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor)
struct cpufreq_governor *t; struct cpufreq_governor *t;
list_for_each_entry(t, &cpufreq_governor_list, governor_list) list_for_each_entry(t, &cpufreq_governor_list, governor_list)
if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) if (!strnicmp(str_governor, t->name, CPUFREQ_NAME_LEN))
return t; return t;
return NULL; return NULL;
...@@ -429,15 +430,11 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, ...@@ -429,15 +430,11 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
mutex_unlock(&cpufreq_governor_mutex); mutex_unlock(&cpufreq_governor_mutex);
} }
out: out:
return err; return err;
} }
/* drivers/base/cpu.c */
extern struct sysdev_class cpu_sysdev_class;
/** /**
* cpufreq_per_cpu_attr_read() / show_##file_name() - * cpufreq_per_cpu_attr_read() / show_##file_name() -
* print out cpufreq information * print out cpufreq information
...@@ -450,11 +447,12 @@ extern struct sysdev_class cpu_sysdev_class; ...@@ -450,11 +447,12 @@ extern struct sysdev_class cpu_sysdev_class;
static ssize_t show_##file_name \ static ssize_t show_##file_name \
(struct cpufreq_policy *policy, char *buf) \ (struct cpufreq_policy *policy, char *buf) \
{ \ { \
return sprintf (buf, "%u\n", policy->object); \ return sprintf(buf, "%u\n", policy->object); \
} }
show_one(cpuinfo_min_freq, cpuinfo.min_freq); show_one(cpuinfo_min_freq, cpuinfo.min_freq);
show_one(cpuinfo_max_freq, cpuinfo.max_freq); show_one(cpuinfo_max_freq, cpuinfo.max_freq);
show_one(cpuinfo_transition_latency, cpuinfo.transition_latency);
show_one(scaling_min_freq, min); show_one(scaling_min_freq, min);
show_one(scaling_max_freq, max); show_one(scaling_max_freq, max);
show_one(scaling_cur_freq, cur); show_one(scaling_cur_freq, cur);
...@@ -476,7 +474,7 @@ static ssize_t store_##file_name \ ...@@ -476,7 +474,7 @@ static ssize_t store_##file_name \
if (ret) \ if (ret) \
return -EINVAL; \ return -EINVAL; \
\ \
ret = sscanf (buf, "%u", &new_policy.object); \ ret = sscanf(buf, "%u", &new_policy.object); \
if (ret != 1) \ if (ret != 1) \
return -EINVAL; \ return -EINVAL; \
\ \
...@@ -486,8 +484,8 @@ static ssize_t store_##file_name \ ...@@ -486,8 +484,8 @@ static ssize_t store_##file_name \
return ret ? ret : count; \ return ret ? ret : count; \
} }
store_one(scaling_min_freq,min); store_one(scaling_min_freq, min);
store_one(scaling_max_freq,max); store_one(scaling_max_freq, max);
/** /**
* show_cpuinfo_cur_freq - current CPU frequency as detected by hardware * show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
...@@ -507,12 +505,13 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy, ...@@ -507,12 +505,13 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
*/ */
static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
{ {
if(policy->policy == CPUFREQ_POLICY_POWERSAVE) if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
return sprintf(buf, "powersave\n"); return sprintf(buf, "powersave\n");
else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
return sprintf(buf, "performance\n"); return sprintf(buf, "performance\n");
else if (policy->governor) else if (policy->governor)
return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", policy->governor->name); return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n",
policy->governor->name);
return -EINVAL; return -EINVAL;
} }
...@@ -531,7 +530,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, ...@@ -531,7 +530,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
if (ret) if (ret)
return ret; return ret;
ret = sscanf (buf, "%15s", str_governor); ret = sscanf(buf, "%15s", str_governor);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
...@@ -575,7 +574,8 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, ...@@ -575,7 +574,8 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
} }
list_for_each_entry(t, &cpufreq_governor_list, governor_list) { list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2))) if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
- (CPUFREQ_NAME_LEN + 2)))
goto out; goto out;
i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name); i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name);
} }
...@@ -594,7 +594,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf) ...@@ -594,7 +594,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
if (i >= (PAGE_SIZE - 5)) if (i >= (PAGE_SIZE - 5))
break; break;
} }
i += sprintf(&buf[i], "\n"); i += sprintf(&buf[i], "\n");
return i; return i;
...@@ -660,6 +660,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name) ...@@ -660,6 +660,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
define_one_ro0400(cpuinfo_cur_freq); define_one_ro0400(cpuinfo_cur_freq);
define_one_ro(cpuinfo_min_freq); define_one_ro(cpuinfo_min_freq);
define_one_ro(cpuinfo_max_freq); define_one_ro(cpuinfo_max_freq);
define_one_ro(cpuinfo_transition_latency);
define_one_ro(scaling_available_governors); define_one_ro(scaling_available_governors);
define_one_ro(scaling_driver); define_one_ro(scaling_driver);
define_one_ro(scaling_cur_freq); define_one_ro(scaling_cur_freq);
...@@ -673,6 +674,7 @@ define_one_rw(scaling_setspeed); ...@@ -673,6 +674,7 @@ define_one_rw(scaling_setspeed);
static struct attribute *default_attrs[] = { static struct attribute *default_attrs[] = {
&cpuinfo_min_freq.attr, &cpuinfo_min_freq.attr,
&cpuinfo_max_freq.attr, &cpuinfo_max_freq.attr,
&cpuinfo_transition_latency.attr,
&scaling_min_freq.attr, &scaling_min_freq.attr,
&scaling_max_freq.attr, &scaling_max_freq.attr,
&affected_cpus.attr, &affected_cpus.attr,
...@@ -684,10 +686,10 @@ static struct attribute *default_attrs[] = { ...@@ -684,10 +686,10 @@ static struct attribute *default_attrs[] = {
NULL NULL
}; };
#define to_policy(k) container_of(k,struct cpufreq_policy,kobj) #define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
#define to_attr(a) container_of(a,struct freq_attr,attr) #define to_attr(a) container_of(a, struct freq_attr, attr)
static ssize_t show(struct kobject *kobj, struct attribute *attr ,char *buf) static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
{ {
struct cpufreq_policy *policy = to_policy(kobj); struct cpufreq_policy *policy = to_policy(kobj);
struct freq_attr *fattr = to_attr(attr); struct freq_attr *fattr = to_attr(attr);
...@@ -853,10 +855,10 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) ...@@ -853,10 +855,10 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
if (cpu == j) if (cpu == j)
continue; continue;
/* check for existing affected CPUs. They may not be aware /* Check for existing affected CPUs.
* of it due to CPU Hotplug. * They may not be aware of it due to CPU Hotplug.
*/ */
managed_policy = cpufreq_cpu_get(j); // FIXME: Where is this released? What about error paths? managed_policy = cpufreq_cpu_get(j); /* FIXME: Where is this released? What about error paths? */
if (unlikely(managed_policy)) { if (unlikely(managed_policy)) {
/* Set proper policy_cpu */ /* Set proper policy_cpu */
...@@ -1127,8 +1129,8 @@ static void handle_update(struct work_struct *work) ...@@ -1127,8 +1129,8 @@ static void handle_update(struct work_struct *work)
* @old_freq: CPU frequency the kernel thinks the CPU runs at * @old_freq: CPU frequency the kernel thinks the CPU runs at
* @new_freq: CPU frequency the CPU actually runs at * @new_freq: CPU frequency the CPU actually runs at
* *
* We adjust to current frequency first, and need to clean up later. So either call * We adjust to current frequency first, and need to clean up later.
* to cpufreq_update_policy() or schedule handle_update()). * So either call to cpufreq_update_policy() or schedule handle_update()).
*/ */
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
unsigned int new_freq) unsigned int new_freq)
...@@ -1610,7 +1612,8 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); ...@@ -1610,7 +1612,8 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
/** /**
* cpufreq_get_policy - get the current cpufreq_policy * cpufreq_get_policy - get the current cpufreq_policy
* @policy: struct cpufreq_policy into which the current cpufreq_policy is written * @policy: struct cpufreq_policy into which the current cpufreq_policy
* is written
* *
* Reads the current cpufreq policy. * Reads the current cpufreq policy.
*/ */
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Copyright (C) 2001 Russell King * Copyright (C) 2001 Russell King
* (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* Jun Nakajima <jun.nakajima@intel.com> * Jun Nakajima <jun.nakajima@intel.com>
* (C) 2004 Alexander Clouter <alex-kernel@digriz.org.uk> * (C) 2009 Alexander Clouter <alex@digriz.org.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -13,22 +13,17 @@ ...@@ -13,22 +13,17 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/smp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ctype.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/sysctl.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/kmod.h>
#include <linux/workqueue.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/percpu.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/hrtimer.h>
#include <linux/tick.h>
#include <linux/ktime.h>
#include <linux/sched.h>
/* /*
* dbs is used in this file as a shortform for demandbased switching * dbs is used in this file as a shortform for demandbased switching
* It helps to keep variable names smaller, simpler * It helps to keep variable names smaller, simpler
...@@ -43,19 +38,31 @@ ...@@ -43,19 +38,31 @@
* latency of the processor. The governor will work on any processor with * latency of the processor. The governor will work on any processor with
* transition latency <= 10mS, using appropriate sampling * transition latency <= 10mS, using appropriate sampling
* rate. * rate.
* For CPUs with transition latency > 10mS (mostly drivers * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
* with CPUFREQ_ETERNAL), this governor will not work. * this governor will not work.
* All times here are in uS. * All times here are in uS.
*/ */
static unsigned int def_sampling_rate; static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE_RATIO (2) #define MIN_SAMPLING_RATE_RATIO (2)
/* for correct statistics, we need at least 10 ticks between each measure */ /* for correct statistics, we need at least 10 ticks between each measure */
#define MIN_STAT_SAMPLING_RATE \ #define MIN_STAT_SAMPLING_RATE \
(MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
#define MIN_SAMPLING_RATE \ #define MIN_SAMPLING_RATE \
(def_sampling_rate / MIN_SAMPLING_RATE_RATIO) (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon
* Define the minimal settable sampling rate to the greater of:
* - "HW transition latency" * 100 (same as default sampling / 10)
* - MIN_STAT_SAMPLING_RATE
* To avoid that userspace shoots itself.
*/
static unsigned int minimum_sampling_rate(void)
{
return max(def_sampling_rate / 10, MIN_STAT_SAMPLING_RATE);
}
/* This will also vanish soon with removing sampling_rate_max */
#define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1) #define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10) #define MAX_SAMPLING_DOWN_FACTOR (10)
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
...@@ -63,12 +70,15 @@ static unsigned int def_sampling_rate; ...@@ -63,12 +70,15 @@ static unsigned int def_sampling_rate;
static void do_dbs_timer(struct work_struct *work); static void do_dbs_timer(struct work_struct *work);
struct cpu_dbs_info_s { struct cpu_dbs_info_s {
cputime64_t prev_cpu_idle;
cputime64_t prev_cpu_wall;
cputime64_t prev_cpu_nice;
struct cpufreq_policy *cur_policy; struct cpufreq_policy *cur_policy;
unsigned int prev_cpu_idle_up; struct delayed_work work;
unsigned int prev_cpu_idle_down;
unsigned int enable;
unsigned int down_skip; unsigned int down_skip;
unsigned int requested_freq; unsigned int requested_freq;
int cpu;
unsigned int enable:1;
}; };
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
...@@ -82,19 +92,18 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ ...@@ -82,19 +92,18 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
* cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
* is recursive for the same process. -Venki * is recursive for the same process. -Venki
*/ */
static DEFINE_MUTEX (dbs_mutex); static DEFINE_MUTEX(dbs_mutex);
static DECLARE_DELAYED_WORK(dbs_work, do_dbs_timer);
struct dbs_tuners { static struct workqueue_struct *kconservative_wq;
static struct dbs_tuners {
unsigned int sampling_rate; unsigned int sampling_rate;
unsigned int sampling_down_factor; unsigned int sampling_down_factor;
unsigned int up_threshold; unsigned int up_threshold;
unsigned int down_threshold; unsigned int down_threshold;
unsigned int ignore_nice; unsigned int ignore_nice;
unsigned int freq_step; unsigned int freq_step;
}; } dbs_tuners_ins = {
static struct dbs_tuners dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD, .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
.down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
...@@ -102,18 +111,37 @@ static struct dbs_tuners dbs_tuners_ins = { ...@@ -102,18 +111,37 @@ static struct dbs_tuners dbs_tuners_ins = {
.freq_step = 5, .freq_step = 5,
}; };
static inline unsigned int get_cpu_idle_time(unsigned int cpu) static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
cputime64_t *wall)
{ {
unsigned int add_nice = 0, ret; cputime64_t idle_time;
cputime64_t cur_wall_time;
cputime64_t busy_time;
if (dbs_tuners_ins.ignore_nice) cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
add_nice = kstat_cpu(cpu).cpustat.nice; busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
kstat_cpu(cpu).cpustat.system);
busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.irq);
busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.softirq);
busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.steal);
busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.nice);
idle_time = cputime64_sub(cur_wall_time, busy_time);
if (wall)
*wall = cur_wall_time;
return idle_time;
}
static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
{
u64 idle_time = get_cpu_idle_time_us(cpu, wall);
ret = kstat_cpu(cpu).cpustat.idle + if (idle_time == -1ULL)
kstat_cpu(cpu).cpustat.iowait + return get_cpu_idle_time_jiffy(cpu, wall);
add_nice;
return ret; return idle_time;
} }
/* keep track of frequency transitions */ /* keep track of frequency transitions */
...@@ -125,10 +153,21 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, ...@@ -125,10 +153,21 @@ dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info, struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info,
freq->cpu); freq->cpu);
struct cpufreq_policy *policy;
if (!this_dbs_info->enable) if (!this_dbs_info->enable)
return 0; return 0;
this_dbs_info->requested_freq = freq->new; policy = this_dbs_info->cur_policy;
/*
* we only care if our internally tracked freq moves outside
* the 'valid' ranges of freqency available to us otherwise
* we do not change it
*/
if (this_dbs_info->requested_freq > policy->max
|| this_dbs_info->requested_freq < policy->min)
this_dbs_info->requested_freq = freq->new;
return 0; return 0;
} }
...@@ -140,16 +179,31 @@ static struct notifier_block dbs_cpufreq_notifier_block = { ...@@ -140,16 +179,31 @@ static struct notifier_block dbs_cpufreq_notifier_block = {
/************************** sysfs interface ************************/ /************************** sysfs interface ************************/
static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
{ {
return sprintf (buf, "%u\n", MAX_SAMPLING_RATE); static int print_once;
if (!print_once) {
printk(KERN_INFO "CPUFREQ: conservative sampling_rate_max "
"sysfs file is deprecated - used by: %s\n",
current->comm);
print_once = 1;
}
return sprintf(buf, "%u\n", MAX_SAMPLING_RATE);
} }
static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf) static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
{ {
return sprintf (buf, "%u\n", MIN_SAMPLING_RATE); static int print_once;
if (!print_once) {
printk(KERN_INFO "CPUFREQ: conservative sampling_rate_max "
"sysfs file is deprecated - used by: %s\n", current->comm);
print_once = 1;
}
return sprintf(buf, "%u\n", MIN_SAMPLING_RATE);
} }
#define define_one_ro(_name) \ #define define_one_ro(_name) \
static struct freq_attr _name = \ static struct freq_attr _name = \
__ATTR(_name, 0444, show_##_name, NULL) __ATTR(_name, 0444, show_##_name, NULL)
define_one_ro(sampling_rate_max); define_one_ro(sampling_rate_max);
...@@ -174,7 +228,8 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, ...@@ -174,7 +228,8 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf (buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL; return -EINVAL;
...@@ -190,15 +245,13 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused, ...@@ -190,15 +245,13 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf (buf, "%u", &input); ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex); if (ret != 1)
if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
mutex_unlock(&dbs_mutex);
return -EINVAL; return -EINVAL;
}
dbs_tuners_ins.sampling_rate = input; mutex_lock(&dbs_mutex);
dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate());
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
return count; return count;
...@@ -209,10 +262,11 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused, ...@@ -209,10 +262,11 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf (buf, "%u", &input); ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex); mutex_lock(&dbs_mutex);
if (ret != 1 || input > 100 || input <= dbs_tuners_ins.down_threshold) { if (ret != 1 || input > 100 ||
input <= dbs_tuners_ins.down_threshold) {
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
return -EINVAL; return -EINVAL;
} }
...@@ -228,10 +282,12 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused, ...@@ -228,10 +282,12 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused,
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf (buf, "%u", &input); ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex); mutex_lock(&dbs_mutex);
if (ret != 1 || input > 100 || input >= dbs_tuners_ins.up_threshold) { /* cannot be lower than 11 otherwise freq will not fall */
if (ret != 1 || input < 11 || input > 100 ||
input >= dbs_tuners_ins.up_threshold) {
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
return -EINVAL; return -EINVAL;
} }
...@@ -264,12 +320,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy, ...@@ -264,12 +320,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
} }
dbs_tuners_ins.ignore_nice = input; dbs_tuners_ins.ignore_nice = input;
/* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */ /* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) { for_each_online_cpu(j) {
struct cpu_dbs_info_s *j_dbs_info; struct cpu_dbs_info_s *dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j); dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; &dbs_info->prev_cpu_wall);
if (dbs_tuners_ins.ignore_nice)
dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
} }
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
...@@ -281,7 +339,6 @@ static ssize_t store_freq_step(struct cpufreq_policy *policy, ...@@ -281,7 +339,6 @@ static ssize_t store_freq_step(struct cpufreq_policy *policy,
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if (ret != 1) if (ret != 1)
...@@ -310,7 +367,7 @@ define_one_rw(down_threshold); ...@@ -310,7 +367,7 @@ define_one_rw(down_threshold);
define_one_rw(ignore_nice_load); define_one_rw(ignore_nice_load);
define_one_rw(freq_step); define_one_rw(freq_step);
static struct attribute * dbs_attributes[] = { static struct attribute *dbs_attributes[] = {
&sampling_rate_max.attr, &sampling_rate_max.attr,
&sampling_rate_min.attr, &sampling_rate_min.attr,
&sampling_rate.attr, &sampling_rate.attr,
...@@ -329,55 +386,78 @@ static struct attribute_group dbs_attr_group = { ...@@ -329,55 +386,78 @@ static struct attribute_group dbs_attr_group = {
/************************** sysfs end ************************/ /************************** sysfs end ************************/
static void dbs_check_cpu(int cpu) static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
{ {
unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; unsigned int load = 0;
unsigned int tmp_idle_ticks, total_idle_ticks;
unsigned int freq_target; unsigned int freq_target;
unsigned int freq_down_sampling_rate;
struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
struct cpufreq_policy *policy;
if (!this_dbs_info->enable) struct cpufreq_policy *policy;
return; unsigned int j;
policy = this_dbs_info->cur_policy; policy = this_dbs_info->cur_policy;
/* /*
* The default safe range is 20% to 80% * Every sampling_rate, we check, if current idle time is less
* Every sampling_rate, we check * than 20% (default), then we try to increase frequency
* - If current idle time is less than 20%, then we try to * Every sampling_rate*sampling_down_factor, we check, if current
* increase frequency * idle time is more than 80%, then we try to decrease frequency
* Every sampling_rate*sampling_down_factor, we check
* - If current idle time is more than 80%, then we try to
* decrease frequency
* *
* Any frequency increase takes it to the maximum frequency. * Any frequency increase takes it to the maximum frequency.
* Frequency reduction happens at minimum steps of * Frequency reduction happens at minimum steps of
* 5% (default) of max_frequency * 5% (default) of maximum frequency
*/ */
/* Check for frequency increase */ /* Get Absolute Load */
idle_ticks = UINT_MAX; for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
cputime64_t cur_wall_time, cur_idle_time;
unsigned int idle_time, wall_time;
/* Check for frequency increase */ j_dbs_info = &per_cpu(cpu_dbs_info, j);
total_idle_ticks = get_cpu_idle_time(cpu);
tmp_idle_ticks = total_idle_ticks - cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
this_dbs_info->prev_cpu_idle_up;
this_dbs_info->prev_cpu_idle_up = total_idle_ticks; wall_time = (unsigned int) cputime64_sub(cur_wall_time,
j_dbs_info->prev_cpu_wall);
j_dbs_info->prev_cpu_wall = cur_wall_time;
idle_time = (unsigned int) cputime64_sub(cur_idle_time,
j_dbs_info->prev_cpu_idle);
j_dbs_info->prev_cpu_idle = cur_idle_time;
if (dbs_tuners_ins.ignore_nice) {
cputime64_t cur_nice;
unsigned long cur_nice_jiffies;
cur_nice = cputime64_sub(kstat_cpu(j).cpustat.nice,
j_dbs_info->prev_cpu_nice);
/*
* Assumption: nice time between sampling periods will
* be less than 2^32 jiffies for 32 bit sys
*/
cur_nice_jiffies = (unsigned long)
cputime64_to_jiffies64(cur_nice);
if (tmp_idle_ticks < idle_ticks) j_dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
idle_ticks = tmp_idle_ticks; idle_time += jiffies_to_usecs(cur_nice_jiffies);
}
if (unlikely(!wall_time || wall_time < idle_time))
continue;
load = 100 * (wall_time - idle_time) / wall_time;
}
/* Scale idle ticks by 100 and compare with up and down ticks */ /*
idle_ticks *= 100; * break out if we 'cannot' reduce the speed as the user might
up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) * * want freq_step to be zero
usecs_to_jiffies(dbs_tuners_ins.sampling_rate); */
if (dbs_tuners_ins.freq_step == 0)
return;
if (idle_ticks < up_idle_ticks) { /* Check for frequency increase */
if (load > dbs_tuners_ins.up_threshold) {
this_dbs_info->down_skip = 0; this_dbs_info->down_skip = 0;
this_dbs_info->prev_cpu_idle_down =
this_dbs_info->prev_cpu_idle_up;
/* if we are already at full speed then break out early */ /* if we are already at full speed then break out early */
if (this_dbs_info->requested_freq == policy->max) if (this_dbs_info->requested_freq == policy->max)
...@@ -398,49 +478,24 @@ static void dbs_check_cpu(int cpu) ...@@ -398,49 +478,24 @@ static void dbs_check_cpu(int cpu)
return; return;
} }
/* Check for frequency decrease */ /*
this_dbs_info->down_skip++; * The optimal frequency is the frequency that is the lowest that
if (this_dbs_info->down_skip < dbs_tuners_ins.sampling_down_factor) * can support the current CPU usage without triggering the up
return; * policy. To be safe, we focus 10 points under the threshold.
*/
/* Check for frequency decrease */ if (load < (dbs_tuners_ins.down_threshold - 10)) {
total_idle_ticks = this_dbs_info->prev_cpu_idle_up;
tmp_idle_ticks = total_idle_ticks -
this_dbs_info->prev_cpu_idle_down;
this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
/* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100;
this_dbs_info->down_skip = 0;
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor;
down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
usecs_to_jiffies(freq_down_sampling_rate);
if (idle_ticks > down_idle_ticks) {
/*
* if we are already at the lowest speed then break out early
* or if we 'cannot' reduce the speed as the user might want
* freq_target to be zero
*/
if (this_dbs_info->requested_freq == policy->min
|| dbs_tuners_ins.freq_step == 0)
return;
freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100;
/* max freq cannot be less than 100. But who knows.... */
if (unlikely(freq_target == 0))
freq_target = 5;
this_dbs_info->requested_freq -= freq_target; this_dbs_info->requested_freq -= freq_target;
if (this_dbs_info->requested_freq < policy->min) if (this_dbs_info->requested_freq < policy->min)
this_dbs_info->requested_freq = policy->min; this_dbs_info->requested_freq = policy->min;
/*
* if we cannot reduce the frequency anymore, break out early
*/
if (policy->cur == policy->min)
return;
__cpufreq_driver_target(policy, this_dbs_info->requested_freq, __cpufreq_driver_target(policy, this_dbs_info->requested_freq,
CPUFREQ_RELATION_H); CPUFREQ_RELATION_H);
return; return;
...@@ -449,27 +504,45 @@ static void dbs_check_cpu(int cpu) ...@@ -449,27 +504,45 @@ static void dbs_check_cpu(int cpu)
static void do_dbs_timer(struct work_struct *work) static void do_dbs_timer(struct work_struct *work)
{ {
int i; struct cpu_dbs_info_s *dbs_info =
mutex_lock(&dbs_mutex); container_of(work, struct cpu_dbs_info_s, work.work);
for_each_online_cpu(i) unsigned int cpu = dbs_info->cpu;
dbs_check_cpu(i);
schedule_delayed_work(&dbs_work, /* We want all CPUs to do sampling nearly on same jiffy */
usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
mutex_unlock(&dbs_mutex);
delay -= jiffies % delay;
if (lock_policy_rwsem_write(cpu) < 0)
return;
if (!dbs_info->enable) {
unlock_policy_rwsem_write(cpu);
return;
}
dbs_check_cpu(dbs_info);
queue_delayed_work_on(cpu, kconservative_wq, &dbs_info->work, delay);
unlock_policy_rwsem_write(cpu);
} }
static inline void dbs_timer_init(void) static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
{ {
init_timer_deferrable(&dbs_work.timer); /* We want all CPUs to do sampling nearly on same jiffy */
schedule_delayed_work(&dbs_work, int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); delay -= jiffies % delay;
return;
dbs_info->enable = 1;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
delay);
} }
static inline void dbs_timer_exit(void) static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{ {
cancel_delayed_work(&dbs_work); dbs_info->enable = 0;
return; cancel_delayed_work(&dbs_info->work);
} }
static int cpufreq_governor_dbs(struct cpufreq_policy *policy, static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
...@@ -503,11 +576,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -503,11 +576,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info = &per_cpu(cpu_dbs_info, j); j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy; j_dbs_info->cur_policy = policy;
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(cpu); j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
j_dbs_info->prev_cpu_idle_down &j_dbs_info->prev_cpu_wall);
= j_dbs_info->prev_cpu_idle_up; if (dbs_tuners_ins.ignore_nice) {
j_dbs_info->prev_cpu_nice =
kstat_cpu(j).cpustat.nice;
}
} }
this_dbs_info->enable = 1;
this_dbs_info->down_skip = 0; this_dbs_info->down_skip = 0;
this_dbs_info->requested_freq = policy->cur; this_dbs_info->requested_freq = policy->cur;
...@@ -523,38 +598,36 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -523,38 +598,36 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if (latency == 0) if (latency == 0)
latency = 1; latency = 1;
def_sampling_rate = 10 * latency * def_sampling_rate =
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; max(latency * LATENCY_MULTIPLIER,
MIN_STAT_SAMPLING_RATE);
if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
dbs_tuners_ins.sampling_rate = def_sampling_rate; dbs_tuners_ins.sampling_rate = def_sampling_rate;
dbs_timer_init();
cpufreq_register_notifier( cpufreq_register_notifier(
&dbs_cpufreq_notifier_block, &dbs_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
} }
dbs_timer_init(this_dbs_info);
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
break; break;
case CPUFREQ_GOV_STOP: case CPUFREQ_GOV_STOP:
mutex_lock(&dbs_mutex); mutex_lock(&dbs_mutex);
this_dbs_info->enable = 0; dbs_timer_exit(this_dbs_info);
sysfs_remove_group(&policy->kobj, &dbs_attr_group); sysfs_remove_group(&policy->kobj, &dbs_attr_group);
dbs_enable--; dbs_enable--;
/* /*
* Stop the timerschedule work, when this governor * Stop the timerschedule work, when this governor
* is used for first time * is used for first time
*/ */
if (dbs_enable == 0) { if (dbs_enable == 0)
dbs_timer_exit();
cpufreq_unregister_notifier( cpufreq_unregister_notifier(
&dbs_cpufreq_notifier_block, &dbs_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
}
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
...@@ -571,6 +644,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -571,6 +644,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
this_dbs_info->cur_policy, this_dbs_info->cur_policy,
policy->min, CPUFREQ_RELATION_L); policy->min, CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
break; break;
} }
return 0; return 0;
...@@ -588,23 +662,33 @@ struct cpufreq_governor cpufreq_gov_conservative = { ...@@ -588,23 +662,33 @@ struct cpufreq_governor cpufreq_gov_conservative = {
static int __init cpufreq_gov_dbs_init(void) static int __init cpufreq_gov_dbs_init(void)
{ {
return cpufreq_register_governor(&cpufreq_gov_conservative); int err;
kconservative_wq = create_workqueue("kconservative");
if (!kconservative_wq) {
printk(KERN_ERR "Creation of kconservative failed\n");
return -EFAULT;
}
err = cpufreq_register_governor(&cpufreq_gov_conservative);
if (err)
destroy_workqueue(kconservative_wq);
return err;
} }
static void __exit cpufreq_gov_dbs_exit(void) static void __exit cpufreq_gov_dbs_exit(void)
{ {
/* Make sure that the scheduled work is indeed not running */
flush_scheduled_work();
cpufreq_unregister_governor(&cpufreq_gov_conservative); cpufreq_unregister_governor(&cpufreq_gov_conservative);
destroy_workqueue(kconservative_wq);
} }
MODULE_AUTHOR ("Alexander Clouter <alex-kernel@digriz.org.uk>"); MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for " MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
"Low Latency Frequency Transition capable processors " "Low Latency Frequency Transition capable processors "
"optimised for use in a battery environment"); "optimised for use in a battery environment");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
fs_initcall(cpufreq_gov_dbs_init); fs_initcall(cpufreq_gov_dbs_init);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/tick.h> #include <linux/tick.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/sched.h>
/* /*
* dbs is used in this file as a shortform for demandbased switching * dbs is used in this file as a shortform for demandbased switching
...@@ -51,8 +52,20 @@ static unsigned int def_sampling_rate; ...@@ -51,8 +52,20 @@ static unsigned int def_sampling_rate;
(MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
#define MIN_SAMPLING_RATE \ #define MIN_SAMPLING_RATE \
(def_sampling_rate / MIN_SAMPLING_RATE_RATIO) (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
/* Above MIN_SAMPLING_RATE will vanish with its sysfs file soon
* Define the minimal settable sampling rate to the greater of:
* - "HW transition latency" * 100 (same as default sampling / 10)
* - MIN_STAT_SAMPLING_RATE
* To avoid that userspace shoots itself.
*/
static unsigned int minimum_sampling_rate(void)
{
return max(def_sampling_rate / 10, MIN_STAT_SAMPLING_RATE);
}
/* This will also vanish soon with removing sampling_rate_max */
#define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define LATENCY_MULTIPLIER (1000)
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work); static void do_dbs_timer(struct work_struct *work);
...@@ -65,14 +78,14 @@ struct cpu_dbs_info_s { ...@@ -65,14 +78,14 @@ struct cpu_dbs_info_s {
cputime64_t prev_cpu_wall; cputime64_t prev_cpu_wall;
cputime64_t prev_cpu_nice; cputime64_t prev_cpu_nice;
struct cpufreq_policy *cur_policy; struct cpufreq_policy *cur_policy;
struct delayed_work work; struct delayed_work work;
struct cpufreq_frequency_table *freq_table; struct cpufreq_frequency_table *freq_table;
unsigned int freq_lo; unsigned int freq_lo;
unsigned int freq_lo_jiffies; unsigned int freq_lo_jiffies;
unsigned int freq_hi_jiffies; unsigned int freq_hi_jiffies;
int cpu; int cpu;
unsigned int enable:1, unsigned int enable:1,
sample_type:1; sample_type:1;
}; };
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
...@@ -203,12 +216,28 @@ static void ondemand_powersave_bias_init(void) ...@@ -203,12 +216,28 @@ static void ondemand_powersave_bias_init(void)
/************************** sysfs interface ************************/ /************************** sysfs interface ************************/
static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
{ {
return sprintf (buf, "%u\n", MAX_SAMPLING_RATE); static int print_once;
if (!print_once) {
printk(KERN_INFO "CPUFREQ: ondemand sampling_rate_max "
"sysfs file is deprecated - used by: %s\n",
current->comm);
print_once = 1;
}
return sprintf(buf, "%u\n", MAX_SAMPLING_RATE);
} }
static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf) static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
{ {
return sprintf (buf, "%u\n", MIN_SAMPLING_RATE); static int print_once;
if (!print_once) {
printk(KERN_INFO "CPUFREQ: ondemand sampling_rate_min "
"sysfs file is deprecated - used by: %s\n",
current->comm);
print_once = 1;
}
return sprintf(buf, "%u\n", MIN_SAMPLING_RATE);
} }
#define define_one_ro(_name) \ #define define_one_ro(_name) \
...@@ -238,13 +267,11 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused, ...@@ -238,13 +267,11 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex); mutex_lock(&dbs_mutex);
if (ret != 1 || input > MAX_SAMPLING_RATE if (ret != 1) {
|| input < MIN_SAMPLING_RATE) {
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
return -EINVAL; return -EINVAL;
} }
dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate());
dbs_tuners_ins.sampling_rate = input;
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
return count; return count;
...@@ -279,14 +306,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy, ...@@ -279,14 +306,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
unsigned int j; unsigned int j;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if ( ret != 1 ) if (ret != 1)
return -EINVAL; return -EINVAL;
if ( input > 1 ) if (input > 1)
input = 1; input = 1;
mutex_lock(&dbs_mutex); mutex_lock(&dbs_mutex);
if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */ if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
return count; return count;
} }
...@@ -337,7 +364,7 @@ define_one_rw(up_threshold); ...@@ -337,7 +364,7 @@ define_one_rw(up_threshold);
define_one_rw(ignore_nice_load); define_one_rw(ignore_nice_load);
define_one_rw(powersave_bias); define_one_rw(powersave_bias);
static struct attribute * dbs_attributes[] = { static struct attribute *dbs_attributes[] = {
&sampling_rate_max.attr, &sampling_rate_max.attr,
&sampling_rate_min.attr, &sampling_rate_min.attr,
&sampling_rate.attr, &sampling_rate.attr,
...@@ -512,8 +539,7 @@ static void do_dbs_timer(struct work_struct *work) ...@@ -512,8 +539,7 @@ static void do_dbs_timer(struct work_struct *work)
} }
} else { } else {
__cpufreq_driver_target(dbs_info->cur_policy, __cpufreq_driver_target(dbs_info->cur_policy,
dbs_info->freq_lo, dbs_info->freq_lo, CPUFREQ_RELATION_H);
CPUFREQ_RELATION_H);
} }
queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
unlock_policy_rwsem_write(cpu); unlock_policy_rwsem_write(cpu);
...@@ -530,7 +556,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) ...@@ -530,7 +556,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
dbs_info->sample_type = DBS_NORMAL_SAMPLE; dbs_info->sample_type = DBS_NORMAL_SAMPLE;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer); INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work, queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
delay); delay);
} }
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
...@@ -591,11 +617,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -591,11 +617,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if (latency == 0) if (latency == 0)
latency = 1; latency = 1;
def_sampling_rate = latency * def_sampling_rate =
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; max(latency * LATENCY_MULTIPLIER,
MIN_STAT_SAMPLING_RATE);
if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
dbs_tuners_ins.sampling_rate = def_sampling_rate; dbs_tuners_ins.sampling_rate = def_sampling_rate;
} }
...@@ -617,12 +641,10 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ...@@ -617,12 +641,10 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_mutex); mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur) if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(this_dbs_info->cur_policy, __cpufreq_driver_target(this_dbs_info->cur_policy,
policy->max, policy->max, CPUFREQ_RELATION_H);
CPUFREQ_RELATION_H);
else if (policy->min > this_dbs_info->cur_policy->cur) else if (policy->min > this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(this_dbs_info->cur_policy, __cpufreq_driver_target(this_dbs_info->cur_policy,
policy->min, policy->min, CPUFREQ_RELATION_L);
CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex); mutex_unlock(&dbs_mutex);
break; break;
} }
...@@ -677,7 +699,7 @@ static void __exit cpufreq_gov_dbs_exit(void) ...@@ -677,7 +699,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>"); MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>"); MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>");
MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for " MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
"Low Latency Frequency Transition capable processors"); "Low Latency Frequency Transition capable processors");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* drivers/cpufreq/cpufreq_stats.c * drivers/cpufreq/cpufreq_stats.c
* *
* Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. * Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* (C) 2004 Zou Nan hai <nanhai.zou@intel.com>. * (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
static spinlock_t cpufreq_stats_lock; static spinlock_t cpufreq_stats_lock;
#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \ #define CPUFREQ_STATDEVICE_ATTR(_name, _mode, _show) \
static struct freq_attr _attr_##_name = {\ static struct freq_attr _attr_##_name = {\
.attr = {.name = __stringify(_name), .mode = _mode, }, \ .attr = {.name = __stringify(_name), .mode = _mode, }, \
.show = _show,\ .show = _show,\
...@@ -50,8 +50,7 @@ struct cpufreq_stats_attribute { ...@@ -50,8 +50,7 @@ struct cpufreq_stats_attribute {
ssize_t(*show) (struct cpufreq_stats *, char *); ssize_t(*show) (struct cpufreq_stats *, char *);
}; };
static int static int cpufreq_stats_update(unsigned int cpu)
cpufreq_stats_update (unsigned int cpu)
{ {
struct cpufreq_stats *stat; struct cpufreq_stats *stat;
unsigned long long cur_time; unsigned long long cur_time;
...@@ -68,8 +67,7 @@ cpufreq_stats_update (unsigned int cpu) ...@@ -68,8 +67,7 @@ cpufreq_stats_update (unsigned int cpu)
return 0; return 0;
} }
static ssize_t static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
show_total_trans(struct cpufreq_policy *policy, char *buf)
{ {
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
if (!stat) if (!stat)
...@@ -78,8 +76,7 @@ show_total_trans(struct cpufreq_policy *policy, char *buf) ...@@ -78,8 +76,7 @@ show_total_trans(struct cpufreq_policy *policy, char *buf)
per_cpu(cpufreq_stats_table, stat->cpu)->total_trans); per_cpu(cpufreq_stats_table, stat->cpu)->total_trans);
} }
static ssize_t static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
show_time_in_state(struct cpufreq_policy *policy, char *buf)
{ {
ssize_t len = 0; ssize_t len = 0;
int i; int i;
...@@ -89,14 +86,14 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf) ...@@ -89,14 +86,14 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf)
cpufreq_stats_update(stat->cpu); cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) { for (i = 0; i < stat->state_num; i++) {
len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
(unsigned long long)cputime64_to_clock_t(stat->time_in_state[i])); (unsigned long long)
cputime64_to_clock_t(stat->time_in_state[i]));
} }
return len; return len;
} }
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
static ssize_t static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
show_trans_table(struct cpufreq_policy *policy, char *buf)
{ {
ssize_t len = 0; ssize_t len = 0;
int i, j; int i, j;
...@@ -139,11 +136,11 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) ...@@ -139,11 +136,11 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
return PAGE_SIZE; return PAGE_SIZE;
return len; return len;
} }
CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table); CPUFREQ_STATDEVICE_ATTR(trans_table, 0444, show_trans_table);
#endif #endif
CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans); CPUFREQ_STATDEVICE_ATTR(total_trans, 0444, show_total_trans);
CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state); CPUFREQ_STATDEVICE_ATTR(time_in_state, 0444, show_time_in_state);
static struct attribute *default_attrs[] = { static struct attribute *default_attrs[] = {
&_attr_total_trans.attr, &_attr_total_trans.attr,
...@@ -158,8 +155,7 @@ static struct attribute_group stats_attr_group = { ...@@ -158,8 +155,7 @@ static struct attribute_group stats_attr_group = {
.name = "stats" .name = "stats"
}; };
static int static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
{ {
int index; int index;
for (index = 0; index < stat->max_state; index++) for (index = 0; index < stat->max_state; index++)
...@@ -183,8 +179,7 @@ static void cpufreq_stats_free_table(unsigned int cpu) ...@@ -183,8 +179,7 @@ static void cpufreq_stats_free_table(unsigned int cpu)
cpufreq_cpu_put(policy); cpufreq_cpu_put(policy);
} }
static int static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
cpufreq_stats_create_table (struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table) struct cpufreq_frequency_table *table)
{ {
unsigned int i, j, count = 0, ret = 0; unsigned int i, j, count = 0, ret = 0;
...@@ -194,7 +189,8 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, ...@@ -194,7 +189,8 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
if (per_cpu(cpufreq_stats_table, cpu)) if (per_cpu(cpufreq_stats_table, cpu))
return -EBUSY; return -EBUSY;
if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL) stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
if ((stat) == NULL)
return -ENOMEM; return -ENOMEM;
data = cpufreq_cpu_get(cpu); data = cpufreq_cpu_get(cpu);
...@@ -203,13 +199,14 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, ...@@ -203,13 +199,14 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
goto error_get_fail; goto error_get_fail;
} }
if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group))) ret = sysfs_create_group(&data->kobj, &stats_attr_group);
if (ret)
goto error_out; goto error_out;
stat->cpu = cpu; stat->cpu = cpu;
per_cpu(cpufreq_stats_table, cpu) = stat; per_cpu(cpufreq_stats_table, cpu) = stat;
for (i=0; table[i].frequency != CPUFREQ_TABLE_END; i++) { for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
unsigned int freq = table[i].frequency; unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) if (freq == CPUFREQ_ENTRY_INVALID)
continue; continue;
...@@ -255,9 +252,8 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, ...@@ -255,9 +252,8 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
return ret; return ret;
} }
static int static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val, unsigned long val, void *data)
void *data)
{ {
int ret; int ret;
struct cpufreq_policy *policy = data; struct cpufreq_policy *policy = data;
...@@ -268,14 +264,14 @@ cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val, ...@@ -268,14 +264,14 @@ cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
table = cpufreq_frequency_get_table(cpu); table = cpufreq_frequency_get_table(cpu);
if (!table) if (!table)
return 0; return 0;
if ((ret = cpufreq_stats_create_table(policy, table))) ret = cpufreq_stats_create_table(policy, table);
if (ret)
return ret; return ret;
return 0; return 0;
} }
static int static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, unsigned long val, void *data)
void *data)
{ {
struct cpufreq_freqs *freq = data; struct cpufreq_freqs *freq = data;
struct cpufreq_stats *stat; struct cpufreq_stats *stat;
...@@ -340,19 +336,20 @@ static struct notifier_block notifier_trans_block = { ...@@ -340,19 +336,20 @@ static struct notifier_block notifier_trans_block = {
.notifier_call = cpufreq_stat_notifier_trans .notifier_call = cpufreq_stat_notifier_trans
}; };
static int static int __init cpufreq_stats_init(void)
__init cpufreq_stats_init(void)
{ {
int ret; int ret;
unsigned int cpu; unsigned int cpu;
spin_lock_init(&cpufreq_stats_lock); spin_lock_init(&cpufreq_stats_lock);
if ((ret = cpufreq_register_notifier(&notifier_policy_block, ret = cpufreq_register_notifier(&notifier_policy_block,
CPUFREQ_POLICY_NOTIFIER))) CPUFREQ_POLICY_NOTIFIER);
if (ret)
return ret; return ret;
if ((ret = cpufreq_register_notifier(&notifier_trans_block, ret = cpufreq_register_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER))) { CPUFREQ_TRANSITION_NOTIFIER);
if (ret) {
cpufreq_unregister_notifier(&notifier_policy_block, cpufreq_unregister_notifier(&notifier_policy_block,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
return ret; return ret;
...@@ -364,8 +361,7 @@ __init cpufreq_stats_init(void) ...@@ -364,8 +361,7 @@ __init cpufreq_stats_init(void)
} }
return 0; return 0;
} }
static void static void __exit cpufreq_stats_exit(void)
__exit cpufreq_stats_exit(void)
{ {
unsigned int cpu; unsigned int cpu;
...@@ -379,10 +375,10 @@ __exit cpufreq_stats_exit(void) ...@@ -379,10 +375,10 @@ __exit cpufreq_stats_exit(void)
} }
} }
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>"); MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats " MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats "
"through sysfs filesystem"); "through sysfs filesystem");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
module_init(cpufreq_stats_init); module_init(cpufreq_stats_init);
module_exit(cpufreq_stats_exit); module_exit(cpufreq_stats_exit);
...@@ -24,9 +24,6 @@ ...@@ -24,9 +24,6 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/uaccess.h>
/** /**
* A few values needed by the userspace governor * A few values needed by the userspace governor
*/ */
...@@ -37,7 +34,7 @@ static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by ...@@ -37,7 +34,7 @@ static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by
userspace */ userspace */
static DEFINE_PER_CPU(unsigned int, cpu_is_managed); static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
static DEFINE_MUTEX (userspace_mutex); static DEFINE_MUTEX(userspace_mutex);
static int cpus_using_userspace_governor; static int cpus_using_userspace_governor;
#define dprintk(msg...) \ #define dprintk(msg...) \
...@@ -46,9 +43,9 @@ static int cpus_using_userspace_governor; ...@@ -46,9 +43,9 @@ static int cpus_using_userspace_governor;
/* keep track of frequency transitions */ /* keep track of frequency transitions */
static int static int
userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data) void *data)
{ {
struct cpufreq_freqs *freq = data; struct cpufreq_freqs *freq = data;
if (!per_cpu(cpu_is_managed, freq->cpu)) if (!per_cpu(cpu_is_managed, freq->cpu))
return 0; return 0;
...@@ -57,11 +54,11 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, ...@@ -57,11 +54,11 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
freq->cpu, freq->new); freq->cpu, freq->new);
per_cpu(cpu_cur_freq, freq->cpu) = freq->new; per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
return 0; return 0;
} }
static struct notifier_block userspace_cpufreq_notifier_block = { static struct notifier_block userspace_cpufreq_notifier_block = {
.notifier_call = userspace_cpufreq_notifier .notifier_call = userspace_cpufreq_notifier
}; };
...@@ -93,8 +90,11 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) ...@@ -93,8 +90,11 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
* We're safe from concurrent calls to ->target() here * We're safe from concurrent calls to ->target() here
* as we hold the userspace_mutex lock. If we were calling * as we hold the userspace_mutex lock. If we were calling
* cpufreq_driver_target, a deadlock situation might occur: * cpufreq_driver_target, a deadlock situation might occur:
* A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock) * A: cpufreq_set (lock userspace_mutex) ->
* B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex) * cpufreq_driver_target(lock policy->lock)
* B: cpufreq_set_policy(lock policy->lock) ->
* __cpufreq_governor ->
* cpufreq_governor_userspace (lock userspace_mutex)
*/ */
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
...@@ -210,9 +210,10 @@ static void __exit cpufreq_gov_userspace_exit(void) ...@@ -210,9 +210,10 @@ static void __exit cpufreq_gov_userspace_exit(void)
} }
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>, Russell King <rmk@arm.linux.org.uk>"); MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'"); "Russell King <rmk@arm.linux.org.uk>");
MODULE_LICENSE ("GPL"); MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
fs_initcall(cpufreq_gov_userspace_init); fs_initcall(cpufreq_gov_userspace_init);
......
...@@ -28,7 +28,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, ...@@ -28,7 +28,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
unsigned int max_freq = 0; unsigned int max_freq = 0;
unsigned int i; unsigned int i;
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency; unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) { if (freq == CPUFREQ_ENTRY_INVALID) {
dprintk("table entry %u is invalid, skipping\n", i); dprintk("table entry %u is invalid, skipping\n", i);
...@@ -70,7 +70,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, ...@@ -70,7 +70,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq); policy->cpuinfo.max_freq);
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency; unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) if (freq == CPUFREQ_ENTRY_INVALID)
continue; continue;
...@@ -125,13 +125,13 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, ...@@ -125,13 +125,13 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
if (!cpu_online(policy->cpu)) if (!cpu_online(policy->cpu))
return -EINVAL; return -EINVAL;
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency; unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) if (freq == CPUFREQ_ENTRY_INVALID)
continue; continue;
if ((freq < policy->min) || (freq > policy->max)) if ((freq < policy->min) || (freq > policy->max))
continue; continue;
switch(relation) { switch (relation) {
case CPUFREQ_RELATION_H: case CPUFREQ_RELATION_H:
if (freq <= target_freq) { if (freq <= target_freq) {
if (freq >= optimal.frequency) { if (freq >= optimal.frequency) {
...@@ -178,7 +178,7 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table); ...@@ -178,7 +178,7 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table);
/** /**
* show_available_freqs - show available frequencies for the specified CPU * show_available_freqs - show available frequencies for the specified CPU
*/ */
static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf) static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf)
{ {
unsigned int i = 0; unsigned int i = 0;
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
...@@ -190,7 +190,7 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf) ...@@ -190,7 +190,7 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
table = per_cpu(show_table, cpu); table = per_cpu(show_table, cpu);
for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID) if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue; continue;
count += sprintf(&buf[count], "%d ", table[i].frequency); count += sprintf(&buf[count], "%d ", table[i].frequency);
...@@ -234,6 +234,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu) ...@@ -234,6 +234,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
} }
EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table); EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>"); MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); MODULE_DESCRIPTION("CPUfreq frequency table helpers");
MODULE_LICENSE ("GPL"); MODULE_LICENSE("GPL");
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