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. ...
This commit is contained in:
Коммит
ada19a31a9
|
@ -117,10 +117,28 @@ accessible parameters:
|
|||
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
|
||||
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
|
||||
The lowest value you can set is:
|
||||
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): the minimum and maximum sampling rates
|
||||
available that you may set 'sampling_rate' to.
|
||||
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
|
||||
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
|
|||
frequency the processor can run at(in kHz)
|
||||
cpuinfo_max_freq : this file shows the maximum operating
|
||||
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
|
||||
used to set the frequency on this CPU
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ unsigned long native_calibrate_tsc(void);
|
|||
|
||||
#ifdef CONFIG_X86_32
|
||||
extern int timer_ack;
|
||||
#endif
|
||||
extern int recalibrate_cpu_khz(void);
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
extern int no_timer_check;
|
||||
|
||||
|
|
|
@ -87,30 +87,15 @@ config X86_POWERNOW_K7_ACPI
|
|||
config X86_POWERNOW_K8
|
||||
tristate "AMD Opteron/Athlon64 PowerNow!"
|
||||
select CPU_FREQ_TABLE
|
||||
depends on ACPI && ACPI_PROCESSOR
|
||||
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
|
||||
module will be called powernow-k8.
|
||||
|
||||
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
|
||||
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
|
||||
depends on X86_32 && PCI
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# 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_K7) += powernow-k7.o
|
||||
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
|
||||
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
|
||||
obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o
|
||||
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.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_LIB) += speedstep-lib.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_P4_CLOCKMOD) += p4-clockmod.o
|
||||
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* 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 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
|
||||
|
@ -36,16 +36,18 @@
|
|||
#include <linux/ftrace.h>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <acpi/processor.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/processor.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_DESCRIPTION("ACPI Processor P-States Driver");
|
||||
|
@ -95,7 +97,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *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)
|
||||
return data->freq_table[i].frequency;
|
||||
}
|
||||
|
@ -110,7 +112,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
|
|||
msr &= INTEL_MSR_RANGE;
|
||||
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)
|
||||
return data->freq_table[i].frequency;
|
||||
}
|
||||
|
@ -138,15 +140,13 @@ struct io_addr {
|
|||
u8 bit_width;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
struct msr_addr msr;
|
||||
struct io_addr io;
|
||||
} drv_addr_union;
|
||||
|
||||
struct drv_cmd {
|
||||
unsigned int type;
|
||||
const struct cpumask *mask;
|
||||
drv_addr_union addr;
|
||||
union {
|
||||
struct msr_addr msr;
|
||||
struct io_addr io;
|
||||
} addr;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
|
@ -369,7 +369,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq,
|
|||
unsigned int cur_freq;
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; i<100; i++) {
|
||||
for (i = 0; i < 100; i++) {
|
||||
cur_freq = extract_freq(get_cur_val(mask), data);
|
||||
if (cur_freq == freq)
|
||||
return 1;
|
||||
|
@ -494,7 +494,7 @@ acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu)
|
|||
unsigned long freq;
|
||||
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;
|
||||
freqn = perf->states[i+1].core_frequency * 1000;
|
||||
if ((2 * cpu_khz) > (freqn + freq)) {
|
||||
|
@ -673,7 +673,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
/* detect transition latency */
|
||||
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) >
|
||||
policy->cpuinfo.transition_latency)
|
||||
policy->cpuinfo.transition_latency =
|
||||
|
@ -682,8 +682,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
data->max_freq = perf->states[0].core_frequency * 1000;
|
||||
/* table init */
|
||||
for (i=0; i<perf->state_count; i++) {
|
||||
if (i>0 && perf->states[i].core_frequency >=
|
||||
for (i = 0; i < perf->state_count; i++) {
|
||||
if (i > 0 && perf->states[i].core_frequency >=
|
||||
data->freq_table[valid_states-1].frequency / 1000)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
* nforce2_chipset:
|
||||
* FSB is changed using the chipset
|
||||
*/
|
||||
static struct pci_dev *nforce2_chipset_dev;
|
||||
static struct pci_dev *nforce2_dev;
|
||||
|
||||
/* fid:
|
||||
* multiplier * 10
|
||||
|
@ -56,7 +56,9 @@ MODULE_PARM_DESC(fid, "CPU multiplier to use (11.5 = 115)");
|
|||
MODULE_PARM_DESC(min_fsb,
|
||||
"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
|
||||
|
@ -118,11 +120,11 @@ static void nforce2_write_pll(int pll)
|
|||
int temp;
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
@ -139,8 +141,8 @@ static unsigned int nforce2_fsb_read(int bootfsb)
|
|||
u32 fsb, temp = 0;
|
||||
|
||||
/* Get chipset boot FSB from subdevice 5 (FSB at boot-time) */
|
||||
nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
|
||||
0x01EF, PCI_ANY_ID, PCI_ANY_ID, NULL);
|
||||
nforce2_sub5 = pci_get_subsys(PCI_VENDOR_ID_NVIDIA, 0x01EF,
|
||||
PCI_ANY_ID, PCI_ANY_ID, NULL);
|
||||
if (!nforce2_sub5)
|
||||
return 0;
|
||||
|
||||
|
@ -148,13 +150,13 @@ static unsigned int nforce2_fsb_read(int bootfsb)
|
|||
fsb /= 1000000;
|
||||
|
||||
/* 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)
|
||||
return fsb;
|
||||
|
||||
/* 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);
|
||||
|
||||
return fsb;
|
||||
|
@ -174,18 +176,18 @@ static int nforce2_set_fsb(unsigned int fsb)
|
|||
int pll = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
tfsb = nforce2_fsb_read(0);
|
||||
if (!tfsb) {
|
||||
printk(KERN_ERR "cpufreq: Error while reading the FSB\n");
|
||||
printk(KERN_ERR PFX "Error while reading the FSB\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
pll = nforce2_calc_pll(tfsb);
|
||||
|
||||
|
@ -197,7 +199,7 @@ static int nforce2_set_fsb(unsigned int fsb)
|
|||
|
||||
/* Enable write access */
|
||||
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;
|
||||
|
||||
|
@ -222,7 +224,7 @@ static int nforce2_set_fsb(unsigned int fsb)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -244,7 +246,8 @@ static unsigned int nforce2_get(unsigned int cpu)
|
|||
* nforce2_target - set a new CPUFreq policy
|
||||
* @policy: new policy
|
||||
* @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.
|
||||
*/
|
||||
|
@ -276,7 +279,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
|
|||
/* local_irq_save(flags); */
|
||||
|
||||
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);
|
||||
else
|
||||
dprintk("Changed FSB successfully to %d\n",
|
||||
|
@ -327,8 +330,8 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
|
|||
/* FIX: Get FID from CPU */
|
||||
if (!fid) {
|
||||
if (!cpu_khz) {
|
||||
printk(KERN_WARNING
|
||||
"cpufreq: cpu_khz not set, can't calculate multiplier!\n");
|
||||
printk(KERN_WARNING PFX
|
||||
"cpu_khz not set, can't calculate multiplier!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/* Set maximum FSB to FSB at boot time */
|
||||
|
@ -392,17 +395,18 @@ static struct cpufreq_driver nforce2_driver = {
|
|||
*/
|
||||
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_ANY_ID, PCI_ANY_ID, NULL);
|
||||
|
||||
if (nforce2_chipset_dev == NULL)
|
||||
if (nforce2_dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n",
|
||||
nforce2_chipset_dev->revision);
|
||||
printk(KERN_INFO
|
||||
"cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n");
|
||||
printk(KERN_INFO PFX "Detected nForce2 chipset revision %X\n",
|
||||
nforce2_dev->revision);
|
||||
printk(KERN_INFO PFX
|
||||
"FSB changing is maybe unstable and can lead to "
|
||||
"crashes and data loss.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -420,7 +424,7 @@ static int __init nforce2_init(void)
|
|||
|
||||
/* detect chipset */
|
||||
if (nforce2_detect_chipset()) {
|
||||
printk(KERN_ERR "cpufreq: No nForce2 chipset.\n");
|
||||
printk(KERN_INFO PFX "No nForce2 chipset.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/msr.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_C7 1
|
||||
|
@ -184,7 +184,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
|
|||
break;
|
||||
}
|
||||
|
||||
switch(brand) {
|
||||
switch (brand) {
|
||||
case EPS_BRAND_C7M:
|
||||
printk(KERN_CONT "C7-M\n");
|
||||
break;
|
||||
|
@ -218,17 +218,20 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
|
|||
/* Print voltage and multiplier */
|
||||
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
|
||||
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;
|
||||
printk(KERN_INFO "eps: Current multiplier = %d\n", current_multiplier);
|
||||
|
||||
/* Print limits */
|
||||
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;
|
||||
printk(KERN_INFO "eps: Highest multiplier = %d\n", max_multiplier);
|
||||
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;
|
||||
printk(KERN_INFO "eps: Lowest multiplier = %d\n", min_multiplier);
|
||||
|
||||
|
@ -318,7 +321,7 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr* eps_attr[] = {
|
||||
static struct freq_attr *eps_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -356,7 +359,7 @@ static void __exit eps_exit(void)
|
|||
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_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -184,7 +184,8 @@ static int elanfreq_target(struct cpufreq_policy *policy,
|
|||
{
|
||||
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;
|
||||
|
||||
elanfreq_set_cpu_state(newstate);
|
||||
|
@ -301,7 +302,8 @@ static void __exit elanfreq_exit(void)
|
|||
module_param(max_freq, int, 0444);
|
||||
|
||||
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_init(elanfreq_init);
|
||||
|
|
|
@ -79,8 +79,9 @@
|
|||
#include <linux/smp.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <asm/processor-cyrix.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
/* PCI config registers, all at F0 */
|
||||
#define PCI_PMER1 0x80 /* power management enable register 1 */
|
||||
|
@ -122,8 +123,8 @@ static struct gxfreq_params *gx_params;
|
|||
static int stock_freq;
|
||||
|
||||
/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */
|
||||
static int pci_busclk = 0;
|
||||
module_param (pci_busclk, int, 0444);
|
||||
static int pci_busclk;
|
||||
module_param(pci_busclk, int, 0444);
|
||||
|
||||
/* maximum duration for which the cpu may be suspended
|
||||
* (32us * MAX_DURATION). If no parameter is given, this defaults
|
||||
|
@ -132,7 +133,7 @@ module_param (pci_busclk, int, 0444);
|
|||
* is suspended -- processing power is just 0.39% of what it used to be,
|
||||
* though. 781.25 kHz(!) for a 200 MHz processor -- wow. */
|
||||
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
|
||||
* - let's say 5%. (min = maxfreq / POLICY_MIN_DIV)
|
||||
|
@ -140,7 +141,8 @@ module_param (max_duration, int, 0444);
|
|||
#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
|
||||
|
@ -166,12 +168,20 @@ static int gx_freq_mult[16] = {
|
|||
* Low Level chipset interface *
|
||||
****************************************************************/
|
||||
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_5520, 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_5530_LEGACY,
|
||||
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, },
|
||||
};
|
||||
|
||||
static void gx_write_byte(int reg, int value)
|
||||
{
|
||||
pci_write_config_byte(gx_params->cs55x0, reg, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* gx_detect_chipset:
|
||||
*
|
||||
|
@ -200,7 +210,8 @@ static __init struct pci_dev *gx_detect_chipset(void)
|
|||
/**
|
||||
* 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)
|
||||
{
|
||||
|
@ -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;
|
||||
u8 tmp_on, tmp_off;
|
||||
int old_tmp_freq = stock_freq;
|
||||
int tmp_freq;
|
||||
|
||||
*off_duration=1;
|
||||
*on_duration=0;
|
||||
*off_duration = 1;
|
||||
*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_on = i - tmp_off;
|
||||
tmp_freq = (stock_freq * tmp_off) / i;
|
||||
|
@ -259,26 +271,34 @@ static void gx_set_cpuspeed(unsigned int khz)
|
|||
freqs.cpu = 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;
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
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) {
|
||||
case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
|
||||
pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
|
||||
/* FIXME: need to test other values -- Zwane,Miura */
|
||||
pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */
|
||||
pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */
|
||||
pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1);
|
||||
/* typical 2 to 4ms */
|
||||
gx_write_byte(PCI_IRQTC, 4);
|
||||
/* typical 50 to 100ms */
|
||||
gx_write_byte(PCI_VIDTC, 100);
|
||||
gx_write_byte(PCI_PMER1, pmer1);
|
||||
|
||||
if (gx_params->cs55x0->revision < 0x10) { /* CS5530(rev 1.2, 1.3) */
|
||||
suscfg = gx_params->pci_suscfg | SUSMOD;
|
||||
} else { /* CS5530A,B.. */
|
||||
suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE;
|
||||
if (gx_params->cs55x0->revision < 0x10) {
|
||||
/* CS5530(rev 1.2, 1.3) */
|
||||
suscfg = gx_params->pci_suscfg|SUSMOD;
|
||||
} else {
|
||||
/* CS5530A,B.. */
|
||||
suscfg = gx_params->pci_suscfg|SUSMOD|PWRSVE;
|
||||
}
|
||||
break;
|
||||
case PCI_DEVICE_ID_CYRIX_5520:
|
||||
|
@ -294,13 +314,13 @@ static void gx_set_cpuspeed(unsigned int khz)
|
|||
suscfg = gx_params->pci_suscfg & ~(SUSMOD);
|
||||
gx_params->off_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);
|
||||
pci_write_config_byte(gx_params->cs55x0, PCI_MODON, gx_params->on_duration);
|
||||
gx_write_byte(PCI_MODOFF, gx_params->off_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);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
@ -334,7 +354,8 @@ static int cpufreq_gx_verify(struct cpufreq_policy *policy)
|
|||
return -EINVAL;
|
||||
|
||||
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
|
||||
* 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)
|
|||
policy->max = tmp_freq;
|
||||
if (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;
|
||||
}
|
||||
|
@ -398,18 +420,18 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
|
|||
return -ENODEV;
|
||||
|
||||
/* determine maximum frequency */
|
||||
if (pci_busclk) {
|
||||
if (pci_busclk)
|
||||
maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
|
||||
} else if (cpu_khz) {
|
||||
else if (cpu_khz)
|
||||
maxfreq = cpu_khz;
|
||||
} else {
|
||||
else
|
||||
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
|
||||
}
|
||||
|
||||
stock_freq = maxfreq;
|
||||
curfreq = gx_get_cpuspeed(0);
|
||||
|
||||
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 */
|
||||
policy->cpu = 0;
|
||||
|
@ -447,7 +469,8 @@ static int __init cpufreq_gx_init(void)
|
|||
struct pci_dev *gx_pci;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* check whether module parameters are sane */
|
||||
|
@ -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_PMER2, &(params->pci_pmer2));
|
||||
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);
|
||||
return ret; /* register error! */
|
||||
}
|
||||
|
@ -485,9 +510,9 @@ static void __exit cpufreq_gx_exit(void)
|
|||
kfree(gx_params);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR ("Hiroshi Miura <miura@da-cha.org>");
|
||||
MODULE_DESCRIPTION ("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
|
||||
MODULE_DESCRIPTION("Cpufreq driver for Cyrix MediaGX and NatSemi Geode");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(cpufreq_gx_init);
|
||||
module_exit(cpufreq_gx_exit);
|
||||
|
|
|
@ -30,12 +30,12 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/string.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/timex.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/processor.h>
|
||||
|
||||
#include "longhaul.h"
|
||||
|
@ -58,7 +58,7 @@
|
|||
#define USE_NORTHBRIDGE (1 << 2)
|
||||
|
||||
static int cpu_model;
|
||||
static unsigned int numscales=16;
|
||||
static unsigned int numscales = 16;
|
||||
static unsigned int fsb;
|
||||
|
||||
static const struct mV_pos *vrm_mV_table;
|
||||
|
@ -67,8 +67,8 @@ static const unsigned char *mV_vrm_table;
|
|||
static unsigned int highest_speed, lowest_speed; /* kHz */
|
||||
static unsigned int minmult, maxmult;
|
||||
static int can_scale_voltage;
|
||||
static struct acpi_processor *pr = NULL;
|
||||
static struct acpi_processor_cx *cx = NULL;
|
||||
static struct acpi_processor *pr;
|
||||
static struct acpi_processor_cx *cx;
|
||||
static u32 acpi_regs_addr;
|
||||
static u8 longhaul_flags;
|
||||
static unsigned int longhaul_index;
|
||||
|
@ -78,12 +78,13 @@ static int scale_voltage;
|
|||
static int disable_acpi_c3;
|
||||
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 */
|
||||
static int clock_ratio[32];
|
||||
static int eblcr_table[32];
|
||||
static int mults[32];
|
||||
static int eblcr[32];
|
||||
static int longhaul_version;
|
||||
static struct cpufreq_frequency_table *longhaul_table;
|
||||
|
||||
|
@ -93,7 +94,7 @@ static char speedbuffer[8];
|
|||
static char *print_speed(int speed)
|
||||
{
|
||||
if (speed < 1000) {
|
||||
snprintf(speedbuffer, sizeof(speedbuffer),"%dMHz", speed);
|
||||
snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed);
|
||||
return speedbuffer;
|
||||
}
|
||||
|
||||
|
@ -122,27 +123,28 @@ static unsigned int calc_speed(int mult)
|
|||
|
||||
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);
|
||||
invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
|
||||
if (longhaul_version==TYPE_LONGHAUL_V2 || longhaul_version==TYPE_POWERSAVER) {
|
||||
rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi);
|
||||
invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22;
|
||||
if (longhaul_version == TYPE_LONGHAUL_V2 ||
|
||||
longhaul_version == TYPE_POWERSAVER) {
|
||||
if (lo & (1<<27))
|
||||
invalue+=16;
|
||||
invalue += 16;
|
||||
}
|
||||
return eblcr_table[invalue];
|
||||
return eblcr[invalue];
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
rdmsrl(MSR_VIA_BCR2, bcr2.val);
|
||||
/* Enable software clock multiplier */
|
||||
bcr2.bits.ESOFTBF = 1;
|
||||
bcr2.bits.CLOCKMUL = clock_ratio_index & 0xff;
|
||||
bcr2.bits.CLOCKMUL = mults_index & 0xff;
|
||||
|
||||
/* Sync to timer tick */
|
||||
safe_halt();
|
||||
|
@ -161,7 +163,7 @@ static void do_longhaul1(unsigned int clock_ratio_index)
|
|||
|
||||
/* 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)
|
||||
{
|
||||
union msr_longhaul longhaul;
|
||||
|
@ -173,11 +175,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
|
|||
longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
|
||||
else
|
||||
longhaul.bits.RevisionKey = 0;
|
||||
longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
|
||||
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
|
||||
longhaul.bits.SoftBusRatio = mults_index & 0xf;
|
||||
longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4;
|
||||
/* Setup new voltage */
|
||||
if (can_scale_voltage)
|
||||
longhaul.bits.SoftVID = (clock_ratio_index >> 8) & 0x1f;
|
||||
longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f;
|
||||
/* Sync to timer tick */
|
||||
safe_halt();
|
||||
/* Raise voltage if necessary */
|
||||
|
@ -240,14 +242,14 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
|
|||
|
||||
/**
|
||||
* longhaul_set_cpu_frequency()
|
||||
* @clock_ratio_index : bitpattern of the new multiplier.
|
||||
* @mults_index : bitpattern of the new multiplier.
|
||||
*
|
||||
* Sets a new clock ratio.
|
||||
*/
|
||||
|
||||
static void longhaul_setstate(unsigned int table_index)
|
||||
{
|
||||
unsigned int clock_ratio_index;
|
||||
unsigned int mults_index;
|
||||
int speed, mult;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long flags;
|
||||
|
@ -256,9 +258,9 @@ static void longhaul_setstate(unsigned int table_index)
|
|||
u32 bm_timeout = 1000;
|
||||
unsigned int dir = 0;
|
||||
|
||||
clock_ratio_index = longhaul_table[table_index].index;
|
||||
mults_index = longhaul_table[table_index].index;
|
||||
/* Safety precautions */
|
||||
mult = clock_ratio[clock_ratio_index & 0x1f];
|
||||
mult = mults[mults_index & 0x1f];
|
||||
if (mult == -1)
|
||||
return;
|
||||
speed = calc_speed(mult);
|
||||
|
@ -274,7 +276,7 @@ static void longhaul_setstate(unsigned int table_index)
|
|||
|
||||
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));
|
||||
retry_loop:
|
||||
preempt_disable();
|
||||
|
@ -282,8 +284,8 @@ retry_loop:
|
|||
|
||||
pic2_mask = inb(0xA1);
|
||||
pic1_mask = inb(0x21); /* works on C3. save mask. */
|
||||
outb(0xFF,0xA1); /* Overkill */
|
||||
outb(0xFE,0x21); /* TMR0 only */
|
||||
outb(0xFF, 0xA1); /* Overkill */
|
||||
outb(0xFE, 0x21); /* TMR0 only */
|
||||
|
||||
/* Wait while PCI bus is busy. */
|
||||
if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
|
||||
|
@ -312,7 +314,7 @@ retry_loop:
|
|||
* Software controlled multipliers only.
|
||||
*/
|
||||
case TYPE_LONGHAUL_V1:
|
||||
do_longhaul1(clock_ratio_index);
|
||||
do_longhaul1(mults_index);
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -327,9 +329,9 @@ retry_loop:
|
|||
if (longhaul_flags & USE_ACPI_C3) {
|
||||
/* Don't allow wakeup */
|
||||
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 {
|
||||
do_powersaver(0, clock_ratio_index, dir);
|
||||
do_powersaver(0, mults_index, dir);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -341,8 +343,8 @@ retry_loop:
|
|||
/* Enable bus master arbitration */
|
||||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
|
||||
}
|
||||
outb(pic2_mask,0xA1); /* restore mask */
|
||||
outb(pic1_mask,0x21);
|
||||
outb(pic2_mask, 0xA1); /* restore mask */
|
||||
outb(pic1_mask, 0x21);
|
||||
|
||||
local_irq_restore(flags);
|
||||
preempt_enable();
|
||||
|
@ -392,7 +394,8 @@ retry_loop:
|
|||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
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)
|
|||
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);
|
||||
|
||||
highest_speed = calc_speed(maxmult);
|
||||
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(highest_speed/1000));
|
||||
|
||||
if (lowest_speed == highest_speed) {
|
||||
printk (KERN_INFO PFX "highestspeed == lowest, aborting.\n");
|
||||
printk(KERN_INFO PFX "highestspeed == lowest, aborting.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
|
||||
if(!longhaul_table)
|
||||
longhaul_table = kmalloc((numscales + 1) * sizeof(*longhaul_table),
|
||||
GFP_KERNEL);
|
||||
if (!longhaul_table)
|
||||
return -ENOMEM;
|
||||
|
||||
for (j = 0; j < numscales; j++) {
|
||||
ratio = clock_ratio[j];
|
||||
ratio = mults[j];
|
||||
if (ratio == -1)
|
||||
continue;
|
||||
if (ratio > maxmult || ratio < minmult)
|
||||
|
@ -507,13 +511,10 @@ static int __init longhaul_get_ranges(void)
|
|||
}
|
||||
}
|
||||
if (min_i != j) {
|
||||
unsigned int temp;
|
||||
temp = longhaul_table[j].frequency;
|
||||
longhaul_table[j].frequency = longhaul_table[min_i].frequency;
|
||||
longhaul_table[min_i].frequency = temp;
|
||||
temp = longhaul_table[j].index;
|
||||
longhaul_table[j].index = longhaul_table[min_i].index;
|
||||
longhaul_table[min_i].index = temp;
|
||||
swap(longhaul_table[j].frequency,
|
||||
longhaul_table[min_i].frequency);
|
||||
swap(longhaul_table[j].index,
|
||||
longhaul_table[min_i].index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -521,7 +522,7 @@ static int __init longhaul_get_ranges(void)
|
|||
|
||||
/* Find index we are running on */
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -559,20 +560,22 @@ static void __init longhaul_setup_voltagescaling(void)
|
|||
maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
|
||||
|
||||
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",
|
||||
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;
|
||||
}
|
||||
|
||||
if (minvid.mV == maxvid.mV) {
|
||||
printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are "
|
||||
"both %d.%03d. Voltage scaling disabled\n",
|
||||
printk(KERN_INFO PFX "Claims to support voltage scaling but "
|
||||
"min & max are both %d.%03d. "
|
||||
"Voltage scaling disabled\n",
|
||||
maxvid.mV/1000, maxvid.mV%1000);
|
||||
return;
|
||||
}
|
||||
|
||||
/* How many voltage steps */
|
||||
/* How many voltage steps*/
|
||||
numvscales = maxvid.pos - minvid.pos + 1;
|
||||
printk(KERN_INFO PFX
|
||||
"Max VID=%d.%03d "
|
||||
|
@ -586,7 +589,7 @@ static void __init longhaul_setup_voltagescaling(void)
|
|||
j = longhaul.bits.MinMHzBR;
|
||||
if (longhaul.bits.MinMHzBR4)
|
||||
j += 16;
|
||||
min_vid_speed = eblcr_table[j];
|
||||
min_vid_speed = eblcr[j];
|
||||
if (min_vid_speed == -1)
|
||||
return;
|
||||
switch (longhaul.bits.MinMHzFSB) {
|
||||
|
@ -617,7 +620,8 @@ static void __init longhaul_setup_voltagescaling(void)
|
|||
pos = minvid.pos;
|
||||
longhaul_table[j].index |= mV_vrm_table[pos] << 8;
|
||||
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++;
|
||||
}
|
||||
|
||||
|
@ -640,7 +644,8 @@ static int longhaul_target(struct cpufreq_policy *policy,
|
|||
unsigned int dir = 0;
|
||||
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;
|
||||
|
||||
/* Don't set same frequency again */
|
||||
|
@ -656,7 +661,8 @@ static int longhaul_target(struct cpufreq_policy *policy,
|
|||
* this in hardware, C3 is old and we need to do this
|
||||
* in software. */
|
||||
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)
|
||||
dir = 1;
|
||||
while (i != table_index) {
|
||||
|
@ -691,9 +697,9 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
|
|||
{
|
||||
struct acpi_device *d;
|
||||
|
||||
if ( acpi_bus_get_device(obj_handle, &d) ) {
|
||||
if (acpi_bus_get_device(obj_handle, &d))
|
||||
return 0;
|
||||
}
|
||||
|
||||
*return_value = acpi_driver_data(d);
|
||||
return 1;
|
||||
}
|
||||
|
@ -750,7 +756,7 @@ static int longhaul_setup_southbridge(void)
|
|||
/* Find VT8235 southbridge */
|
||||
dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
|
||||
if (dev == NULL)
|
||||
/* Find VT8237 southbridge */
|
||||
/* Find VT8237 southbridge */
|
||||
dev = pci_get_device(PCI_VENDOR_ID_VIA,
|
||||
PCI_DEVICE_ID_VIA_8237, NULL);
|
||||
if (dev != NULL) {
|
||||
|
@ -769,7 +775,8 @@ static int longhaul_setup_southbridge(void)
|
|||
if (pci_cmd & 1 << 7) {
|
||||
pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
|
||||
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);
|
||||
|
@ -781,7 +788,7 @@ static int longhaul_setup_southbridge(void)
|
|||
static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
char *cpuname=NULL;
|
||||
char *cpuname = NULL;
|
||||
int ret;
|
||||
u32 lo, hi;
|
||||
|
||||
|
@ -791,8 +798,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
|
|||
cpu_model = CPU_SAMUEL;
|
||||
cpuname = "C3 'Samuel' [C5A]";
|
||||
longhaul_version = TYPE_LONGHAUL_V1;
|
||||
memcpy (clock_ratio, samuel1_clock_ratio, sizeof(samuel1_clock_ratio));
|
||||
memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
|
||||
memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
|
||||
memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));
|
||||
break;
|
||||
|
||||
case 7:
|
||||
|
@ -803,10 +810,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
|
|||
cpuname = "C3 'Samuel 2' [C5B]";
|
||||
/* Note, this is not a typo, early Samuel2's had
|
||||
* Samuel1 ratios. */
|
||||
memcpy(clock_ratio, samuel1_clock_ratio,
|
||||
sizeof(samuel1_clock_ratio));
|
||||
memcpy(eblcr_table, samuel2_eblcr,
|
||||
sizeof(samuel2_eblcr));
|
||||
memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
|
||||
memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));
|
||||
break;
|
||||
case 1 ... 15:
|
||||
longhaul_version = TYPE_LONGHAUL_V1;
|
||||
|
@ -817,10 +822,8 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
|
|||
cpu_model = CPU_EZRA;
|
||||
cpuname = "C3 'Ezra' [C5C]";
|
||||
}
|
||||
memcpy(clock_ratio, ezra_clock_ratio,
|
||||
sizeof(ezra_clock_ratio));
|
||||
memcpy(eblcr_table, ezra_eblcr,
|
||||
sizeof(ezra_eblcr));
|
||||
memcpy(mults, ezra_mults, sizeof(ezra_mults));
|
||||
memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -829,18 +832,16 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
|
|||
cpu_model = CPU_EZRA_T;
|
||||
cpuname = "C3 'Ezra-T' [C5M]";
|
||||
longhaul_version = TYPE_POWERSAVER;
|
||||
numscales=32;
|
||||
memcpy (clock_ratio, ezrat_clock_ratio, sizeof(ezrat_clock_ratio));
|
||||
memcpy (eblcr_table, ezrat_eblcr, sizeof(ezrat_eblcr));
|
||||
numscales = 32;
|
||||
memcpy(mults, ezrat_mults, sizeof(ezrat_mults));
|
||||
memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));
|
||||
break;
|
||||
|
||||
case 9:
|
||||
longhaul_version = TYPE_POWERSAVER;
|
||||
numscales = 32;
|
||||
memcpy(clock_ratio,
|
||||
nehemiah_clock_ratio,
|
||||
sizeof(nehemiah_clock_ratio));
|
||||
memcpy(eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
|
||||
memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
|
||||
memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
|
||||
switch (c->x86_mask) {
|
||||
case 0 ... 1:
|
||||
cpu_model = CPU_NEHEMIAH;
|
||||
|
@ -869,14 +870,14 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
|
|||
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) {
|
||||
case TYPE_LONGHAUL_V1:
|
||||
case TYPE_LONGHAUL_V2:
|
||||
printk ("Longhaul v%d supported.\n", longhaul_version);
|
||||
printk(KERN_CONT "Longhaul v%d supported.\n", longhaul_version);
|
||||
break;
|
||||
case TYPE_POWERSAVER:
|
||||
printk ("Powersaver supported.\n");
|
||||
printk(KERN_CONT "Powersaver supported.\n");
|
||||
break;
|
||||
};
|
||||
|
||||
|
@ -940,7 +941,7 @@ static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr* longhaul_attr[] = {
|
||||
static struct freq_attr *longhaul_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -966,13 +967,15 @@ static int __init longhaul_init(void)
|
|||
|
||||
#ifdef CONFIG_SMP
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_X86_IO_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;
|
||||
}
|
||||
#endif
|
||||
|
@ -993,8 +996,8 @@ static void __exit longhaul_exit(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < numscales; i++) {
|
||||
if (clock_ratio[i] == maxmult) {
|
||||
for (i = 0; i < numscales; i++) {
|
||||
if (mults[i] == maxmult) {
|
||||
longhaul_setstate(i);
|
||||
break;
|
||||
}
|
||||
|
@ -1007,11 +1010,11 @@ static void __exit longhaul_exit(void)
|
|||
/* Even if BIOS is exporting ACPI C3 state, and it is used
|
||||
* with success when CPU is idle, this state doesn't
|
||||
* 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");
|
||||
/* Change CPU voltage with frequency. Very usefull to save
|
||||
* 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");
|
||||
/* Force revision key to 0 for processors which doesn't
|
||||
* support voltage scaling, but are introducing itself as
|
||||
|
@ -1019,9 +1022,9 @@ MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
|
|||
module_param(revid_errata, int, 0644);
|
||||
MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
|
||||
|
||||
MODULE_AUTHOR ("Dave Jones <davej@redhat.com>");
|
||||
MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
|
||||
MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
late_initcall(longhaul_init);
|
||||
module_exit(longhaul_exit);
|
||||
|
|
|
@ -49,14 +49,14 @@ union msr_longhaul {
|
|||
|
||||
/*
|
||||
* Clock ratio tables. Div/Mod by 10 to get ratio.
|
||||
* The eblcr ones specify the ratio read from the CPU.
|
||||
* The clock_ratio ones specify what to write to the CPU.
|
||||
* The eblcr values specify the ratio read from the CPU.
|
||||
* The mults values specify what to write to the CPU.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
30, /* 0001 -> 3.0x */
|
||||
40, /* 0010 -> 4.0x */
|
||||
|
@ -119,7 +119,7 @@ static const int __initdata samuel2_eblcr[16] = {
|
|||
/*
|
||||
* VIA C3 Ezra
|
||||
*/
|
||||
static const int __initdata ezra_clock_ratio[16] = {
|
||||
static const int __initdata ezra_mults[16] = {
|
||||
100, /* 0000 -> 10.0x */
|
||||
30, /* 0001 -> 3.0x */
|
||||
40, /* 0010 -> 4.0x */
|
||||
|
@ -160,7 +160,7 @@ static const int __initdata ezra_eblcr[16] = {
|
|||
/*
|
||||
* VIA C3 (Ezra-T) [C5M].
|
||||
*/
|
||||
static const int __initdata ezrat_clock_ratio[32] = {
|
||||
static const int __initdata ezrat_mults[32] = {
|
||||
100, /* 0000 -> 10.0x */
|
||||
30, /* 0001 -> 3.0x */
|
||||
40, /* 0010 -> 4.0x */
|
||||
|
@ -235,7 +235,7 @@ static const int __initdata ezrat_eblcr[32] = {
|
|||
/*
|
||||
* VIA C3 Nehemiah */
|
||||
|
||||
static const int __initdata nehemiah_clock_ratio[32] = {
|
||||
static const int __initdata nehemiah_mults[32] = {
|
||||
100, /* 0000 -> 10.0x */
|
||||
-1, /* 0001 -> 16.0x */
|
||||
40, /* 0010 -> 4.0x */
|
||||
|
|
|
@ -11,12 +11,13 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#include <asm/msr.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;
|
||||
|
||||
|
@ -51,7 +52,7 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy)
|
|||
msr_lo &= 0x0000007F;
|
||||
msr_hi &= 0x0000007F;
|
||||
|
||||
if ( longrun_high_freq <= longrun_low_freq ) {
|
||||
if (longrun_high_freq <= longrun_low_freq) {
|
||||
/* Assume degenerate Longrun table */
|
||||
policy->min = policy->max = longrun_high_freq;
|
||||
} else {
|
||||
|
@ -79,7 +80,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
|
|||
if (!policy)
|
||||
return -EINVAL;
|
||||
|
||||
if ( longrun_high_freq <= longrun_low_freq ) {
|
||||
if (longrun_high_freq <= longrun_low_freq) {
|
||||
/* Assume degenerate Longrun table */
|
||||
pctg_lo = pctg_hi = 100;
|
||||
} else {
|
||||
|
@ -152,7 +153,7 @@ static unsigned int longrun_get(unsigned int cpu)
|
|||
cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
|
||||
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,
|
|||
rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
|
||||
*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)
|
||||
*low_freq = *high_freq;
|
||||
|
@ -219,7 +221,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
|
|||
cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
|
||||
/* try decreasing in 10% steps, some processors react only
|
||||
* 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 */
|
||||
msr_lo &= 0xFFFFFF80;
|
||||
msr_hi &= 0xFFFFFF80;
|
||||
|
@ -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)
|
||||
* 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".
|
||||
*/
|
||||
|
@ -317,9 +319,10 @@ static void __exit longrun_exit(void)
|
|||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe and Efficeon processors.");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION("LongRun driver for Transmeta Crusoe and "
|
||||
"Efficeon processors.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(longrun_init);
|
||||
module_exit(longrun_exit);
|
||||
|
|
|
@ -27,15 +27,17 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/timex.h>
|
||||
#include <asm/timer.h>
|
||||
|
||||
#include "speedstep-lib.h"
|
||||
|
||||
#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
|
||||
|
@ -58,7 +60,8 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
|
|||
{
|
||||
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;
|
||||
|
||||
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)
|
|||
if (l & 0x01)
|
||||
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;
|
||||
|
||||
rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
|
||||
|
@ -112,7 +116,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
|
|||
struct cpufreq_freqs freqs;
|
||||
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;
|
||||
|
||||
freqs.old = cpufreq_p4_get(policy->cpu);
|
||||
|
@ -127,7 +132,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
|
|||
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
|
||||
*/
|
||||
for_each_cpu(i, policy->cpus)
|
||||
|
@ -153,28 +159,30 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
|
|||
{
|
||||
if (c->x86 == 0x06) {
|
||||
if (cpu_has(c, X86_FEATURE_EST))
|
||||
printk(KERN_WARNING PFX "Warning: EST-capable CPU detected. "
|
||||
"The acpi-cpufreq module offers voltage scaling"
|
||||
" in addition of frequency scaling. You should use "
|
||||
"that instead of p4-clockmod, if possible.\n");
|
||||
printk(KERN_WARNING PFX "Warning: EST-capable CPU "
|
||||
"detected. The acpi-cpufreq module offers "
|
||||
"voltage scaling in addition of frequency "
|
||||
"scaling. You should use that instead of "
|
||||
"p4-clockmod, if possible.\n");
|
||||
switch (c->x86_model) {
|
||||
case 0x0E: /* Core */
|
||||
case 0x0F: /* Core Duo */
|
||||
case 0x16: /* Celeron Core */
|
||||
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) */
|
||||
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
|
||||
/* fall through */
|
||||
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 (!cpu_has(c, X86_FEATURE_EST))
|
||||
printk(KERN_WARNING PFX "Unknown p4-clockmod-capable CPU. "
|
||||
"Please send an e-mail to <cpufreq@vger.kernel.org>\n");
|
||||
printk(KERN_WARNING PFX "Unknown CPU. "
|
||||
"Please send an e-mail to "
|
||||
"<cpufreq@vger.kernel.org>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -182,16 +190,16 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
|
|||
* throttling is active or not. */
|
||||
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. "
|
||||
"The speedstep-ich or acpi cpufreq modules offer "
|
||||
"voltage scaling in addition of frequency scaling. "
|
||||
"You should use either one instead of p4-clockmod, "
|
||||
"if possible.\n");
|
||||
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_P4M);
|
||||
return speedstep_get_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)
|
|||
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 */
|
||||
stock_freq = cpufreq_p4_get_frequency(c);
|
||||
if (!stock_freq)
|
||||
return -EINVAL;
|
||||
|
||||
/* table init */
|
||||
for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||
if ((i<2) && (has_N44_O17_errata[policy->cpu]))
|
||||
for (i = 1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||
if ((i < 2) && (has_N44_O17_errata[policy->cpu]))
|
||||
p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
else
|
||||
p4clockmod_table[i].frequency = (stock_freq * i)/8;
|
||||
|
@ -232,7 +246,10 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
|
|||
cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
|
||||
|
||||
/* 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;
|
||||
|
||||
return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]);
|
||||
|
@ -258,12 +275,12 @@ static unsigned int cpufreq_p4_get(unsigned int cpu)
|
|||
l = DC_DISABLE;
|
||||
|
||||
if (l != DC_DISABLE)
|
||||
return (stock_freq * l / 8);
|
||||
return stock_freq * l / 8;
|
||||
|
||||
return stock_freq;
|
||||
}
|
||||
|
||||
static struct freq_attr* p4clockmod_attr[] = {
|
||||
static struct freq_attr *p4clockmod_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -298,9 +315,10 @@ static int __init cpufreq_p4_init(void)
|
|||
|
||||
ret = cpufreq_register_driver(&p4clockmod_driver);
|
||||
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)
|
|||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>");
|
||||
MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
|
||||
MODULE_DESCRIPTION("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
late_initcall(cpufreq_p4_init);
|
||||
module_exit(cpufreq_p4_exit);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
|
@ -13,14 +14,15 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
|
||||
#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long
|
||||
as it is unused */
|
||||
|
||||
#define PFX "powernow-k6: "
|
||||
static unsigned int busfreq; /* FSB, in 10 kHz */
|
||||
static unsigned int max_multiplier;
|
||||
|
||||
|
@ -47,8 +49,8 @@ static struct cpufreq_frequency_table clock_ratio[] = {
|
|||
*/
|
||||
static int powernow_k6_get_cpu_multiplier(void)
|
||||
{
|
||||
u64 invalue = 0;
|
||||
u32 msrval;
|
||||
u64 invalue = 0;
|
||||
u32 msrval;
|
||||
|
||||
msrval = POWERNOW_IOPORT + 0x1;
|
||||
wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
|
||||
|
@ -68,12 +70,12 @@ static int powernow_k6_get_cpu_multiplier(void)
|
|||
*/
|
||||
static void powernow_k6_set_state(unsigned int best_i)
|
||||
{
|
||||
unsigned long outvalue = 0, invalue = 0;
|
||||
unsigned long msrval;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long outvalue = 0, invalue = 0;
|
||||
unsigned long msrval;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -119,7 +121,8 @@ static int powernow_k6_verify(struct cpufreq_policy *policy)
|
|||
* powernow_k6_setpolicy - sets a new CPUFreq policy
|
||||
* @policy: new policy
|
||||
* @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
|
||||
*/
|
||||
|
@ -127,9 +130,10 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
|
|||
unsigned int target_freq,
|
||||
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;
|
||||
|
||||
powernow_k6_set_state(newstate);
|
||||
|
@ -140,7 +144,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
|
|||
|
||||
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i, f;
|
||||
int result;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
|
@ -152,10 +156,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
/* table init */
|
||||
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;
|
||||
else
|
||||
clock_ratio[i].frequency = busfreq * clock_ratio[i].index;
|
||||
clock_ratio[i].frequency = busfreq * f;
|
||||
}
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
|
@ -185,7 +190,9 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
|
|||
|
||||
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[] = {
|
||||
|
@ -221,7 +228,7 @@ static int __init powernow_k6_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
* Licensed under the terms of the GNU GPL License version 2.
|
||||
* Based upon datasheets & sample CPUs kindly provided by AMD.
|
||||
*
|
||||
* Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt.
|
||||
* - We cli/sti on stepping A0 CPUs around the FID/VID transition.
|
||||
* Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect.
|
||||
* - We disable half multipliers if ACPI is used on A0 stepping CPUs.
|
||||
* Errata 5:
|
||||
* CPU may fail to execute a FID/VID change in presence of interrupt.
|
||||
* - We cli/sti on stepping A0 CPUs around the FID/VID transition.
|
||||
* 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>
|
||||
|
@ -20,11 +22,11 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/string.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/timer.h>
|
||||
#include <asm/timex.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
|
||||
|
@ -58,9 +60,9 @@ struct pst_s {
|
|||
union powernow_acpi_control_t {
|
||||
struct {
|
||||
unsigned long fid:5,
|
||||
vid:5,
|
||||
sgtc:20,
|
||||
res1:2;
|
||||
vid:5,
|
||||
sgtc:20,
|
||||
res1:2;
|
||||
} bits;
|
||||
unsigned long val;
|
||||
};
|
||||
|
@ -94,14 +96,15 @@ static struct cpufreq_frequency_table *powernow_table;
|
|||
|
||||
static unsigned int can_scale_bus;
|
||||
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 number_scales;
|
||||
static unsigned int fsb;
|
||||
static unsigned int latency;
|
||||
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)
|
||||
{
|
||||
|
@ -109,7 +112,7 @@ static int check_fsb(unsigned int fsbspeed)
|
|||
unsigned int f = fsb / 1000;
|
||||
|
||||
delta = (fsbspeed > f) ? fsbspeed - f : f - fsbspeed;
|
||||
return (delta < 5);
|
||||
return delta < 5;
|
||||
}
|
||||
|
||||
static int check_powernow(void)
|
||||
|
@ -117,24 +120,26 @@ static int check_powernow(void)
|
|||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
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
|
||||
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
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get maximum capabilities */
|
||||
maxei = cpuid_eax (0x80000000);
|
||||
maxei = cpuid_eax(0x80000000);
|
||||
if (maxei < 0x80000007) { /* Any powernow info ? */
|
||||
#ifdef MODULE
|
||||
printk (KERN_INFO PFX "No powernow capabilities detected\n");
|
||||
printk(KERN_INFO PFX "No powernow capabilities detected\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -144,37 +149,42 @@ static int check_powernow(void)
|
|||
if (!(edx & (1 << 1 | 1 << 2)))
|
||||
return 0;
|
||||
|
||||
printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
|
||||
printk(KERN_INFO PFX "PowerNOW! Technology present. Can scale: ");
|
||||
|
||||
if (edx & 1 << 1) {
|
||||
printk ("frequency");
|
||||
can_scale_bus=1;
|
||||
printk("frequency");
|
||||
can_scale_bus = 1;
|
||||
}
|
||||
|
||||
if ((edx & (1 << 1 | 1 << 2)) == 0x6)
|
||||
printk (" and ");
|
||||
printk(" and ");
|
||||
|
||||
if (edx & 1 << 2) {
|
||||
printk ("voltage");
|
||||
can_scale_vid=1;
|
||||
printk("voltage");
|
||||
can_scale_vid = 1;
|
||||
}
|
||||
|
||||
printk (".\n");
|
||||
printk(".\n");
|
||||
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 speed;
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
for (j=0 ; j < number_scales; j++) {
|
||||
for (j = 0 ; j < number_scales; j++) {
|
||||
fid = *pst++;
|
||||
|
||||
powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
|
||||
|
@ -182,10 +192,10 @@ static int get_ranges (unsigned char *pst)
|
|||
|
||||
speed = powernow_table[j].frequency;
|
||||
|
||||
if ((fid_codes[fid] % 10)==5) {
|
||||
if ((fid_codes[fid] % 10) == 5) {
|
||||
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
|
||||
if (have_a0 == 1)
|
||||
powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
invalidate_entry(j);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -197,7 +207,7 @@ static int get_ranges (unsigned char *pst)
|
|||
vid = *pst++;
|
||||
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,
|
||||
fid_codes[fid] % 10, speed/1000, vid,
|
||||
mobile_vid_table[vid]/1000,
|
||||
|
@ -214,13 +224,13 @@ static void change_FID(int fid)
|
|||
{
|
||||
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) {
|
||||
fidvidctl.bits.SGTC = latency;
|
||||
fidvidctl.bits.FID = fid;
|
||||
fidvidctl.bits.VIDC = 0;
|
||||
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)
|
|||
{
|
||||
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) {
|
||||
fidvidctl.bits.SGTC = latency;
|
||||
fidvidctl.bits.VID = vid;
|
||||
fidvidctl.bits.FIDC = 0;
|
||||
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;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
@ -257,7 +267,7 @@ static void change_speed (unsigned int index)
|
|||
|
||||
freqs.cpu = 0;
|
||||
|
||||
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
cfid = fidvidstatus.bits.CFID;
|
||||
freqs.old = fsb * fid_codes[cfid] / 10;
|
||||
|
||||
|
@ -321,12 +331,14 @@ static int powernow_acpi_init(void)
|
|||
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;
|
||||
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;
|
||||
goto err2;
|
||||
}
|
||||
|
@ -338,7 +350,8 @@ static int powernow_acpi_init(void)
|
|||
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) {
|
||||
retval = -ENOMEM;
|
||||
goto err2;
|
||||
|
@ -352,7 +365,7 @@ static int powernow_acpi_init(void)
|
|||
unsigned int speed, speed_mhz;
|
||||
|
||||
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,
|
||||
(u32) state->core_frequency,
|
||||
(u32) state->power,
|
||||
|
@ -381,12 +394,12 @@ static int powernow_acpi_init(void)
|
|||
if (speed % 1000 > 0)
|
||||
speed_mhz++;
|
||||
|
||||
if ((fid_codes[fid] % 10)==5) {
|
||||
if ((fid_codes[fid] % 10) == 5) {
|
||||
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,
|
||||
fid_codes[fid] % 10, speed_mhz, vid,
|
||||
mobile_vid_table[vid]/1000,
|
||||
|
@ -422,7 +435,8 @@ err1:
|
|||
err05:
|
||||
kfree(acpi_processor_perf);
|
||||
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;
|
||||
return retval;
|
||||
}
|
||||
|
@ -435,7 +449,14 @@ static int powernow_acpi_init(void)
|
|||
}
|
||||
#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 pst_s *pst;
|
||||
|
@ -446,61 +467,67 @@ static int powernow_decode_bios (int maxfid, int startvid)
|
|||
|
||||
etuple = cpuid_eax(0x80000001);
|
||||
|
||||
for (i=0xC0000; i < 0xffff0 ; i+=16) {
|
||||
for (i = 0xC0000; i < 0xffff0 ; i += 16) {
|
||||
|
||||
p = phys_to_virt(i);
|
||||
|
||||
if (memcmp(p, "AMDK7PNOW!", 10) == 0){
|
||||
dprintk ("Found PSB header at %p\n", p);
|
||||
if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
|
||||
dprintk("Found PSB header at %p\n", 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
dprintk ("Flags: 0x%x\n", psb->flags);
|
||||
if ((psb->flags & 1)==0) {
|
||||
dprintk ("Mobile voltage regulator\n");
|
||||
} else {
|
||||
dprintk ("Desktop voltage regulator\n");
|
||||
}
|
||||
dprintk("Flags: 0x%x\n", psb->flags);
|
||||
if ((psb->flags & 1) == 0)
|
||||
dprintk("Mobile voltage regulator\n");
|
||||
else
|
||||
dprintk("Desktop voltage regulator\n");
|
||||
|
||||
latency = psb->settlingtime;
|
||||
if (latency < 100) {
|
||||
printk(KERN_INFO PFX "BIOS set settling time to %d microseconds. "
|
||||
"Should be at least 100. Correcting.\n", latency);
|
||||
printk(KERN_INFO PFX "BIOS set settling time "
|
||||
"to %d microseconds. "
|
||||
"Should be at least 100. "
|
||||
"Correcting.\n", latency);
|
||||
latency = 100;
|
||||
}
|
||||
dprintk ("Settling Time: %d microseconds.\n", psb->settlingtime);
|
||||
dprintk ("Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst);
|
||||
dprintk("Settling Time: %d microseconds.\n",
|
||||
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;
|
||||
|
||||
for (j=0; j<psb->numpst; j++) {
|
||||
for (j = 0; j < psb->numpst; j++) {
|
||||
pst = (struct pst_s *) p;
|
||||
number_scales = pst->numpstates;
|
||||
|
||||
if ((etuple == pst->cpuid) && check_fsb(pst->fsbspeed) &&
|
||||
(maxfid==pst->maxfid) && (startvid==pst->startvid))
|
||||
{
|
||||
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);
|
||||
|
||||
ret = get_ranges ((char *) pst + sizeof (struct pst_s));
|
||||
if ((etuple == pst->cpuid) &&
|
||||
check_fsb(pst->fsbspeed) &&
|
||||
(maxfid == pst->maxfid) &&
|
||||
(startvid == pst->startvid)) {
|
||||
print_pst_entry(pst, j);
|
||||
p = (char *)pst + sizeof(struct pst_s);
|
||||
ret = get_ranges(p);
|
||||
return ret;
|
||||
} else {
|
||||
unsigned int k;
|
||||
p = (char *) pst + sizeof (struct pst_s);
|
||||
for (k=0; k<number_scales; k++)
|
||||
p+=2;
|
||||
p = (char *)pst + sizeof(struct pst_s);
|
||||
for (k = 0; k < number_scales; k++)
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
printk (KERN_INFO PFX "No PST tables match this cpuid (0x%x)\n", etuple);
|
||||
printk (KERN_INFO PFX "This is indicative of a broken BIOS.\n");
|
||||
printk(KERN_INFO PFX "No PST tables match this cpuid "
|
||||
"(0x%x)\n", etuple);
|
||||
printk(KERN_INFO PFX "This is indicative of a broken "
|
||||
"BIOS.\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -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 relation)
|
||||
{
|
||||
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;
|
||||
|
||||
change_speed(newstate);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -566,18 +594,23 @@ static unsigned int powernow_get(unsigned int cpu)
|
|||
|
||||
if (cpu)
|
||||
return 0;
|
||||
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
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)
|
||||
{
|
||||
printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);
|
||||
printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
|
||||
printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");
|
||||
printk(KERN_WARNING PFX
|
||||
"%s laptop with broken PST tables in BIOS detected.\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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
int result;
|
||||
|
@ -606,7 +639,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
|
|||
if (policy->cpu != 0)
|
||||
return -ENODEV;
|
||||
|
||||
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
|
||||
|
||||
recalibrate_cpu_khz();
|
||||
|
||||
|
@ -618,19 +651,21 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
|
|||
dprintk("FSB: %3dMHz\n", fsb/1000);
|
||||
|
||||
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();
|
||||
} else {
|
||||
result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID);
|
||||
result = powernow_decode_bios(fidvidstatus.bits.MFID,
|
||||
fidvidstatus.bits.SVID);
|
||||
if (result) {
|
||||
printk (KERN_INFO PFX "Trying ACPI perflib\n");
|
||||
printk(KERN_INFO PFX "Trying ACPI perflib\n");
|
||||
maximum_speed = 0;
|
||||
minimum_speed = -1;
|
||||
latency = 0;
|
||||
result = powernow_acpi_init();
|
||||
if (result) {
|
||||
printk (KERN_INFO PFX "ACPI and legacy methods failed\n");
|
||||
printk (KERN_INFO PFX "See http://www.codemonkey.org.uk/projects/cpufreq/powernow-k7.html\n");
|
||||
printk(KERN_INFO PFX
|
||||
"ACPI and legacy methods failed\n");
|
||||
}
|
||||
} else {
|
||||
/* SGTC use the bus clock as timer */
|
||||
|
@ -642,10 +677,11 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
|
|||
if (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);
|
||||
|
||||
policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
|
||||
policy->cpuinfo.transition_latency =
|
||||
cpufreq_scale(2000000UL, fsb, latency);
|
||||
|
||||
policy->cur = powernow_get(0);
|
||||
|
||||
|
@ -654,7 +690,8 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
|
|||
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);
|
||||
|
||||
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
|
||||
|
@ -669,7 +706,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr* powernow_table_attr[] = {
|
||||
static struct freq_attr *powernow_table_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -685,15 +722,15 @@ static struct cpufreq_driver powernow_driver = {
|
|||
.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 cpufreq_register_driver(&powernow_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit powernow_exit (void)
|
||||
static void __exit powernow_exit(void)
|
||||
{
|
||||
cpufreq_unregister_driver(&powernow_driver);
|
||||
}
|
||||
|
@ -701,9 +738,9 @@ static void __exit powernow_exit (void)
|
|||
module_param(acpi_force, int, 0444);
|
||||
MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
|
||||
|
||||
MODULE_AUTHOR ("Dave Jones <davej@redhat.com>");
|
||||
MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
|
||||
MODULE_DESCRIPTION("Powernow driver for AMD K7 processors.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
late_initcall(powernow_init);
|
||||
module_exit(powernow_exit);
|
||||
|
|
|
@ -33,16 +33,14 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/sched.h> /* for current / set_cpus_allowed() */
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.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/mutex.h>
|
||||
#include <acpi/processor.h>
|
||||
#endif
|
||||
|
||||
#define PFX "powernow-k8: "
|
||||
#define VERSION "version 2.20.00"
|
||||
|
@ -71,7 +69,8 @@ static u32 find_khz_freq_from_fid(u32 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;
|
||||
}
|
||||
|
@ -186,7 +185,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
|
|||
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",
|
||||
fid, lo, data->plllock * PLL_LOCK_CONVERSION);
|
||||
|
@ -194,7 +195,9 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
|
|||
do {
|
||||
wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
|
||||
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;
|
||||
}
|
||||
} while (query_current_values_with_pending_wait(data));
|
||||
|
@ -202,14 +205,16 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
|
|||
count_off_irt(data);
|
||||
|
||||
if (savevid != data->currvid) {
|
||||
printk(KERN_ERR PFX "vid change on fid trans, old 0x%x, new 0x%x\n",
|
||||
savevid, data->currvid);
|
||||
printk(KERN_ERR PFX
|
||||
"vid change on fid trans, old 0x%x, new 0x%x\n",
|
||||
savevid, data->currvid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fid != data->currfid) {
|
||||
printk(KERN_ERR PFX "fid trans failed, fid 0x%x, curr 0x%x\n", fid,
|
||||
data->currfid);
|
||||
printk(KERN_ERR PFX
|
||||
"fid trans failed, fid 0x%x, curr 0x%x\n", fid,
|
||||
data->currfid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -228,7 +233,9 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
|
|||
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",
|
||||
vid, lo, STOP_GRANT_5NS);
|
||||
|
@ -236,20 +243,24 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
|
|||
do {
|
||||
wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
|
||||
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;
|
||||
}
|
||||
} while (query_current_values_with_pending_wait(data));
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vid != data->currvid) {
|
||||
printk(KERN_ERR PFX "vid trans failed, vid 0x%x, curr 0x%x\n", vid,
|
||||
data->currvid);
|
||||
printk(KERN_ERR PFX "vid trans failed, vid 0x%x, "
|
||||
"curr 0x%x\n",
|
||||
vid, data->currvid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -261,7 +272,8 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
|
|||
* Decreasing vid codes represent increasing voltages:
|
||||
* 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)
|
||||
reqvid = data->currvid - step;
|
||||
|
@ -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. */
|
||||
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))
|
||||
return 1;
|
||||
|
@ -298,7 +311,8 @@ static int transition_fid_vid(struct powernow_k8_data *data, u32 reqfid, u32 req
|
|||
return 1;
|
||||
|
||||
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(),
|
||||
reqfid, reqvid, data->currfid, data->currvid);
|
||||
return 1;
|
||||
|
@ -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 */
|
||||
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 savefid = data->currfid;
|
||||
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(),
|
||||
data->currfid, data->currvid, reqvid, data->rvo);
|
||||
|
||||
|
@ -340,7 +356,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
|
|||
} else {
|
||||
dprintk("ph1: changing vid for rvo, req 0x%x\n",
|
||||
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;
|
||||
rvosteps--;
|
||||
}
|
||||
|
@ -350,7 +366,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
|
|||
return 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -363,20 +380,24 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
|
|||
/* Phase 2 - core frequency transition */
|
||||
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)) {
|
||||
printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n",
|
||||
reqfid, data->currfid);
|
||||
if ((reqfid < HI_FID_TABLE_BOTTOM) &&
|
||||
(data->currfid < HI_FID_TABLE_BOTTOM)) {
|
||||
printk(KERN_ERR PFX "ph2: illegal lo-lo transition "
|
||||
"0x%x 0x%x\n", reqfid, data->currfid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(),
|
||||
data->currfid, data->currvid, reqfid);
|
||||
|
||||
|
@ -390,14 +411,14 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
|
|||
|
||||
if (reqfid > data->currfid) {
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (write_new_fid
|
||||
(data, 2 + convert_fid_to_vco_fid(data->currfid))) {
|
||||
(data,
|
||||
2 + convert_fid_to_vco_fid(data->currfid)))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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)
|
|||
|
||||
if (data->currfid != reqfid) {
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
@ -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. */
|
||||
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 savereqvid = reqvid;
|
||||
|
@ -457,7 +480,8 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi
|
|||
|
||||
if (data->currvid != reqvid) {
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
@ -508,7 +532,8 @@ static int check_supported_cpu(unsigned int cpu)
|
|||
if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
|
||||
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
|
||||
((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;
|
||||
}
|
||||
|
||||
|
@ -520,8 +545,10 @@ static int check_supported_cpu(unsigned int cpu)
|
|||
}
|
||||
|
||||
cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
|
||||
if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
|
||||
printk(KERN_INFO PFX "Power state transitions not supported\n");
|
||||
if ((edx & P_STATE_TRANSITION_CAPABLE)
|
||||
!= P_STATE_TRANSITION_CAPABLE) {
|
||||
printk(KERN_INFO PFX
|
||||
"Power state transitions not supported\n");
|
||||
goto out;
|
||||
}
|
||||
} else { /* must be a HW Pstate capable processor */
|
||||
|
@ -539,7 +566,8 @@ out:
|
|||
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;
|
||||
u8 lastfid = 0xff;
|
||||
|
@ -550,12 +578,14 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
|
|||
j, pst[j].vid);
|
||||
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"
|
||||
" %d\n", j);
|
||||
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"
|
||||
" %d\n", j);
|
||||
return -ENODEV;
|
||||
|
@ -579,23 +609,31 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8
|
|||
return -EINVAL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int 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) {
|
||||
printk(KERN_INFO PFX " %d : pstate %d (%d MHz)\n",
|
||||
j,
|
||||
printk(KERN_INFO PFX
|
||||
" %d : pstate %d (%d MHz)\n", j,
|
||||
data->powernow_table[j].index,
|
||||
data->powernow_table[j].frequency/1000);
|
||||
} 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,
|
||||
data->powernow_table[j].index & 0xff,
|
||||
data->powernow_table[j].frequency/1000,
|
||||
|
@ -604,20 +642,25 @@ static void print_basics(struct powernow_k8_data *data)
|
|||
}
|
||||
}
|
||||
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;
|
||||
unsigned int j;
|
||||
|
||||
if (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);
|
||||
if (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;
|
||||
}
|
||||
|
||||
for ( j=1; j<data->numps; j++ ) {
|
||||
for (j = 1; j < data->numps; j++) {
|
||||
if (pst[j-1].fid >= pst[j].fid) {
|
||||
printk(KERN_ERR PFX "PST out of sequence\n");
|
||||
return -EINVAL;
|
||||
|
@ -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++) {
|
||||
int freq;
|
||||
powernow_table[j].index = pst[j].fid; /* lower 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].index = 0;
|
||||
|
@ -658,7 +703,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst,
|
|||
print_basics(data);
|
||||
|
||||
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;
|
||||
|
||||
dprintk("currfid/vid do not match PST, ignoring\n");
|
||||
|
@ -698,7 +744,8 @@ static int find_psb_table(struct powernow_k8_data *data)
|
|||
}
|
||||
|
||||
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);
|
||||
data->rvo = psb->flags2 & 3;
|
||||
|
@ -713,11 +760,12 @@ static int find_psb_table(struct powernow_k8_data *data)
|
|||
|
||||
dprintk("numpst: 0x%x\n", 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);
|
||||
if ((thiscpuid == 0x00000fc0) || (thiscpuid == 0x00000fe0) ) {
|
||||
if ((thiscpuid == 0x00000fc0) ||
|
||||
(thiscpuid == 0x00000fe0))
|
||||
cpst = 1;
|
||||
}
|
||||
}
|
||||
if (cpst != 1) {
|
||||
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)
|
|||
|
||||
data->numps = psb->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
|
||||
|
@ -745,28 +794,31 @@ static int find_psb_table(struct powernow_k8_data *data)
|
|||
* BIOS and Kernel Developer's Guide, which is available on
|
||||
* 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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
|
||||
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)
|
||||
{
|
||||
acpi_integer control;
|
||||
|
||||
if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
|
||||
return;
|
||||
|
||||
data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;
|
||||
data->rvo = (data->acpi_data.states[index].control >> RVO_SHIFT) & RVO_MASK;
|
||||
data->exttype = (data->acpi_data.states[index].control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
|
||||
data->plllock = (data->acpi_data.states[index].control >> PLL_L_SHIFT) & PLL_L_MASK;
|
||||
data->vidmvs = 1 << ((data->acpi_data.states[index].control >> MVS_SHIFT) & MVS_MASK);
|
||||
data->vstable = (data->acpi_data.states[index].control >> VST_SHIFT) & VST_MASK;
|
||||
}
|
||||
control = data->acpi_data.states[index].control; data->irt = (control
|
||||
>> IRT_SHIFT) & IRT_MASK; data->rvo = (control >>
|
||||
RVO_SHIFT) & RVO_MASK; data->exttype = (control
|
||||
>> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
|
||||
data->plllock = (control >> PLL_L_SHIFT) & PLL_L_MASK; data->vidmvs = 1
|
||||
<< ((control >> MVS_SHIFT) & MVS_MASK); data->vstable =
|
||||
(control >> VST_SHIFT) & VST_MASK; }
|
||||
|
||||
static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
||||
{
|
||||
struct cpufreq_frequency_table *powernow_table;
|
||||
int ret_val = -ENODEV;
|
||||
acpi_integer space_id;
|
||||
|
||||
if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
|
||||
dprintk("register performance failed: bad ACPI data\n");
|
||||
|
@ -779,11 +831,12 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
|
||||
(data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
|
||||
space_id = data->acpi_data.control_register.space_id;
|
||||
if ((space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
|
||||
(space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
|
||||
dprintk("Invalid control/status registers (%x - %x)\n",
|
||||
data->acpi_data.control_register.space_id,
|
||||
data->acpi_data.status_register.space_id);
|
||||
space_id);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
@ -802,7 +855,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
|||
if (ret_val)
|
||||
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;
|
||||
data->powernow_table = powernow_table;
|
||||
|
||||
|
@ -830,13 +884,15 @@ err_out_mem:
|
|||
err_out:
|
||||
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;
|
||||
|
||||
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;
|
||||
u32 hi = 0, lo = 0;
|
||||
|
@ -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;
|
||||
if (index > data->max_hw_pstate) {
|
||||
printk(KERN_ERR PFX "invalid pstate %d - bad value %d.\n", i, index);
|
||||
printk(KERN_ERR PFX "Please report to BIOS manufacturer\n");
|
||||
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
printk(KERN_ERR PFX "invalid pstate %d - "
|
||||
"bad value %d.\n", i, index);
|
||||
printk(KERN_ERR PFX "Please report to BIOS "
|
||||
"manufacturer\n");
|
||||
invalidate_entry(data, i);
|
||||
continue;
|
||||
}
|
||||
rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
|
||||
if (!(hi & HW_PSTATE_VALID_MASK)) {
|
||||
dprintk("invalid pstate %d, ignoring\n", index);
|
||||
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
invalidate_entry(data, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 cntlofreq = 0;
|
||||
|
||||
for (i = 0; i < data->acpi_data.state_count; i++) {
|
||||
u32 fid;
|
||||
u32 vid;
|
||||
u32 freq, index;
|
||||
acpi_integer status, control;
|
||||
|
||||
if (data->exttype) {
|
||||
fid = data->acpi_data.states[i].status & EXT_FID_MASK;
|
||||
vid = (data->acpi_data.states[i].status >> VID_SHIFT) & EXT_VID_MASK;
|
||||
status = data->acpi_data.states[i].status;
|
||||
fid = status & EXT_FID_MASK;
|
||||
vid = (status >> VID_SHIFT) & EXT_VID_MASK;
|
||||
} else {
|
||||
fid = data->acpi_data.states[i].control & FID_MASK;
|
||||
vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;
|
||||
control = data->acpi_data.states[i].control;
|
||||
fid = control & FID_MASK;
|
||||
vid = (control >> VID_SHIFT) & VID_MASK;
|
||||
}
|
||||
|
||||
dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
|
||||
|
||||
powernow_table[i].index = fid; /* lower 8 bits */
|
||||
powernow_table[i].index |= (vid << 8); /* upper 8 bits */
|
||||
powernow_table[i].frequency = find_khz_freq_from_fid(fid);
|
||||
index = fid | (vid<<8);
|
||||
powernow_table[i].index = index;
|
||||
|
||||
freq = find_khz_freq_from_fid(fid);
|
||||
powernow_table[i].frequency = freq;
|
||||
|
||||
/* verify frequency is OK */
|
||||
if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||
|
||||
(powernow_table[i].frequency < (MIN_FREQ * 1000))) {
|
||||
dprintk("invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);
|
||||
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
|
||||
dprintk("invalid freq %u kHz, ignoring\n", freq);
|
||||
invalidate_entry(data, i);
|
||||
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) {
|
||||
dprintk("invalid vid %u, ignoring\n", vid);
|
||||
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
invalidate_entry(data, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* verify only 1 entry from the lo frequency table */
|
||||
if (fid < HI_FID_TABLE_BOTTOM) {
|
||||
if (cntlofreq) {
|
||||
/* if both entries are the same, ignore this one ... */
|
||||
if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
|
||||
(powernow_table[i].index != powernow_table[cntlofreq].index)) {
|
||||
printk(KERN_ERR PFX "Too many lo freq table entries\n");
|
||||
/* if both entries are the same,
|
||||
* ignore this one ... */
|
||||
if ((freq != powernow_table[cntlofreq].frequency) ||
|
||||
(index != powernow_table[cntlofreq].index)) {
|
||||
printk(KERN_ERR PFX
|
||||
"Too many lo freq table "
|
||||
"entries\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dprintk("double low frequency table entry, ignoring it.\n");
|
||||
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
dprintk("double low frequency table entry, "
|
||||
"ignoring it.\n");
|
||||
invalidate_entry(data, i);
|
||||
continue;
|
||||
} else
|
||||
cntlofreq = i;
|
||||
}
|
||||
|
||||
if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
|
||||
printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n",
|
||||
powernow_table[i].frequency,
|
||||
(unsigned int) (data->acpi_data.states[i].core_frequency * 1000));
|
||||
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
||||
if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
|
||||
printk(KERN_INFO PFX "invalid freq entries "
|
||||
"%u kHz vs. %u kHz\n", freq,
|
||||
(unsigned int)
|
||||
(data->acpi_data.states[i].core_frequency
|
||||
* 1000));
|
||||
invalidate_entry(data, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -953,15 +1027,9 @@ static int get_transition_latency(struct powernow_k8_data *data)
|
|||
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 */
|
||||
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 vid = 0;
|
||||
|
@ -989,7 +1057,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i
|
|||
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
|
||||
"ignoring illegal change in lo freq table-%x to 0x%x\n",
|
||||
data->currfid, fid);
|
||||
|
@ -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 */
|
||||
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;
|
||||
int res, i;
|
||||
|
@ -1029,7 +1099,8 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i
|
|||
pstate = index & HW_PSTATE_MASK;
|
||||
if (pstate > data->max_hw_pstate)
|
||||
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);
|
||||
|
||||
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
|
|||
}
|
||||
|
||||
/* 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;
|
||||
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
|
|||
dprintk("targ: curr fid 0x%x, vid 0x%x\n",
|
||||
data->currfid, data->currvid);
|
||||
|
||||
if ((checkvid != data->currvid) || (checkfid != data->currfid)) {
|
||||
if ((checkvid != data->currvid) ||
|
||||
(checkfid != data->currfid)) {
|
||||
printk(KERN_INFO PFX
|
||||
"error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
|
||||
checkfid, data->currfid, checkvid, data->currvid);
|
||||
"error - out of sync, fix 0x%x 0x%x, "
|
||||
"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;
|
||||
|
||||
mutex_lock(&fidvid_mutex);
|
||||
|
@ -1114,7 +1190,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
|
|||
mutex_unlock(&fidvid_mutex);
|
||||
|
||||
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
|
||||
pol->cur = find_khz_freq_from_fid(data->currfid);
|
||||
ret = 0;
|
||||
|
@ -1141,6 +1218,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
struct powernow_k8_data *data;
|
||||
cpumask_t oldmask;
|
||||
int rc;
|
||||
static int print_once;
|
||||
|
||||
if (!cpu_online(pol->cpu))
|
||||
return -ENODEV;
|
||||
|
@ -1163,33 +1241,31 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
* an UP version, and is deprecated by AMD.
|
||||
*/
|
||||
if (num_online_cpus() != 1) {
|
||||
#ifndef CONFIG_ACPI_PROCESSOR
|
||||
printk(KERN_ERR PFX "ACPI Processor support is required "
|
||||
"for SMP systems but is absent. Please load the "
|
||||
"ACPI Processor module before starting this "
|
||||
"driver.\n");
|
||||
#else
|
||||
printk(KERN_ERR FW_BUG PFX "Your BIOS does not provide"
|
||||
" ACPI _PSS objects in a way that Linux "
|
||||
"understands. Please report this to the Linux "
|
||||
"ACPI maintainers and complain to your BIOS "
|
||||
"vendor.\n");
|
||||
#endif
|
||||
kfree(data);
|
||||
return -ENODEV;
|
||||
/*
|
||||
* Replace this one with print_once as soon as such a
|
||||
* thing gets introduced
|
||||
*/
|
||||
if (!print_once) {
|
||||
WARN_ONCE(1, KERN_ERR FW_BUG PFX "Your BIOS "
|
||||
"does not provide ACPI _PSS objects "
|
||||
"in a way that Linux understands. "
|
||||
"Please report this to the Linux ACPI"
|
||||
" maintainers and complain to your "
|
||||
"BIOS vendor.\n");
|
||||
print_once++;
|
||||
}
|
||||
goto err_out;
|
||||
}
|
||||
if (pol->cpu != 0) {
|
||||
printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
|
||||
"CPU other than CPU0. Complain to your BIOS "
|
||||
"vendor.\n");
|
||||
kfree(data);
|
||||
return -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
rc = find_psb_table(data);
|
||||
if (rc) {
|
||||
kfree(data);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
/* Take a crude guess here.
|
||||
* That guess was in microseconds, so multiply with 1000 */
|
||||
pol->cpuinfo.transition_latency = (
|
||||
|
@ -1204,16 +1280,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
|
||||
if (smp_processor_id() != 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()) {
|
||||
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))
|
||||
goto err_out;
|
||||
goto err_out_unmask;
|
||||
|
||||
if (cpu_family == CPU_OPTERON)
|
||||
fidvid_msr_init();
|
||||
|
@ -1228,7 +1304,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
data->available_cores = pol->cpus;
|
||||
|
||||
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
|
||||
pol->cur = find_khz_freq_from_fid(data->currfid);
|
||||
dprintk("policy current frequency %d kHz\n", pol->cur);
|
||||
|
@ -1245,7 +1322,8 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
|
||||
|
||||
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
|
||||
dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
|
||||
data->currfid, data->currvid);
|
||||
|
@ -1254,15 +1332,16 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
err_out_unmask:
|
||||
set_cpus_allowed_ptr(current, &oldmask);
|
||||
powernow_k8_cpu_exit_acpi(data);
|
||||
|
||||
err_out:
|
||||
kfree(data);
|
||||
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);
|
||||
|
||||
|
@ -1279,7 +1358,7 @@ static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int powernowk8_get (unsigned int cpu)
|
||||
static unsigned int powernowk8_get(unsigned int cpu)
|
||||
{
|
||||
struct powernow_k8_data *data;
|
||||
cpumask_t oldmask = current->cpus_allowed;
|
||||
|
@ -1315,7 +1394,7 @@ out:
|
|||
return khz;
|
||||
}
|
||||
|
||||
static struct freq_attr* powernow_k8_attr[] = {
|
||||
static struct freq_attr *powernow_k8_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -1360,7 +1439,8 @@ static void __exit powernowk8_exit(void)
|
|||
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_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -45,11 +45,10 @@ struct powernow_k8_data {
|
|||
* frequency is in kHz */
|
||||
struct cpufreq_frequency_table *powernow_table;
|
||||
|
||||
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
|
||||
/* the acpi table needs to be kept. it's only available if ACPI was
|
||||
* used to determine valid frequency/vid/fid states */
|
||||
struct acpi_processor_performance acpi_data;
|
||||
#endif
|
||||
|
||||
/* we need to keep track of associated cores, but let cpufreq
|
||||
* handle hotplug events - so just point at cpufreq pol->cpus
|
||||
* structure */
|
||||
|
@ -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);
|
||||
|
||||
#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_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
|
||||
|
|
|
@ -19,17 +19,19 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
#include <asm/timex.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MMCR_BASE 0xfffef000 /* The default base address */
|
||||
#define OFFS_CPUCTL 0x2 /* CPU Control Register */
|
||||
|
||||
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[] = {
|
||||
{0x01, 100000},
|
||||
|
@ -43,7 +45,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
|
|||
|
||||
switch (clockspeed_reg & 0x03) {
|
||||
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:
|
||||
return 100000;
|
||||
case 0x02:
|
||||
|
@ -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;
|
||||
|
@ -76,18 +79,19 @@ static void sc520_freq_set_cpu_state (unsigned int state)
|
|||
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]);
|
||||
}
|
||||
|
||||
static int sc520_freq_target (struct cpufreq_policy *policy,
|
||||
static int sc520_freq_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
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;
|
||||
|
||||
sc520_freq_set_cpu_state(newstate);
|
||||
|
@ -116,7 +120,7 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
|
||||
if (result)
|
||||
return (result);
|
||||
return result;
|
||||
|
||||
cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
|
||||
|
||||
|
@ -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,
|
||||
NULL,
|
||||
};
|
||||
|
@ -155,13 +159,13 @@ static int __init sc520_freq_init(void)
|
|||
int err;
|
||||
|
||||
/* Test if we have the right hardware */
|
||||
if(c->x86_vendor != X86_VENDOR_AMD ||
|
||||
c->x86 != 4 || c->x86_model != 9) {
|
||||
if (c->x86_vendor != X86_VENDOR_AMD ||
|
||||
c->x86 != 4 || c->x86_model != 9) {
|
||||
dprintk("no Elan SC520 processor found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
|
||||
if(!cpuctl) {
|
||||
if (!cpuctl) {
|
||||
printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ static struct pci_dev *speedstep_chipset_dev;
|
|||
|
||||
/* speedstep_processor
|
||||
*/
|
||||
static unsigned int speedstep_processor = 0;
|
||||
static unsigned int speedstep_processor;
|
||||
|
||||
static u32 pmbase;
|
||||
|
||||
|
@ -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[] = {
|
|||
*
|
||||
* Returns: -ENODEV if no register could be found
|
||||
*/
|
||||
static int speedstep_find_register (void)
|
||||
static int speedstep_find_register(void)
|
||||
{
|
||||
if (!speedstep_chipset_dev)
|
||||
return -ENODEV;
|
||||
|
@ -90,7 +91,7 @@ static int speedstep_find_register (void)
|
|||
*
|
||||
* 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 value;
|
||||
|
@ -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);
|
||||
|
||||
if (state == (value & 0x1)) {
|
||||
dprintk("change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000));
|
||||
} else {
|
||||
printk (KERN_ERR "cpufreq: change failed - I/O error\n");
|
||||
}
|
||||
if (state == (value & 0x1))
|
||||
dprintk("change to %u MHz succeeded\n",
|
||||
speedstep_get_frequency(speedstep_processor) / 1000);
|
||||
else
|
||||
printk(KERN_ERR "cpufreq: change failed - I/O error\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -149,7 +150,7 @@ static void speedstep_set_state (unsigned int state)
|
|||
* Tries to activate the SpeedStep status and control registers.
|
||||
* Returns -EINVAL on an unsupported chipset, and zero on success.
|
||||
*/
|
||||
static int speedstep_activate (void)
|
||||
static int speedstep_activate(void)
|
||||
{
|
||||
u16 value = 0;
|
||||
|
||||
|
@ -175,20 +176,18 @@ static int speedstep_activate (void)
|
|||
* functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
|
||||
* 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,
|
||||
PCI_DEVICE_ID_INTEL_82801DB_12,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
NULL);
|
||||
if (speedstep_chipset_dev)
|
||||
return 4; /* 4-M */
|
||||
|
||||
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
||||
PCI_DEVICE_ID_INTEL_82801CA_12,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
NULL);
|
||||
if (speedstep_chipset_dev)
|
||||
return 3; /* 3-M */
|
||||
|
@ -196,8 +195,7 @@ static unsigned int speedstep_detect_chipset (void)
|
|||
|
||||
speedstep_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
||||
PCI_DEVICE_ID_INTEL_82801BA_10,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
NULL);
|
||||
if (speedstep_chipset_dev) {
|
||||
/* speedstep.c causes lockups on Dell Inspirons 8000 and
|
||||
|
@ -208,8 +206,7 @@ static unsigned int speedstep_detect_chipset (void)
|
|||
|
||||
hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL,
|
||||
PCI_DEVICE_ID_INTEL_82815_MC,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
NULL);
|
||||
|
||||
if (!hostbridge)
|
||||
|
@ -236,7 +233,7 @@ static unsigned int _speedstep_get(const struct cpumask *cpus)
|
|||
|
||||
cpus_allowed = current->cpus_allowed;
|
||||
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);
|
||||
dprintk("detected %u kHz as current frequency\n", speed);
|
||||
return speed;
|
||||
|
@ -251,11 +248,12 @@ static unsigned int speedstep_get(unsigned int cpu)
|
|||
* speedstep_target - set a new CPUFreq policy
|
||||
* @policy: new policy
|
||||
* @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.
|
||||
*/
|
||||
static int speedstep_target (struct cpufreq_policy *policy,
|
||||
static int speedstep_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
|
@ -264,7 +262,8 @@ static int speedstep_target (struct cpufreq_policy *policy,
|
|||
cpumask_t cpus_allowed;
|
||||
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;
|
||||
|
||||
freqs.old = _speedstep_get(policy->cpus);
|
||||
|
@ -308,7 +307,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
|
|||
* Limit must be within speedstep_low_freq and speedstep_high_freq, with
|
||||
* 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]);
|
||||
}
|
||||
|
@ -344,7 +343,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||
return -EIO;
|
||||
|
||||
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));
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
|
@ -352,9 +352,9 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
|
||||
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;
|
||||
}
|
||||
|
@ -366,7 +366,7 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr* speedstep_attr[] = {
|
||||
static struct freq_attr *speedstep_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -396,13 +396,15 @@ static int __init speedstep_init(void)
|
|||
/* detect processor */
|
||||
speedstep_processor = speedstep_detect_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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -431,9 +433,11 @@ static void __exit speedstep_exit(void)
|
|||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR ("Dave Jones <davej@redhat.com>, Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges.");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dave Jones <davej@redhat.com>, "
|
||||
"Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION("Speedstep driver for Intel mobile processors on chipsets "
|
||||
"with ICH-M southbridges.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(speedstep_init);
|
||||
module_exit(speedstep_exit);
|
||||
|
|
|
@ -16,12 +16,16 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/msr.h>
|
||||
#include <asm/tsc.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
|
||||
static int relaxed_check = 0;
|
||||
static int relaxed_check;
|
||||
#else
|
||||
#define relaxed_check 0
|
||||
#endif
|
||||
|
@ -30,14 +34,14 @@ static int relaxed_check = 0;
|
|||
* 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 {
|
||||
unsigned int ratio; /* Frequency Multiplier (x10) */
|
||||
u8 bitmap; /* power on configuration bits
|
||||
[27, 25:22] (in MSR 0x2a) */
|
||||
} msr_decode_mult [] = {
|
||||
} msr_decode_mult[] = {
|
||||
{ 30, 0x01 },
|
||||
{ 35, 0x05 },
|
||||
{ 40, 0x02 },
|
||||
|
@ -52,7 +56,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
|
|||
{ 85, 0x26 },
|
||||
{ 90, 0x20 },
|
||||
{ 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 */
|
||||
|
@ -60,7 +64,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
|
|||
unsigned int value; /* Front Side Bus speed in MHz */
|
||||
u8 bitmap; /* power on configuration bits [18: 19]
|
||||
(in MSR 0x2a) */
|
||||
} msr_decode_fsb [] = {
|
||||
} msr_decode_fsb[] = {
|
||||
{ 66, 0x0 },
|
||||
{ 100, 0x2 },
|
||||
{ 133, 0x1 },
|
||||
|
@ -85,7 +89,7 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
|
|||
}
|
||||
|
||||
/* decode the multiplier */
|
||||
if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY) {
|
||||
if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
|
||||
dprintk("workaround for early PIIIs\n");
|
||||
msr_lo &= 0x03c00000;
|
||||
} else
|
||||
|
@ -97,9 +101,10 @@ static unsigned int pentium3_get_frequency (unsigned int processor)
|
|||
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)
|
|||
|
||||
/* see table B-2 of 24547212.pdf */
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 fsb = 0;
|
||||
u32 msr_lo, msr_tmp;
|
||||
int ret;
|
||||
|
||||
rdmsr(MSR_FSB_FREQ, msr_lo, msr_tmp);
|
||||
/* see table B-2 of 25366920.pdf */
|
||||
|
@ -153,12 +161,15 @@ static unsigned int pentium_core_get_frequency(void)
|
|||
}
|
||||
|
||||
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;
|
||||
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)
|
|||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
u32 msr_lo, msr_hi, mult;
|
||||
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);
|
||||
|
||||
|
@ -177,62 +198,61 @@ static unsigned int pentium4_get_frequency(void)
|
|||
* revision #12 in Table B-1: MSRs in the Pentium 4 and
|
||||
* 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;
|
||||
else {
|
||||
u8 fsb_code = (msr_lo >> 16) & 0x7;
|
||||
switch (fsb_code) {
|
||||
case 0:
|
||||
fsb = 100 * 1000;
|
||||
break;
|
||||
case 1:
|
||||
fsb = 13333 * 10;
|
||||
break;
|
||||
case 2:
|
||||
fsb = 200 * 1000;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
fsb = 13333 * 10;
|
||||
break;
|
||||
case 2:
|
||||
fsb = 200 * 1000;
|
||||
break;
|
||||
}
|
||||
|
||||
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. */
|
||||
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) {
|
||||
case SPEEDSTEP_PROCESSOR_PCORE:
|
||||
case SPEEDSTEP_CPU_PCORE:
|
||||
return pentium_core_get_frequency();
|
||||
case SPEEDSTEP_PROCESSOR_PM:
|
||||
case SPEEDSTEP_CPU_PM:
|
||||
return pentiumM_get_frequency();
|
||||
case SPEEDSTEP_PROCESSOR_P4D:
|
||||
case SPEEDSTEP_PROCESSOR_P4M:
|
||||
case SPEEDSTEP_CPU_P4D:
|
||||
case SPEEDSTEP_CPU_P4M:
|
||||
return pentium4_get_frequency();
|
||||
case SPEEDSTEP_PROCESSOR_PIII_T:
|
||||
case SPEEDSTEP_PROCESSOR_PIII_C:
|
||||
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
|
||||
case SPEEDSTEP_CPU_PIII_T:
|
||||
case SPEEDSTEP_CPU_PIII_C:
|
||||
case SPEEDSTEP_CPU_PIII_C_EARLY:
|
||||
return pentium3_get_frequency(processor);
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(speedstep_get_processor_frequency);
|
||||
EXPORT_SYMBOL_GPL(speedstep_get_frequency);
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* DETECT SPEEDSTEP-CAPABLE PROCESSOR *
|
||||
*********************************************************************/
|
||||
|
||||
unsigned int speedstep_detect_processor (void)
|
||||
unsigned int speedstep_detect_processor(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
||||
u32 ebx, msr_lo, msr_hi;
|
||||
|
@ -261,7 +281,7 @@ unsigned int speedstep_detect_processor (void)
|
|||
* sample has ebx = 0x0f, production has 0x0e.
|
||||
*/
|
||||
if ((ebx == 0x0e) || (ebx == 0x0f))
|
||||
return SPEEDSTEP_PROCESSOR_P4M;
|
||||
return SPEEDSTEP_CPU_P4M;
|
||||
break;
|
||||
case 7:
|
||||
/*
|
||||
|
@ -272,7 +292,7 @@ unsigned int speedstep_detect_processor (void)
|
|||
* samples are only of B-stepping...
|
||||
*/
|
||||
if (ebx == 0x0e)
|
||||
return SPEEDSTEP_PROCESSOR_P4M;
|
||||
return SPEEDSTEP_CPU_P4M;
|
||||
break;
|
||||
case 9:
|
||||
/*
|
||||
|
@ -288,10 +308,13 @@ unsigned int speedstep_detect_processor (void)
|
|||
* M-P4-Ms may have either ebx=0xe or 0xf [see above]
|
||||
* M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf]
|
||||
* 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))
|
||||
return SPEEDSTEP_PROCESSOR_P4M;
|
||||
if ((ebx == 0x0e) ||
|
||||
(strstr(c->x86_model_id,
|
||||
"Mobile Intel(R) Pentium(R) 4") != NULL))
|
||||
return SPEEDSTEP_CPU_P4M;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -301,7 +324,8 @@ unsigned int speedstep_detect_processor (void)
|
|||
|
||||
switch (c->x86_model) {
|
||||
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);
|
||||
dprintk("ebx is %x\n", ebx);
|
||||
|
||||
|
@ -313,14 +337,15 @@ unsigned int speedstep_detect_processor (void)
|
|||
/* So far all PIII-M processors support SpeedStep. See
|
||||
* Intel's 24540640.pdf of June 2003
|
||||
*/
|
||||
return SPEEDSTEP_PROCESSOR_PIII_T;
|
||||
return SPEEDSTEP_CPU_PIII_T;
|
||||
|
||||
case 0x08: /* Intel PIII [Coppermine] */
|
||||
|
||||
/* all mobile PIII Coppermines have FSB 100 MHz
|
||||
* ==> sort out a few desktop PIIIs. */
|
||||
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;
|
||||
if (msr_lo != 0x0080000)
|
||||
return 0;
|
||||
|
@ -332,13 +357,15 @@ unsigned int speedstep_detect_processor (void)
|
|||
* bit 56 or 57 is set
|
||||
*/
|
||||
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);
|
||||
if ((msr_hi & (1<<18)) && (relaxed_check ? 1 : (msr_hi & (3<<24)))) {
|
||||
dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
|
||||
msr_lo, msr_hi);
|
||||
if ((msr_hi & (1<<18)) &&
|
||||
(relaxed_check ? 1 : (msr_hi & (3<<24)))) {
|
||||
if (c->x86_mask == 0x01) {
|
||||
dprintk("early PIII version\n");
|
||||
return SPEEDSTEP_PROCESSOR_PIII_C_EARLY;
|
||||
return SPEEDSTEP_CPU_PIII_C_EARLY;
|
||||
} else
|
||||
return SPEEDSTEP_PROCESSOR_PIII_C;
|
||||
return SPEEDSTEP_CPU_PIII_C;
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -369,7 +396,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||
dprintk("trying to determine both speeds\n");
|
||||
|
||||
/* get current speed */
|
||||
prev_speed = speedstep_get_processor_frequency(processor);
|
||||
prev_speed = speedstep_get_frequency(processor);
|
||||
if (!prev_speed)
|
||||
return -EIO;
|
||||
|
||||
|
@ -379,7 +406,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||
|
||||
/* switch to low state */
|
||||
set_state(SPEEDSTEP_LOW);
|
||||
*low_speed = speedstep_get_processor_frequency(processor);
|
||||
*low_speed = speedstep_get_frequency(processor);
|
||||
if (!*low_speed) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
|
@ -398,7 +425,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||
if (transition_latency)
|
||||
do_gettimeofday(&tv2);
|
||||
|
||||
*high_speed = speedstep_get_processor_frequency(processor);
|
||||
*high_speed = speedstep_get_frequency(processor);
|
||||
if (!*high_speed) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
|
@ -426,9 +453,12 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||
/* check if the latency measurement is too high or too low
|
||||
* and set it to a safe value (500uSec) in that case
|
||||
*/
|
||||
if (*transition_latency > 10000000 || *transition_latency < 50000) {
|
||||
printk (KERN_WARNING "speedstep: frequency transition measured seems out of "
|
||||
"range (%u nSec), falling back to a safe one of %u nSec.\n",
|
||||
if (*transition_latency > 10000000 ||
|
||||
*transition_latency < 50000) {
|
||||
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;
|
||||
}
|
||||
|
@ -436,15 +466,16 @@ unsigned int speedstep_get_freqs(unsigned int processor,
|
|||
|
||||
out:
|
||||
local_irq_restore(flags);
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(speedstep_get_freqs);
|
||||
|
||||
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
|
||||
module_param(relaxed_check, int, 0444);
|
||||
MODULE_PARM_DESC(relaxed_check, "Don't do all checks for speedstep capability.");
|
||||
MODULE_PARM_DESC(relaxed_check,
|
||||
"Don't do all checks for speedstep capability.");
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION("Library for Intel SpeedStep 1 or 2 cpufreq drivers.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
|
||||
/* processors */
|
||||
|
||||
#define SPEEDSTEP_PROCESSOR_PIII_C_EARLY 0x00000001 /* Coppermine core */
|
||||
#define SPEEDSTEP_PROCESSOR_PIII_C 0x00000002 /* Coppermine core */
|
||||
#define SPEEDSTEP_PROCESSOR_PIII_T 0x00000003 /* Tualatin core */
|
||||
#define SPEEDSTEP_PROCESSOR_P4M 0x00000004 /* P4-M */
|
||||
#define SPEEDSTEP_CPU_PIII_C_EARLY 0x00000001 /* Coppermine core */
|
||||
#define SPEEDSTEP_CPU_PIII_C 0x00000002 /* Coppermine core */
|
||||
#define SPEEDSTEP_CPU_PIII_T 0x00000003 /* Tualatin core */
|
||||
#define SPEEDSTEP_CPU_P4M 0x00000004 /* P4-M */
|
||||
|
||||
/* the following processors are not speedstep-capable and are not auto-detected
|
||||
* in speedstep_detect_processor(). However, their speed can be detected using
|
||||
* the speedstep_get_processor_frequency() call. */
|
||||
#define SPEEDSTEP_PROCESSOR_PM 0xFFFFFF03 /* Pentium M */
|
||||
#define SPEEDSTEP_PROCESSOR_P4D 0xFFFFFF04 /* desktop P4 */
|
||||
#define SPEEDSTEP_PROCESSOR_PCORE 0xFFFFFF05 /* Core */
|
||||
* the speedstep_get_frequency() call. */
|
||||
#define SPEEDSTEP_CPU_PM 0xFFFFFF03 /* Pentium M */
|
||||
#define SPEEDSTEP_CPU_P4D 0xFFFFFF04 /* desktop P4 */
|
||||
#define SPEEDSTEP_CPU_PCORE 0xFFFFFF05 /* Core */
|
||||
|
||||
/* speedstep states -- only two of them */
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
extern unsigned int speedstep_detect_processor (void);
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/ist.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "speedstep-lib.h"
|
||||
|
||||
|
@ -30,12 +30,12 @@
|
|||
* If user gives it, these are used.
|
||||
*
|
||||
*/
|
||||
static int smi_port = 0;
|
||||
static int smi_cmd = 0;
|
||||
static unsigned int smi_sig = 0;
|
||||
static int smi_port;
|
||||
static int smi_cmd;
|
||||
static unsigned int smi_sig;
|
||||
|
||||
/* 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
|
||||
|
@ -56,12 +56,13 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
|
|||
* of DMA activity going on? */
|
||||
#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
|
||||
*/
|
||||
static int speedstep_smi_ownership (void)
|
||||
static int speedstep_smi_ownership(void)
|
||||
{
|
||||
u32 command, result, magic, dummy;
|
||||
u32 function = GET_SPEEDSTEP_OWNER;
|
||||
|
@ -70,16 +71,18 @@ static int speedstep_smi_ownership (void)
|
|||
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
|
||||
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__(
|
||||
"push %%ebp\n"
|
||||
"out %%al, (%%dx)\n"
|
||||
"pop %%ebp\n"
|
||||
: "=D" (result), "=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
|
||||
"=S" (dummy)
|
||||
: "=D" (result),
|
||||
"=a" (dummy), "=b" (dummy), "=c" (dummy), "=d" (dummy),
|
||||
"=S" (dummy)
|
||||
: "a" (command), "b" (function), "c" (0), "d" (smi_port),
|
||||
"D" (0), "S" (magic)
|
||||
"D" (0), "S" (magic)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
|
@ -97,10 +100,10 @@ static int speedstep_smi_ownership (void)
|
|||
* even hangs [cf. bugme.osdl.org # 1422] on earlier systems. Empirical testing
|
||||
* 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 state=0;
|
||||
u32 state = 0;
|
||||
u32 function = GET_SPEEDSTEP_FREQS;
|
||||
|
||||
if (!(ist_info.event & 0xFFFF)) {
|
||||
|
@ -110,17 +113,25 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
|
|||
|
||||
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__(
|
||||
"push %%ebp\n"
|
||||
"out %%al, (%%dx)\n"
|
||||
"pop %%ebp"
|
||||
: "=a" (result), "=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)
|
||||
: "=a" (result),
|
||||
"=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... */
|
||||
if ((high_mhz + low_mhz) < 600)
|
||||
|
@ -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)
|
||||
*
|
||||
*/
|
||||
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;
|
||||
|
||||
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__(
|
||||
"push %%ebp\n"
|
||||
"out %%al, (%%dx)\n"
|
||||
"pop %%ebp\n"
|
||||
: "=a" (result), "=b" (state), "=D" (edi), "=c" (dummy), "=d" (dummy), "=S" (dummy)
|
||||
: "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0), "D" (0)
|
||||
: "=a" (result),
|
||||
"=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);
|
||||
|
||||
return (state & 1);
|
||||
return state & 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,11 +180,11 @@ static int speedstep_get_state (void)
|
|||
* @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 long flags;
|
||||
unsigned int function=SET_SPEEDSTEP_STATE;
|
||||
unsigned int function = SET_SPEEDSTEP_STATE;
|
||||
unsigned int retry = 0;
|
||||
|
||||
if (state > 0x1)
|
||||
|
@ -180,11 +195,14 @@ static void speedstep_set_state (unsigned int state)
|
|||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
retry++;
|
||||
|
@ -192,20 +210,26 @@ static void speedstep_set_state (unsigned int state)
|
|||
"push %%ebp\n"
|
||||
"out %%al, (%%dx)\n"
|
||||
"pop %%ebp"
|
||||
: "=b" (new_state), "=D" (result), "=c" (dummy), "=a" (dummy),
|
||||
"=d" (dummy), "=S" (dummy)
|
||||
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0), "D" (0)
|
||||
: "=b" (new_state), "=D" (result),
|
||||
"=c" (dummy), "=a" (dummy),
|
||||
"=d" (dummy), "=S" (dummy)
|
||||
: "a" (command), "b" (function), "c" (state),
|
||||
"d" (smi_port), "S" (0), "D" (0)
|
||||
);
|
||||
} while ((new_state != state) && (retry <= SMI_TRIES));
|
||||
|
||||
/* enable IRQs */
|
||||
local_irq_restore(flags);
|
||||
|
||||
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);
|
||||
} else {
|
||||
printk(KERN_ERR "cpufreq: change to state %u failed with new_state %u and result %u\n", state, new_state, result);
|
||||
}
|
||||
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);
|
||||
else
|
||||
printk(KERN_ERR "cpufreq: change to state %u "
|
||||
"failed with new_state %u and result %u\n",
|
||||
state, new_state, result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -219,13 +243,14 @@ static void speedstep_set_state (unsigned int state)
|
|||
*
|
||||
* 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 newstate = 0;
|
||||
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;
|
||||
|
||||
freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
|
||||
|
@ -250,7 +275,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
|
|||
* Limit must be within speedstep_low_freq and speedstep_high_freq, with
|
||||
* 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]);
|
||||
}
|
||||
|
@ -259,7 +284,8 @@ static int speedstep_verify (struct cpufreq_policy *policy)
|
|||
static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int result;
|
||||
unsigned int speed,state;
|
||||
unsigned int speed, state;
|
||||
unsigned int *low, *high;
|
||||
|
||||
/* capability check */
|
||||
if (policy->cpu != 0)
|
||||
|
@ -272,19 +298,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||
}
|
||||
|
||||
/* detect low and high frequency */
|
||||
result = speedstep_smi_get_freqs(&speedstep_freqs[SPEEDSTEP_LOW].frequency,
|
||||
&speedstep_freqs[SPEEDSTEP_HIGH].frequency);
|
||||
low = &speedstep_freqs[SPEEDSTEP_LOW].frequency;
|
||||
high = &speedstep_freqs[SPEEDSTEP_HIGH].frequency;
|
||||
|
||||
result = speedstep_smi_get_freqs(low, high);
|
||||
if (result) {
|
||||
/* fall back to speedstep_lib.c dection mechanism: try both states out */
|
||||
dprintk("could not detect low and high frequencies by SMI call.\n");
|
||||
/* fall back to speedstep_lib.c dection mechanism:
|
||||
* try both states out */
|
||||
dprintk("could not detect low and high frequencies "
|
||||
"by SMI call.\n");
|
||||
result = speedstep_get_freqs(speedstep_processor,
|
||||
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
|
||||
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
|
||||
low, high,
|
||||
NULL,
|
||||
&speedstep_set_state);
|
||||
|
||||
if (result) {
|
||||
dprintk("could not detect two different speeds -- aborting.\n");
|
||||
dprintk("could not detect two different speeds"
|
||||
" -- aborting.\n");
|
||||
return result;
|
||||
} else
|
||||
dprintk("workaround worked.\n");
|
||||
|
@ -295,7 +325,8 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||
speed = speedstep_freqs[state].frequency;
|
||||
|
||||
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));
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
|
@ -304,7 +335,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
|
||||
if (result)
|
||||
return (result);
|
||||
return result;
|
||||
|
||||
cpufreq_frequency_table_get_attr(speedstep_freqs, policy->cpu);
|
||||
|
||||
|
@ -321,7 +352,7 @@ static unsigned int speedstep_get(unsigned int cpu)
|
|||
{
|
||||
if (cpu)
|
||||
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)
|
|||
return result;
|
||||
}
|
||||
|
||||
static struct freq_attr* speedstep_attr[] = {
|
||||
static struct freq_attr *speedstep_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
@ -364,21 +395,23 @@ static int __init speedstep_init(void)
|
|||
speedstep_processor = speedstep_detect_processor();
|
||||
|
||||
switch (speedstep_processor) {
|
||||
case SPEEDSTEP_PROCESSOR_PIII_T:
|
||||
case SPEEDSTEP_PROCESSOR_PIII_C:
|
||||
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
|
||||
case SPEEDSTEP_CPU_PIII_T:
|
||||
case SPEEDSTEP_CPU_PIII_C:
|
||||
case SPEEDSTEP_CPU_PIII_C_EARLY:
|
||||
break;
|
||||
default:
|
||||
speedstep_processor = 0;
|
||||
}
|
||||
|
||||
if (!speedstep_processor) {
|
||||
dprintk ("No supported Intel CPU detected.\n");
|
||||
dprintk("No supported Intel CPU detected.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dprintk("signature:0x%.8lx, command:0x%.8lx, event:0x%.8lx, perf_level:0x%.8lx.\n",
|
||||
ist_info.signature, ist_info.command, ist_info.event, ist_info.perf_level);
|
||||
dprintk("signature:0x%.8lx, command:0x%.8lx, "
|
||||
"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
|
||||
sig= 'ISGE' aka 'Intel Speedstep Gate E' */
|
||||
|
@ -416,17 +449,20 @@ static void __exit speedstep_exit(void)
|
|||
cpufreq_unregister_driver(&speedstep_driver);
|
||||
}
|
||||
|
||||
module_param(smi_port, int, 0444);
|
||||
module_param(smi_cmd, int, 0444);
|
||||
module_param(smi_sig, uint, 0444);
|
||||
module_param(smi_port, int, 0444);
|
||||
module_param(smi_cmd, int, 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_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_PARM_DESC(smi_port, "Override the BIOS-given IST port with this value "
|
||||
"-- Intel's default setting is 0xb2");
|
||||
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_DESCRIPTION ("Speedstep driver for IST applet SMI interface.");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Hiroshi Miura");
|
||||
MODULE_DESCRIPTION("Speedstep driver for IST applet SMI interface.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(speedstep_init);
|
||||
module_exit(speedstep_exit);
|
||||
|
|
|
@ -543,8 +543,6 @@ unsigned long native_calibrate_tsc(void)
|
|||
return tsc_pit_min;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/* Only called from the Powernow K7 cpu freq driver */
|
||||
int recalibrate_cpu_khz(void)
|
||||
{
|
||||
#ifndef CONFIG_SMP
|
||||
|
@ -566,7 +564,6 @@ int recalibrate_cpu_khz(void)
|
|||
|
||||
EXPORT_SYMBOL(recalibrate_cpu_khz);
|
||||
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
/* Accelerators for sched_clock()
|
||||
* convert from cycles(64bits) => nanoseconds (64bits)
|
||||
|
|
|
@ -104,7 +104,8 @@ EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
|
|||
|
||||
|
||||
/* 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 void handle_update(struct work_struct *work);
|
||||
|
||||
|
@ -128,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void)
|
|||
pure_initcall(init_cpufreq_transition_notifier_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)
|
||||
{
|
||||
|
@ -371,7 +372,7 @@ static struct cpufreq_governor *__find_governor(const char *str_governor)
|
|||
struct cpufreq_governor *t;
|
||||
|
||||
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 NULL;
|
||||
|
@ -429,15 +430,11 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
|
|||
|
||||
mutex_unlock(&cpufreq_governor_mutex);
|
||||
}
|
||||
out:
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* drivers/base/cpu.c */
|
||||
extern struct sysdev_class cpu_sysdev_class;
|
||||
|
||||
|
||||
/**
|
||||
* cpufreq_per_cpu_attr_read() / show_##file_name() -
|
||||
* print out cpufreq information
|
||||
|
@ -450,11 +447,12 @@ extern struct sysdev_class cpu_sysdev_class;
|
|||
static ssize_t show_##file_name \
|
||||
(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_max_freq, cpuinfo.max_freq);
|
||||
show_one(cpuinfo_transition_latency, cpuinfo.transition_latency);
|
||||
show_one(scaling_min_freq, min);
|
||||
show_one(scaling_max_freq, max);
|
||||
show_one(scaling_cur_freq, cur);
|
||||
|
@ -476,7 +474,7 @@ static ssize_t store_##file_name \
|
|||
if (ret) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
ret = sscanf (buf, "%u", &new_policy.object); \
|
||||
ret = sscanf(buf, "%u", &new_policy.object); \
|
||||
if (ret != 1) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
|
@ -486,8 +484,8 @@ static ssize_t store_##file_name \
|
|||
return ret ? ret : count; \
|
||||
}
|
||||
|
||||
store_one(scaling_min_freq,min);
|
||||
store_one(scaling_max_freq,max);
|
||||
store_one(scaling_min_freq, min);
|
||||
store_one(scaling_max_freq, max);
|
||||
|
||||
/**
|
||||
* 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,
|
|||
*/
|
||||
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");
|
||||
else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
|
||||
return sprintf(buf, "performance\n");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -531,7 +530,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sscanf (buf, "%15s", str_governor);
|
||||
ret = sscanf(buf, "%15s", str_governor);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -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) {
|
||||
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;
|
||||
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)
|
|||
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
|
||||
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
|
||||
if (i >= (PAGE_SIZE - 5))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
i += sprintf(&buf[i], "\n");
|
||||
return i;
|
||||
|
@ -660,6 +660,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
|
|||
define_one_ro0400(cpuinfo_cur_freq);
|
||||
define_one_ro(cpuinfo_min_freq);
|
||||
define_one_ro(cpuinfo_max_freq);
|
||||
define_one_ro(cpuinfo_transition_latency);
|
||||
define_one_ro(scaling_available_governors);
|
||||
define_one_ro(scaling_driver);
|
||||
define_one_ro(scaling_cur_freq);
|
||||
|
@ -673,6 +674,7 @@ define_one_rw(scaling_setspeed);
|
|||
static struct attribute *default_attrs[] = {
|
||||
&cpuinfo_min_freq.attr,
|
||||
&cpuinfo_max_freq.attr,
|
||||
&cpuinfo_transition_latency.attr,
|
||||
&scaling_min_freq.attr,
|
||||
&scaling_max_freq.attr,
|
||||
&affected_cpus.attr,
|
||||
|
@ -684,10 +686,10 @@ static struct attribute *default_attrs[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
#define to_policy(k) container_of(k,struct cpufreq_policy,kobj)
|
||||
#define to_attr(a) container_of(a,struct freq_attr,attr)
|
||||
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
|
||||
#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 freq_attr *fattr = to_attr(attr);
|
||||
|
@ -853,10 +855,10 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
|
|||
if (cpu == j)
|
||||
continue;
|
||||
|
||||
/* check for existing affected CPUs. They may not be aware
|
||||
* of it due to CPU Hotplug.
|
||||
/* Check for existing affected CPUs.
|
||||
* 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)) {
|
||||
|
||||
/* Set proper policy_cpu */
|
||||
|
@ -1127,8 +1129,8 @@ static void handle_update(struct work_struct *work)
|
|||
* @old_freq: CPU frequency the kernel thinks the CPU 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
|
||||
* to cpufreq_update_policy() or schedule handle_update()).
|
||||
* We adjust to current frequency first, and need to clean up later.
|
||||
* So either call to cpufreq_update_policy() or schedule handle_update()).
|
||||
*/
|
||||
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
|
||||
unsigned int new_freq)
|
||||
|
@ -1610,7 +1612,8 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
|
|||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright (C) 2001 Russell King
|
||||
* (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@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
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -13,22 +13,17 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ctype.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/kmod.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/percpu.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
|
||||
* It helps to keep variable names smaller, simpler
|
||||
|
@ -43,19 +38,31 @@
|
|||
* latency of the processor. The governor will work on any processor with
|
||||
* transition latency <= 10mS, using appropriate sampling
|
||||
* rate.
|
||||
* For CPUs with transition latency > 10mS (mostly drivers
|
||||
* with CPUFREQ_ETERNAL), this governor will not work.
|
||||
* For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
|
||||
* this governor will not work.
|
||||
* All times here are in uS.
|
||||
*/
|
||||
static unsigned int def_sampling_rate;
|
||||
#define MIN_SAMPLING_RATE_RATIO (2)
|
||||
/* 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))
|
||||
#define MIN_SAMPLING_RATE \
|
||||
(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 DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
|
||||
#define LATENCY_MULTIPLIER (1000)
|
||||
#define DEF_SAMPLING_DOWN_FACTOR (1)
|
||||
#define MAX_SAMPLING_DOWN_FACTOR (10)
|
||||
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
|
||||
|
@ -63,12 +70,15 @@ static unsigned int def_sampling_rate;
|
|||
static void do_dbs_timer(struct work_struct *work);
|
||||
|
||||
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;
|
||||
unsigned int prev_cpu_idle_up;
|
||||
unsigned int prev_cpu_idle_down;
|
||||
unsigned int enable;
|
||||
struct delayed_work work;
|
||||
unsigned int down_skip;
|
||||
unsigned int requested_freq;
|
||||
int cpu;
|
||||
unsigned int enable:1;
|
||||
};
|
||||
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 */
|
|||
* cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
|
||||
* is recursive for the same process. -Venki
|
||||
*/
|
||||
static DEFINE_MUTEX (dbs_mutex);
|
||||
static DECLARE_DELAYED_WORK(dbs_work, do_dbs_timer);
|
||||
static DEFINE_MUTEX(dbs_mutex);
|
||||
|
||||
struct dbs_tuners {
|
||||
static struct workqueue_struct *kconservative_wq;
|
||||
|
||||
static struct dbs_tuners {
|
||||
unsigned int sampling_rate;
|
||||
unsigned int sampling_down_factor;
|
||||
unsigned int up_threshold;
|
||||
unsigned int down_threshold;
|
||||
unsigned int ignore_nice;
|
||||
unsigned int freq_step;
|
||||
};
|
||||
|
||||
static struct dbs_tuners dbs_tuners_ins = {
|
||||
} dbs_tuners_ins = {
|
||||
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
|
||||
.down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
|
||||
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
|
||||
|
@ -102,18 +111,37 @@ static struct dbs_tuners dbs_tuners_ins = {
|
|||
.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)
|
||||
add_nice = kstat_cpu(cpu).cpustat.nice;
|
||||
cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
|
||||
busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
|
||||
kstat_cpu(cpu).cpustat.system);
|
||||
|
||||
ret = kstat_cpu(cpu).cpustat.idle +
|
||||
kstat_cpu(cpu).cpustat.iowait +
|
||||
add_nice;
|
||||
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);
|
||||
|
||||
return ret;
|
||||
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);
|
||||
|
||||
if (idle_time == -1ULL)
|
||||
return get_cpu_idle_time_jiffy(cpu, wall);
|
||||
|
||||
return idle_time;
|
||||
}
|
||||
|
||||
/* keep track of frequency transitions */
|
||||
|
@ -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,
|
||||
freq->cpu);
|
||||
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
if (!this_dbs_info->enable)
|
||||
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;
|
||||
}
|
||||
|
@ -140,16 +179,31 @@ static struct notifier_block dbs_cpufreq_notifier_block = {
|
|||
/************************** sysfs interface ************************/
|
||||
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)
|
||||
{
|
||||
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) \
|
||||
static struct freq_attr _name = \
|
||||
#define define_one_ro(_name) \
|
||||
static struct freq_attr _name = \
|
||||
__ATTR(_name, 0444, show_##_name, NULL)
|
||||
|
||||
define_one_ro(sampling_rate_max);
|
||||
|
@ -174,7 +228,8 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
|
|||
{
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf (buf, "%u", &input);
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -190,15 +245,13 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
|
|||
{
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf (buf, "%u", &input);
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dbs_mutex);
|
||||
if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
|
||||
mutex_unlock(&dbs_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dbs_tuners_ins.sampling_rate = input;
|
||||
dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate());
|
||||
mutex_unlock(&dbs_mutex);
|
||||
|
||||
return count;
|
||||
|
@ -209,10 +262,11 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
|
|||
{
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf (buf, "%u", &input);
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -228,10 +282,12 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused,
|
|||
{
|
||||
unsigned int input;
|
||||
int ret;
|
||||
ret = sscanf (buf, "%u", &input);
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -264,12 +320,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
|
|||
}
|
||||
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) {
|
||||
struct cpu_dbs_info_s *j_dbs_info;
|
||||
j_dbs_info = &per_cpu(cpu_dbs_info, j);
|
||||
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
|
||||
j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
|
||||
struct cpu_dbs_info_s *dbs_info;
|
||||
dbs_info = &per_cpu(cpu_dbs_info, j);
|
||||
dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
|
||||
&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);
|
||||
|
||||
|
@ -281,7 +339,6 @@ static ssize_t store_freq_step(struct cpufreq_policy *policy,
|
|||
{
|
||||
unsigned int input;
|
||||
int ret;
|
||||
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
if (ret != 1)
|
||||
|
@ -310,7 +367,7 @@ define_one_rw(down_threshold);
|
|||
define_one_rw(ignore_nice_load);
|
||||
define_one_rw(freq_step);
|
||||
|
||||
static struct attribute * dbs_attributes[] = {
|
||||
static struct attribute *dbs_attributes[] = {
|
||||
&sampling_rate_max.attr,
|
||||
&sampling_rate_min.attr,
|
||||
&sampling_rate.attr,
|
||||
|
@ -329,55 +386,78 @@ static struct attribute_group dbs_attr_group = {
|
|||
|
||||
/************************** 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 tmp_idle_ticks, total_idle_ticks;
|
||||
unsigned int load = 0;
|
||||
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)
|
||||
return;
|
||||
struct cpufreq_policy *policy;
|
||||
unsigned int j;
|
||||
|
||||
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 than 20%, then we try to
|
||||
* increase frequency
|
||||
* Every sampling_rate*sampling_down_factor, we check
|
||||
* - If current idle time is more than 80%, then we try to
|
||||
* decrease frequency
|
||||
* Every sampling_rate, we check, if current idle time is less
|
||||
* than 20% (default), then we try to increase 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.
|
||||
* Frequency reduction happens at minimum steps of
|
||||
* 5% (default) of max_frequency
|
||||
* 5% (default) of maximum frequency
|
||||
*/
|
||||
|
||||
/* Check for frequency increase */
|
||||
idle_ticks = UINT_MAX;
|
||||
/* Get Absolute Load */
|
||||
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;
|
||||
|
||||
j_dbs_info = &per_cpu(cpu_dbs_info, j);
|
||||
|
||||
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
|
||||
|
||||
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);
|
||||
|
||||
j_dbs_info->prev_cpu_nice = kstat_cpu(j).cpustat.nice;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* break out if we 'cannot' reduce the speed as the user might
|
||||
* want freq_step to be zero
|
||||
*/
|
||||
if (dbs_tuners_ins.freq_step == 0)
|
||||
return;
|
||||
|
||||
/* Check for frequency increase */
|
||||
total_idle_ticks = get_cpu_idle_time(cpu);
|
||||
tmp_idle_ticks = total_idle_ticks -
|
||||
this_dbs_info->prev_cpu_idle_up;
|
||||
this_dbs_info->prev_cpu_idle_up = 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;
|
||||
up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
|
||||
usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
|
||||
|
||||
if (idle_ticks < up_idle_ticks) {
|
||||
if (load > dbs_tuners_ins.up_threshold) {
|
||||
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 (this_dbs_info->requested_freq == policy->max)
|
||||
|
@ -398,49 +478,24 @@ static void dbs_check_cpu(int cpu)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Check for frequency decrease */
|
||||
this_dbs_info->down_skip++;
|
||||
if (this_dbs_info->down_skip < dbs_tuners_ins.sampling_down_factor)
|
||||
return;
|
||||
|
||||
/* Check for frequency decrease */
|
||||
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;
|
||||
|
||||
/*
|
||||
* The optimal frequency is the frequency that is the lowest that
|
||||
* can support the current CPU usage without triggering the up
|
||||
* policy. To be safe, we focus 10 points under the threshold.
|
||||
*/
|
||||
if (load < (dbs_tuners_ins.down_threshold - 10)) {
|
||||
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;
|
||||
if (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_RELATION_H);
|
||||
return;
|
||||
|
@ -449,27 +504,45 @@ static void dbs_check_cpu(int cpu)
|
|||
|
||||
static void do_dbs_timer(struct work_struct *work)
|
||||
{
|
||||
int i;
|
||||
mutex_lock(&dbs_mutex);
|
||||
for_each_online_cpu(i)
|
||||
dbs_check_cpu(i);
|
||||
schedule_delayed_work(&dbs_work,
|
||||
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
|
||||
mutex_unlock(&dbs_mutex);
|
||||
struct cpu_dbs_info_s *dbs_info =
|
||||
container_of(work, struct cpu_dbs_info_s, work.work);
|
||||
unsigned int cpu = dbs_info->cpu;
|
||||
|
||||
/* We want all CPUs to do sampling nearly on same jiffy */
|
||||
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
|
||||
|
||||
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);
|
||||
schedule_delayed_work(&dbs_work,
|
||||
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
|
||||
return;
|
||||
/* We want all CPUs to do sampling nearly on same jiffy */
|
||||
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
|
||||
delay -= jiffies % delay;
|
||||
|
||||
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);
|
||||
return;
|
||||
dbs_info->enable = 0;
|
||||
cancel_delayed_work(&dbs_info->work);
|
||||
}
|
||||
|
||||
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->cur_policy = policy;
|
||||
|
||||
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(cpu);
|
||||
j_dbs_info->prev_cpu_idle_down
|
||||
= j_dbs_info->prev_cpu_idle_up;
|
||||
j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j,
|
||||
&j_dbs_info->prev_cpu_wall);
|
||||
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->requested_freq = policy->cur;
|
||||
|
||||
|
@ -523,38 +598,36 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
|||
if (latency == 0)
|
||||
latency = 1;
|
||||
|
||||
def_sampling_rate = 10 * latency *
|
||||
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
|
||||
|
||||
if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
|
||||
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
|
||||
def_sampling_rate =
|
||||
max(latency * LATENCY_MULTIPLIER,
|
||||
MIN_STAT_SAMPLING_RATE);
|
||||
|
||||
dbs_tuners_ins.sampling_rate = def_sampling_rate;
|
||||
|
||||
dbs_timer_init();
|
||||
cpufreq_register_notifier(
|
||||
&dbs_cpufreq_notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
dbs_timer_init(this_dbs_info);
|
||||
|
||||
mutex_unlock(&dbs_mutex);
|
||||
|
||||
break;
|
||||
|
||||
case CPUFREQ_GOV_STOP:
|
||||
mutex_lock(&dbs_mutex);
|
||||
this_dbs_info->enable = 0;
|
||||
dbs_timer_exit(this_dbs_info);
|
||||
sysfs_remove_group(&policy->kobj, &dbs_attr_group);
|
||||
dbs_enable--;
|
||||
|
||||
/*
|
||||
* Stop the timerschedule work, when this governor
|
||||
* is used for first time
|
||||
*/
|
||||
if (dbs_enable == 0) {
|
||||
dbs_timer_exit();
|
||||
if (dbs_enable == 0)
|
||||
cpufreq_unregister_notifier(
|
||||
&dbs_cpufreq_notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
mutex_unlock(&dbs_mutex);
|
||||
|
||||
|
@ -571,6 +644,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
|||
this_dbs_info->cur_policy,
|
||||
policy->min, CPUFREQ_RELATION_L);
|
||||
mutex_unlock(&dbs_mutex);
|
||||
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -588,23 +662,33 @@ struct cpufreq_governor cpufreq_gov_conservative = {
|
|||
|
||||
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)
|
||||
{
|
||||
/* Make sure that the scheduled work is indeed not running */
|
||||
flush_scheduled_work();
|
||||
|
||||
cpufreq_unregister_governor(&cpufreq_gov_conservative);
|
||||
destroy_workqueue(kconservative_wq);
|
||||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR ("Alexander Clouter <alex-kernel@digriz.org.uk>");
|
||||
MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for "
|
||||
MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
|
||||
MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
|
||||
"Low Latency Frequency Transition capable processors "
|
||||
"optimised for use in a battery environment");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
|
||||
fs_initcall(cpufreq_gov_dbs_init);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#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
|
||||
|
@ -51,8 +52,20 @@ static unsigned int def_sampling_rate;
|
|||
(MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10))
|
||||
#define MIN_SAMPLING_RATE \
|
||||
(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 DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
|
||||
#define LATENCY_MULTIPLIER (1000)
|
||||
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
|
||||
|
||||
static void do_dbs_timer(struct work_struct *work);
|
||||
|
@ -65,14 +78,14 @@ struct cpu_dbs_info_s {
|
|||
cputime64_t prev_cpu_wall;
|
||||
cputime64_t prev_cpu_nice;
|
||||
struct cpufreq_policy *cur_policy;
|
||||
struct delayed_work work;
|
||||
struct delayed_work work;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
unsigned int freq_lo;
|
||||
unsigned int freq_lo_jiffies;
|
||||
unsigned int freq_hi_jiffies;
|
||||
int cpu;
|
||||
unsigned int enable:1,
|
||||
sample_type:1;
|
||||
sample_type:1;
|
||||
};
|
||||
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
|
||||
|
||||
|
@ -203,12 +216,28 @@ static void ondemand_powersave_bias_init(void)
|
|||
/************************** sysfs interface ************************/
|
||||
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)
|
||||
{
|
||||
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) \
|
||||
|
@ -238,13 +267,11 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
|
|||
ret = sscanf(buf, "%u", &input);
|
||||
|
||||
mutex_lock(&dbs_mutex);
|
||||
if (ret != 1 || input > MAX_SAMPLING_RATE
|
||||
|| input < MIN_SAMPLING_RATE) {
|
||||
if (ret != 1) {
|
||||
mutex_unlock(&dbs_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dbs_tuners_ins.sampling_rate = input;
|
||||
dbs_tuners_ins.sampling_rate = max(input, minimum_sampling_rate());
|
||||
mutex_unlock(&dbs_mutex);
|
||||
|
||||
return count;
|
||||
|
@ -279,14 +306,14 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
|
|||
unsigned int j;
|
||||
|
||||
ret = sscanf(buf, "%u", &input);
|
||||
if ( ret != 1 )
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if ( input > 1 )
|
||||
if (input > 1)
|
||||
input = 1;
|
||||
|
||||
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);
|
||||
return count;
|
||||
}
|
||||
|
@ -337,7 +364,7 @@ define_one_rw(up_threshold);
|
|||
define_one_rw(ignore_nice_load);
|
||||
define_one_rw(powersave_bias);
|
||||
|
||||
static struct attribute * dbs_attributes[] = {
|
||||
static struct attribute *dbs_attributes[] = {
|
||||
&sampling_rate_max.attr,
|
||||
&sampling_rate_min.attr,
|
||||
&sampling_rate.attr,
|
||||
|
@ -512,8 +539,7 @@ static void do_dbs_timer(struct work_struct *work)
|
|||
}
|
||||
} else {
|
||||
__cpufreq_driver_target(dbs_info->cur_policy,
|
||||
dbs_info->freq_lo,
|
||||
CPUFREQ_RELATION_H);
|
||||
dbs_info->freq_lo, CPUFREQ_RELATION_H);
|
||||
}
|
||||
queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
|
||||
unlock_policy_rwsem_write(cpu);
|
||||
|
@ -530,7 +556,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
|
|||
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
|
||||
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
|
||||
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)
|
||||
|
@ -591,11 +617,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
|||
if (latency == 0)
|
||||
latency = 1;
|
||||
|
||||
def_sampling_rate = latency *
|
||||
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
|
||||
|
||||
if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
|
||||
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
|
||||
def_sampling_rate =
|
||||
max(latency * LATENCY_MULTIPLIER,
|
||||
MIN_STAT_SAMPLING_RATE);
|
||||
|
||||
dbs_tuners_ins.sampling_rate = def_sampling_rate;
|
||||
}
|
||||
|
@ -617,12 +641,10 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
|||
mutex_lock(&dbs_mutex);
|
||||
if (policy->max < this_dbs_info->cur_policy->cur)
|
||||
__cpufreq_driver_target(this_dbs_info->cur_policy,
|
||||
policy->max,
|
||||
CPUFREQ_RELATION_H);
|
||||
policy->max, CPUFREQ_RELATION_H);
|
||||
else if (policy->min > this_dbs_info->cur_policy->cur)
|
||||
__cpufreq_driver_target(this_dbs_info->cur_policy,
|
||||
policy->min,
|
||||
CPUFREQ_RELATION_L);
|
||||
policy->min, CPUFREQ_RELATION_L);
|
||||
mutex_unlock(&dbs_mutex);
|
||||
break;
|
||||
}
|
||||
|
@ -677,7 +699,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
|
|||
MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
|
||||
MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>");
|
||||
MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
|
||||
"Low Latency Frequency Transition capable processors");
|
||||
"Low Latency Frequency Transition capable processors");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* drivers/cpufreq/cpufreq_stats.c
|
||||
*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -23,7 +23,7 @@
|
|||
|
||||
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 = {\
|
||||
.attr = {.name = __stringify(_name), .mode = _mode, }, \
|
||||
.show = _show,\
|
||||
|
@ -50,8 +50,7 @@ struct cpufreq_stats_attribute {
|
|||
ssize_t(*show) (struct cpufreq_stats *, char *);
|
||||
};
|
||||
|
||||
static int
|
||||
cpufreq_stats_update (unsigned int cpu)
|
||||
static int cpufreq_stats_update(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_stats *stat;
|
||||
unsigned long long cur_time;
|
||||
|
@ -68,8 +67,7 @@ cpufreq_stats_update (unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_total_trans(struct cpufreq_policy *policy, char *buf)
|
||||
static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
|
||||
if (!stat)
|
||||
|
@ -78,8 +76,7 @@ show_total_trans(struct cpufreq_policy *policy, char *buf)
|
|||
per_cpu(cpufreq_stats_table, stat->cpu)->total_trans);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
||||
static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
ssize_t len = 0;
|
||||
int i;
|
||||
|
@ -89,14 +86,14 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
|||
cpufreq_stats_update(stat->cpu);
|
||||
for (i = 0; i < stat->state_num; 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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
static ssize_t
|
||||
show_trans_table(struct cpufreq_policy *policy, char *buf)
|
||||
static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
ssize_t len = 0;
|
||||
int i, j;
|
||||
|
@ -139,11 +136,11 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
|
|||
return PAGE_SIZE;
|
||||
return len;
|
||||
}
|
||||
CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
|
||||
CPUFREQ_STATDEVICE_ATTR(trans_table, 0444, show_trans_table);
|
||||
#endif
|
||||
|
||||
CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans);
|
||||
CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state);
|
||||
CPUFREQ_STATDEVICE_ATTR(total_trans, 0444, show_total_trans);
|
||||
CPUFREQ_STATDEVICE_ATTR(time_in_state, 0444, show_time_in_state);
|
||||
|
||||
static struct attribute *default_attrs[] = {
|
||||
&_attr_total_trans.attr,
|
||||
|
@ -158,8 +155,7 @@ static struct attribute_group stats_attr_group = {
|
|||
.name = "stats"
|
||||
};
|
||||
|
||||
static int
|
||||
freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
|
||||
static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < stat->max_state; index++)
|
||||
|
@ -183,8 +179,7 @@ static void cpufreq_stats_free_table(unsigned int cpu)
|
|||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static int
|
||||
cpufreq_stats_create_table (struct cpufreq_policy *policy,
|
||||
static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table)
|
||||
{
|
||||
unsigned int i, j, count = 0, ret = 0;
|
||||
|
@ -194,7 +189,8 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
|
|||
unsigned int cpu = policy->cpu;
|
||||
if (per_cpu(cpufreq_stats_table, cpu))
|
||||
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;
|
||||
|
||||
data = cpufreq_cpu_get(cpu);
|
||||
|
@ -203,13 +199,14 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
|
|||
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;
|
||||
|
||||
stat->cpu = cpu;
|
||||
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;
|
||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
|
@ -255,9 +252,8 @@ error_get_fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
int ret;
|
||||
struct cpufreq_policy *policy = data;
|
||||
|
@ -268,14 +264,14 @@ cpufreq_stat_notifier_policy (struct notifier_block *nb, unsigned long val,
|
|||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (!table)
|
||||
return 0;
|
||||
if ((ret = cpufreq_stats_create_table(policy, table)))
|
||||
ret = cpufreq_stats_create_table(policy, table);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
struct cpufreq_freqs *freq = data;
|
||||
struct cpufreq_stats *stat;
|
||||
|
@ -340,19 +336,20 @@ static struct notifier_block notifier_trans_block = {
|
|||
.notifier_call = cpufreq_stat_notifier_trans
|
||||
};
|
||||
|
||||
static int
|
||||
__init cpufreq_stats_init(void)
|
||||
static int __init cpufreq_stats_init(void)
|
||||
{
|
||||
int ret;
|
||||
unsigned int cpu;
|
||||
|
||||
spin_lock_init(&cpufreq_stats_lock);
|
||||
if ((ret = cpufreq_register_notifier(¬ifier_policy_block,
|
||||
CPUFREQ_POLICY_NOTIFIER)))
|
||||
ret = cpufreq_register_notifier(¬ifier_policy_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((ret = cpufreq_register_notifier(¬ifier_trans_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER))) {
|
||||
ret = cpufreq_register_notifier(¬ifier_trans_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
if (ret) {
|
||||
cpufreq_unregister_notifier(¬ifier_policy_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
return ret;
|
||||
|
@ -364,8 +361,7 @@ __init cpufreq_stats_init(void)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
static void
|
||||
__exit cpufreq_stats_exit(void)
|
||||
static void __exit cpufreq_stats_exit(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
|
@ -379,10 +375,10 @@ __exit cpufreq_stats_exit(void)
|
|||
}
|
||||
}
|
||||
|
||||
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
|
||||
MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
|
||||
MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
|
||||
MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats "
|
||||
"through sysfs filesystem");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(cpufreq_stats_init);
|
||||
module_exit(cpufreq_stats_exit);
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
#include <linux/sysfs.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
|||
userspace */
|
||||
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;
|
||||
|
||||
#define dprintk(msg...) \
|
||||
|
@ -46,9 +43,9 @@ static int cpus_using_userspace_governor;
|
|||
/* keep track of frequency transitions */
|
||||
static int
|
||||
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))
|
||||
return 0;
|
||||
|
@ -57,11 +54,11 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
|||
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 = {
|
||||
.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)
|
|||
* We're safe from concurrent calls to ->target() here
|
||||
* as we hold the userspace_mutex lock. If we were calling
|
||||
* cpufreq_driver_target, a deadlock situation might occur:
|
||||
* A: cpufreq_set (lock userspace_mutex) -> cpufreq_driver_target(lock policy->lock)
|
||||
* B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_mutex)
|
||||
* A: cpufreq_set (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);
|
||||
|
||||
|
@ -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_DESCRIPTION ("CPUfreq policy governor 'userspace'");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
|
||||
"Russell King <rmk@arm.linux.org.uk>");
|
||||
MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
|
||||
fs_initcall(cpufreq_gov_userspace_init);
|
||||
|
|
|
@ -28,7 +28,7 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
|
|||
unsigned int max_freq = 0;
|
||||
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;
|
||||
if (freq == CPUFREQ_ENTRY_INVALID) {
|
||||
dprintk("table entry %u is invalid, skipping\n", i);
|
||||
|
@ -70,7 +70,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
|
|||
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_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;
|
||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
|
@ -125,13 +125,13 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
|||
if (!cpu_online(policy->cpu))
|
||||
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;
|
||||
if (freq == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
if ((freq < policy->min) || (freq > policy->max))
|
||||
continue;
|
||||
switch(relation) {
|
||||
switch (relation) {
|
||||
case CPUFREQ_RELATION_H:
|
||||
if (freq <= target_freq) {
|
||||
if (freq >= optimal.frequency) {
|
||||
|
@ -178,7 +178,7 @@ static DEFINE_PER_CPU(struct cpufreq_frequency_table *, show_table);
|
|||
/**
|
||||
* 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 cpu = policy->cpu;
|
||||
|
@ -190,7 +190,7 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
|
|||
|
||||
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)
|
||||
continue;
|
||||
count += sprintf(&buf[count], "%d ", table[i].frequency);
|
||||
|
@ -234,6 +234,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
|
||||
|
||||
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
|
||||
MODULE_LICENSE ("GPL");
|
||||
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
|
||||
MODULE_DESCRIPTION("CPUfreq frequency table helpers");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
Загрузка…
Ссылка в новой задаче