Commit eb2b0751 authored by Dave Jones's avatar Dave Jones

Merge delerium.codemonkey.org.uk:/mnt/data/src/bk/bk-linus

into delerium.codemonkey.org.uk:/mnt/data/src/bk/cpufreq
parents 4d802161 a0dea52b
......@@ -88,6 +88,11 @@ config X86_POWERNOW_K7
If in doubt, say N.
config X86_POWERNOW_K7_ACPI
bool
depends on ((X86_POWERNOW_K7 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K7 = "y" && ACPI_PROCESSOR = "y"))
default y
config X86_POWERNOW_K8
tristate "AMD Opteron/Athlon64 PowerNow!"
depends on CPU_FREQ && EXPERIMENTAL
......@@ -98,6 +103,11 @@ config X86_POWERNOW_K8
If in doubt, say N.
config X86_POWERNOW_K8_ACPI
bool
depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
default y
config X86_GX_SUSPMOD
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
depends on CPU_FREQ
......
......@@ -297,6 +297,7 @@ static void gx_set_cpuspeed(unsigned int khz)
case PCI_DEVICE_ID_CYRIX_5520:
case PCI_DEVICE_ID_CYRIX_5510:
suscfg = gx_params->pci_suscfg | SUSMOD;
break;
default:
local_irq_restore(flags);
dprintk("fatal: try to set unknown chipset.\n");
......
......@@ -5,14 +5,19 @@
* Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by VIA.
*
* VIA have currently 2 different versions of Longhaul.
* VIA have currently 3 different versions of Longhaul.
* Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.
* It is present only in Samuel 1, Samuel 2 and Ezra.
* Version 2 (Powersaver) uses the POWERSAVER MSR at 0x110a.
* It is present in Ezra-T, Nehemiah and above.
* In addition to scaling multiplier, it can also scale voltage.
* There is provision for scaling FSB too, but this doesn't work
* too well in practice.
* It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0.
* Version 2 of longhaul is the same as v1, but adds voltage scaling.
* Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C)
* voltage scaling support has currently been disabled in this driver
* until we have code that gets it right.
* Version 3 of longhaul got renamed to Powersaver and redesigned
* to use the POWERSAVER MSR at 0x110a.
* It is present in Ezra-T (C5M), Nehemiah (C5X) and above.
* It's pretty much the same feature wise to longhaul v2, though
* there is provision for scaling FSB too, but this doesn't work
* too well in practice so we don't even try to use this.
*
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*/
......@@ -95,6 +100,27 @@ static int longhaul_get_cpu_mult(void)
}
static void do_powersaver(union msr_longhaul *longhaul,
unsigned int clock_ratio_index, int version)
{
rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf;
longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
longhaul->bits.EnableSoftBusRatio = 1;
longhaul->bits.RevisionKey = 0;
local_irq_disable();
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
local_irq_enable();
__hlt();
rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
longhaul->bits.EnableSoftBusRatio = 0;
longhaul->bits.RevisionKey = version;
local_irq_disable();
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
local_irq_enable();
}
/**
* longhaul_set_cpu_frequency()
* @clock_ratio_index : bitpattern of the new multiplier.
......@@ -126,61 +152,54 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
dprintk (KERN_INFO PFX "FSB:%d Mult:%d.%dx\n", fsb, mult/10, mult%10);
switch (longhaul_version) {
/*
* Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
* Software controlled multipliers only.
*
* *NB* Until we get voltage scaling working v1 & v2 are the same code.
* Longhaul v2 appears in Samuel2 Steppings 1->7 [C5b] and Ezra [C5C]
*/
case 1:
rdmsrl (MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */
bcr2.bits.ESOFTBF = 1;
bcr2.bits.CLOCKMUL = clock_ratio_index;
local_irq_disable();
wrmsrl (MSR_VIA_BCR2, bcr2.val);
local_irq_enable();
__hlt();
/* Disable software clock multiplier */
rdmsrl (MSR_VIA_BCR2, bcr2.val);
bcr2.bits.ESOFTBF = 0;
local_irq_disable();
wrmsrl (MSR_VIA_BCR2, bcr2.val);
local_irq_enable();
break;
/*
* Powersaver. (Ezra-T [C5M], Nehemiah [C5N])
* Longhaul v3 (aka Powersaver). (Ezra-T [C5M])
* We can scale voltage with this too, but that's currently
* disabled until we come up with a decent 'match freq to voltage'
* algorithm.
* We also need to do the voltage/freq setting in order depending
* on the direction of scaling (like we do in powernow-k7.c)
* Ezra-T was alleged to do FSB scaling too, but it never worked in practice.
* When we add voltage scaling, we will also need to do the
* voltage/freq setting in order depending on the direction
* of scaling (like we do in powernow-k7.c)
*/
case 2:
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
longhaul.bits.EnableSoftBusRatio = 1;
/* We must program the revision key only with values we
* know about, not blindly copy it from 0:3 */
longhaul.bits.RevisionKey = 3; /* SoftVID & SoftBSEL */
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
__hlt();
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
longhaul.bits.EnableSoftBusRatio = 0;
longhaul.bits.RevisionKey = 3;
wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
do_powersaver(&longhaul, clock_ratio_index, 3);
break;
case 3:
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
longhaul.bits.EnableSoftBusRatio = 1;
longhaul.bits.RevisionKey = 0x0;
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
__hlt();
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
longhaul.bits.EnableSoftBusRatio = 0;
longhaul.bits.RevisionKey = 0xf;
wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
/*
* Powersaver. (Nehemiah [C5N])
* As for Ezra-T, we don't do voltage yet.
* This can do FSB scaling too, but it has never been proven
* to work in practice.
*/
case 3:
do_powersaver(&longhaul, clock_ratio_index, 0xf);
break;
}
......@@ -289,7 +308,11 @@ static int __init longhaul_get_ranges(void)
minmult=50;
maxmult=longhaul_get_cpu_mult();
fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
/* Starting with the 1.2GHz parts, theres a 200MHz bus. */
if ((cpu_khz/1000) > 1200)
fsb = 200;
else
fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
break;
}
......
......@@ -7,7 +7,7 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/cpufreq.h>
......@@ -19,7 +19,7 @@
static struct cpufreq_driver longrun_driver;
/**
* longrun_{low,high}_freq is needed for the conversion of cpufreq kHz
* longrun_{low,high}_freq is needed for the conversion of cpufreq kHz
* values into per cent values. In TMTA microcode, the following is valid:
* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
*/
......@@ -42,18 +42,18 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy)
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
else
policy->policy = CPUFREQ_POLICY_POWERSAVE;
rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
msr_lo &= 0x0000007F;
msr_hi &= 0x0000007F;
if ( longrun_high_freq <= longrun_low_freq ) {
/* Assume degenerate Longrun table */
policy->min = policy->max = longrun_high_freq;
} else {
policy->min = longrun_low_freq + msr_lo *
policy->min = longrun_low_freq + msr_lo *
((longrun_high_freq - longrun_low_freq) / 100);
policy->max = longrun_low_freq + msr_hi *
policy->max = longrun_low_freq + msr_hi *
((longrun_high_freq - longrun_low_freq) / 100);
}
policy->cpu = 0;
......@@ -79,9 +79,9 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
/* Assume degenerate Longrun table */
pctg_lo = pctg_hi = 100;
} else {
pctg_lo = (policy->min - longrun_low_freq) /
pctg_lo = (policy->min - longrun_low_freq) /
((longrun_high_freq - longrun_low_freq) / 100);
pctg_hi = (policy->max - longrun_low_freq) /
pctg_hi = (policy->max - longrun_low_freq) /
((longrun_high_freq - longrun_low_freq) / 100);
}
......@@ -118,7 +118,7 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
* longrun_verify_poliy - verifies a new CPUFreq policy
* @policy: the policy to verify
*
* Validates a new CPUFreq policy. This function has to be called with
* Validates a new CPUFreq policy. This function has to be called with
* cpufreq_driver locked.
*/
static int longrun_verify_policy(struct cpufreq_policy *policy)
......@@ -127,8 +127,8 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
return -EINVAL;
policy->cpu = 0;
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) &&
......@@ -160,7 +160,7 @@ static unsigned int longrun_get(unsigned int cpu)
* TMTA rules:
* performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
*/
static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
unsigned int *high_freq)
{
u32 msr_lo, msr_hi;
......@@ -174,9 +174,9 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
if (cpu_has(c, X86_FEATURE_LRTI)) {
/* if the LongRun Table Interface is present, the
* detection is a bit easier:
* detection is a bit easier:
* For minimum frequency, read out the maximum
* level (msr_hi), write that into "currently
* level (msr_hi), write that into "currently
* selected level", and read out the frequency.
* For maximum frequency, read out level zero.
*/
......@@ -223,7 +223,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
/* restore values */
wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
}
/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
......@@ -237,7 +237,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
if ((ecx > 95) || (ecx == 0) || (eax < ebx))
return -EIO;
edx = (eax - ebx) / (100 - ecx);
edx = (eax - ebx) / (100 - ecx);
*low_freq = edx * 1000; /* back to kHz */
if (*low_freq > *high_freq)
......@@ -249,7 +249,7 @@ static unsigned int __init longrun_determine_freqs(unsigned int *low_freq,
static int __init longrun_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
int result = 0;
/* capability check */
if (policy->cpu != 0)
......@@ -265,15 +265,15 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.max_freq = longrun_high_freq;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
longrun_get_policy(policy);
return 0;
}
static struct cpufreq_driver longrun_driver = {
.flags = CPUFREQ_CONST_LOOPS,
.verify = longrun_verify_policy,
.setpolicy = longrun_set_policy,
.verify = longrun_verify_policy,
.setpolicy = longrun_set_policy,
.get = longrun_get,
.init = longrun_cpu_init,
.name = "longrun",
......@@ -290,7 +290,7 @@ static int __init longrun_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
!cpu_has(c, X86_FEATURE_LONGRUN))
return -ENODEV;
......
......@@ -184,7 +184,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
"The speedstep_centrino module offers voltage scaling"
" in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n");
/* on P-4s, the TSC runs with constant frequency independent wether
/* on P-4s, the TSC runs with constant frequency independent whether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
......@@ -195,7 +195,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
return 0;
}
/* on P-4s, the TSC runs with constant frequency independent wether
/* on P-4s, the TSC runs with constant frequency independent whether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
......
......@@ -6,8 +6,6 @@
* Licensed under the terms of the GNU GPL License version 2.
* Based upon datasheets & sample CPUs kindly provided by AMD.
*
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
*
* 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.
......@@ -29,21 +27,13 @@
#include <asm/io.h>
#include <asm/system.h>
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif
#include "powernow-k7.h"
#define DEBUG
#ifdef DEBUG
#define dprintk(msg...) printk(msg)
#else
#define dprintk(msg...) do { } while(0)
#endif
#define PFX "powernow: "
......@@ -64,7 +54,7 @@ struct pst_s {
u8 numpstates;
};
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
union powernow_acpi_control_t {
struct {
unsigned long fid:5,
......@@ -97,6 +87,7 @@ static int fid_codes[32] = {
*/
static int acpi_force;
static int debug;
static struct cpufreq_frequency_table *powernow_table;
......@@ -109,6 +100,21 @@ static unsigned int fsb;
static unsigned int latency;
static char have_a0;
static void dprintk(const char *fmt, ...)
{
char s[256];
va_list args;
if (debug==0)
return;
va_start(args,fmt);
vsprintf(s, fmt, args);
printk(s);
va_end(args);
}
static int check_fsb(unsigned int fsbspeed)
{
int delta;
......@@ -190,13 +196,13 @@ static int get_ranges (unsigned char *pst)
speed = powernow_table[j].frequency;
if ((fid_codes[fid] % 10)==5) {
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (have_a0 == 1)
powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID;
#endif
}
dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid,
dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid,
fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000);
if (speed < minimum_speed)
......@@ -285,7 +291,7 @@ static void change_speed (unsigned int index)
change_VID(vid);
change_FID(fid);
}
if (have_a0 == 1)
local_irq_enable();
......@@ -294,7 +300,7 @@ static void change_speed (unsigned int index)
}
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
struct acpi_processor_performance *acpi_processor_perf;
......@@ -377,7 +383,7 @@ static int powernow_acpi_init(void)
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
}
dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid,
dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz]) ", fid,
fid_codes[fid] / 10, fid_codes[fid] % 10, speed/1000);
dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000,
mobile_vid_table[vid]%1000);
......@@ -467,9 +473,9 @@ static int powernow_decode_bios (int maxfid, int startvid)
(maxfid==pst->maxfid) && (startvid==pst->startvid))
{
dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst);
dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid);
dprintk ("fsb: %d\t", pst->fsbspeed);
dprintk ("maxFID: 0x%x\t", pst->maxfid);
dprintk (KERN_INFO PFX " cpuid: 0x%x ", pst->cpuid);
dprintk ("fsb: %d ", pst->fsbspeed);
dprintk ("maxFID: 0x%x ", pst->maxfid);
dprintk ("startvid: 0x%x\n", pst->startvid);
ret = get_ranges ((char *) pst + sizeof (struct pst_s));
......@@ -591,14 +597,14 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
/* A K7 with powernow technology is set to max frequency by BIOS */
fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID];
if (!fsb) {
printk(KERN_WARNING PFX "can not determine bus frequency\n");
return -EINVAL;
}
dprintk(KERN_INFO PFX "FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000);
if (dmi_check_system(powernow_dmi_table) || acpi_force) {
if (dmi_check_system(powernow_dmi_table) || acpi_force) {
printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n");
result = powernow_acpi_init();
} else {
......@@ -648,14 +654,14 @@ static struct freq_attr* powernow_table_attr[] = {
};
static struct cpufreq_driver powernow_driver = {
.verify = powernow_verify,
.target = powernow_target,
.get = powernow_get,
.init = powernow_cpu_init,
.exit = powernow_cpu_exit,
.name = "powernow-k7",
.owner = THIS_MODULE,
.attr = powernow_table_attr,
.verify = powernow_verify,
.target = powernow_target,
.get = powernow_get,
.init = powernow_cpu_init,
.exit = powernow_cpu_exit,
.name = "powernow-k7",
.owner = THIS_MODULE,
.attr = powernow_table_attr,
};
static int __init powernow_init (void)
......@@ -668,7 +674,7 @@ static int __init powernow_init (void)
static void __exit powernow_exit (void)
{
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
if (acpi_processor_perf) {
acpi_processor_unregister_performance(acpi_processor_perf, 0);
kfree(acpi_processor_perf);
......@@ -679,8 +685,10 @@ static void __exit powernow_exit (void)
kfree(powernow_table);
}
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "enable debug output.");
module_param(acpi_force, int, 0444);
MODULE_PARM_DESC(acpi_force, "Force ACPI to be used");
MODULE_PARM_DESC(acpi_force, "Force ACPI to be used.");
MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors.");
......
......@@ -32,7 +32,7 @@
#include <asm/io.h>
#include <asm/delay.h>
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif
......@@ -664,7 +664,7 @@ static int find_psb_table(struct powernow_k8_data *data)
return -ENODEV;
}
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
{
if (!data->acpi_data.state_count)
......@@ -1024,7 +1024,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol)
return -ENODEV;
}
static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
static int __devexit powernowk8_cpu_exit (struct cpufreq_policy *pol)
{
struct powernow_k8_data *data = powernow_data[pol->cpu];
......@@ -1076,7 +1076,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.verify = powernowk8_verify,
.target = powernowk8_target,
.init = powernowk8_cpu_init,
.exit = powernowk8_cpu_exit,
.exit = __devexit_p(powernowk8_cpu_exit),
.get = powernowk8_get,
.name = "powernow-k8",
.owner = THIS_MODULE,
......
......@@ -29,7 +29,7 @@ struct powernow_k8_data {
* frequency is in kHz */
struct cpufreq_frequency_table *powernow_table;
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#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;
......
......@@ -7,7 +7,7 @@
* for chipsets ICH2-M and ICH3-M.
*
* Many thanks to Ducrot Bruno for finding and fixing the last
* "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
* "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler
* for extensive testing.
*
* BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
......@@ -19,7 +19,7 @@
*********************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
......@@ -29,24 +29,24 @@
/* speedstep_chipset:
* It is necessary to know which chipset is used. As accesses to
* this device occur at various places in this module, we need a
* It is necessary to know which chipset is used. As accesses to
* this device occur at various places in this module, we need a
* static struct pci_dev * pointing to that device.
*/
static struct pci_dev *speedstep_chipset_dev;
static struct pci_dev *speedstep_chipset_dev;
/* speedstep_processor
*/
static unsigned int speedstep_processor = 0;
static unsigned int speedstep_processor = 0;
/*
/*
* There are only two frequency states for each processor. Values
* are in kHz for the time being.
*/
static struct cpufreq_frequency_table speedstep_freqs[] = {
{SPEEDSTEP_HIGH, 0},
{SPEEDSTEP_HIGH, 0},
{SPEEDSTEP_LOW, 0},
{0, CPUFREQ_TABLE_END},
};
......@@ -68,22 +68,21 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
* speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
*
* Tries to change the SpeedStep state.
* Tries to change the SpeedStep state.
*/
static void speedstep_set_state (unsigned int state)
{
u32 pmbase;
u8 pm2_blk;
u8 value;
unsigned long flags;
u32 pmbase;
u8 pm2_blk;
u8 value;
unsigned long flags;
if (!speedstep_chipset_dev || (state > 0x1))
return;
/* get PMBASE */
pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
if (!(pmbase & 0x01))
{
if (!(pmbase & 0x01)) {
printk(KERN_ERR "cpufreq: could not find speedstep register\n");
return;
}
......@@ -146,18 +145,16 @@ static void speedstep_set_state (unsigned int state)
*/
static int speedstep_activate (void)
{
u16 value = 0;
u16 value = 0;
if (!speedstep_chipset_dev)
return -EINVAL;
pci_read_config_word(speedstep_chipset_dev,
0x00A0, &value);
pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
if (!(value & 0x08)) {
value |= 0x08;
dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n");
pci_write_config_word(speedstep_chipset_dev,
0x00A0, value);
pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
}
return 0;
......@@ -167,15 +164,15 @@ static int speedstep_activate (void)
/**
* speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
*
* Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to
* the LPC bridge / PM module which contains all power-management
* Detects ICH2-M, ICH3-M and ICH4-M so far. The pci_dev points to
* the LPC bridge / PM module which contains all power-management
* functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
* chipset, or zero on failure.
*/
static unsigned int speedstep_detect_chipset (void)
{
speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801DB_12,
PCI_DEVICE_ID_INTEL_82801DB_12,
PCI_ANY_ID,
PCI_ANY_ID,
NULL);
......@@ -183,7 +180,7 @@ static unsigned int speedstep_detect_chipset (void)
return 4; /* 4-M */
speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801CA_12,
PCI_DEVICE_ID_INTEL_82801CA_12,
PCI_ANY_ID,
PCI_ANY_ID,
NULL);
......@@ -198,11 +195,11 @@ static unsigned int speedstep_detect_chipset (void)
NULL);
if (speedstep_chipset_dev) {
/* speedstep.c causes lockups on Dell Inspirons 8000 and
* 8100 which use a pretty old revision of the 82815
* 8100 which use a pretty old revision of the 82815
* host brige. Abort on these systems.
*/
static struct pci_dev *hostbridge;
u8 rev = 0;
static struct pci_dev *hostbridge;
u8 rev = 0;
hostbridge = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82815_MC,
......@@ -212,7 +209,7 @@ static unsigned int speedstep_detect_chipset (void)
if (!hostbridge)
return 2; /* 2-M */
pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
if (rev < 5) {
dprintk(KERN_INFO "cpufreq: hostbridge does not support speedstep\n");
......@@ -226,6 +223,23 @@ static unsigned int speedstep_detect_chipset (void)
return 0;
}
static unsigned int speedstep_get(unsigned int cpu)
{
unsigned int speed;
cpumask_t cpus_allowed,affected_cpu_map;
/* only run on CPU to be set, or on its sibling */
cpus_allowed = current->cpus_allowed;
#ifdef CONFIG_SMP
affected_cpu_map = cpu_sibling_map[cpu];
#else
affected_cpu_map = cpumask_of_cpu(cpu);
#endif
set_cpus_allowed(current, affected_cpu_map);
speed=speedstep_get_processor_frequency(speedstep_processor);
set_cpus_allowed(current, cpus_allowed);
return speed;
}
/**
* speedstep_target - set a new CPUFreq policy
......@@ -239,7 +253,7 @@ static int speedstep_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int newstate = 0;
unsigned int newstate = 0;
struct cpufreq_freqs freqs;
cpumask_t cpus_allowed, affected_cpu_map;
int i;
......@@ -247,14 +261,14 @@ static int speedstep_target (struct cpufreq_policy *policy,
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
return -EINVAL;
freqs.old = speedstep_get(policy->cpu);
freqs.new = speedstep_freqs[newstate].frequency;
freqs.cpu = policy->cpu;
/* no transition necessary */
if (freqs.old == freqs.new)
return 0;
freqs.old = speedstep_get_processor_frequency(speedstep_processor);
freqs.new = speedstep_freqs[newstate].frequency;
freqs.cpu = policy->cpu;
cpus_allowed = current->cpus_allowed;
/* only run on CPU to be set, or on its sibling */
......@@ -301,9 +315,9 @@ static int speedstep_verify (struct cpufreq_policy *policy)
static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
unsigned int speed;
cpumask_t cpus_allowed,affected_cpu_map;
int result = 0;
unsigned int speed;
cpumask_t cpus_allowed,affected_cpu_map;
/* capability check */
......@@ -324,18 +338,16 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
&speedstep_set_state);
if (result) {
set_cpus_allowed(current, cpus_allowed);
set_cpus_allowed(current, cpus_allowed);
if (result)
return result;
}
/* get current speed setting */
speed = speedstep_get_processor_frequency(speedstep_processor);
set_cpus_allowed(current, cpus_allowed);
speed = speedstep_get(policy->cpu);
if (!speed)
return -EIO;
dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n",
dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high",
(speed / 1000));
......@@ -360,11 +372,6 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
return 0;
}
static unsigned int speedstep_get(unsigned int cpu)
{
return speedstep_get_processor_frequency(speedstep_processor);
}
static struct freq_attr* speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
......@@ -372,14 +379,14 @@ static struct freq_attr* speedstep_attr[] = {
static struct cpufreq_driver speedstep_driver = {
.name = "speedstep-ich",
.verify = speedstep_verify,
.target = speedstep_target,
.init = speedstep_cpu_init,
.exit = speedstep_cpu_exit,
.get = speedstep_get,
.owner = THIS_MODULE,
.attr = speedstep_attr,
.name = "speedstep-ich",
.verify = speedstep_verify,
.target = speedstep_target,
.init = speedstep_cpu_init,
.exit = speedstep_cpu_exit,
.get = speedstep_get,
.owner = THIS_MODULE,
.attr = speedstep_attr,
};
......
......@@ -115,6 +115,11 @@ static int speedstep_smi_get_freqs (unsigned int *low, unsigned int *high)
: "=a" (result), "=b" (high_mhz), "=c" (low_mhz), "=d" (state), "=D" (edi)
: "a" (command), "b" (function), "c" (state), "d" (smi_port), "S" (0)
);
/* abort if results are obviously incorrect... */
if ((high_mhz + low_mhz) < 600)
return -EINVAL;
*high = high_mhz * 1000;
*low = low_mhz * 1000;
......@@ -180,7 +185,7 @@ static void speedstep_set_state (unsigned int state)
local_irq_restore(flags);
if (new_state == state) {
dprintk(KERN_INFO "cpufreq: change to %u MHz succeeded after %u tries with result %u\n", (freqs.new / 1000), retry, result);
dprintk(KERN_INFO "cpufreq: 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 failed with new_state %u and result %u\n", new_state, result);
}
......
......@@ -17,7 +17,7 @@
* Fixes
* Felix Koop : NR_CPUS used properly
* Jose Renau : Handle single CPU case.
* Alan Cox : By repeated request 8) - Total BogoMIP report.
* Alan Cox : By repeated request 8) - Total BogoMIPS report.
* Greg Wright : Fix for kernel stacks panic.
* Erich Boleyn : MP v1.4 and additional changes.
* Matthias Sattler : Changes for 2.1 kernel map.
......
......@@ -265,7 +265,8 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
{
struct cpufreq_freqs *freq = data;
write_seqlock_irq(&xtime_lock);
if (val != CPUFREQ_RESUMECHANGE)
write_seqlock_irq(&xtime_lock);
if (!ref_freq) {
ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
......@@ -291,7 +292,9 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
}
#endif
}
write_sequnlock_irq(&xtime_lock);
if (val != CPUFREQ_RESUMECHANGE)
write_sequnlock_irq(&xtime_lock);
return 0;
}
......
......@@ -41,4 +41,9 @@ config X86_POWERNOW_K8
If in doubt, say N.
config X86_POWERNOW_K8_ACPI
bool
depends on ((X86_POWERNOW_K8 = "m" && ACPI_PROCESSOR) || (X86_POWERNOW_K8 = "y" && ACPI_PROCESSOR = "y"))
default y
endmenu
......@@ -99,6 +99,88 @@ static void cpufreq_cpu_put(struct cpufreq_policy *data)
module_put(cpufreq_driver->owner);
}
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/
/**
* adjust_jiffies - adjust the system "loops_per_jiffy"
*
* This function alters the system "loops_per_jiffy" for the clock
* speed change. Note that loops_per_jiffy cannot be updated on SMP
* systems as each CPU might be scaled differently. So, use the arch
* per-CPU loops_per_jiffy value wherever possible.
*/
#ifndef CONFIG_SMP
static unsigned long l_p_j_ref;
static unsigned int l_p_j_ref_freq;
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{
if (ci->flags & CPUFREQ_CONST_LOOPS)
return;
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
(val == CPUFREQ_RESUMECHANGE))
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
}
#else
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
#endif
/**
* cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
*
* This function calls the transition notifiers and the "adjust_jiffies" function. It is called
* twice on all CPU frequency changes that have external effects.
*/
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{
BUG_ON(irqs_disabled());
freqs->flags = cpufreq_driver->flags;
down_read(&cpufreq_notifier_rwsem);
switch (state) {
case CPUFREQ_PRECHANGE:
/* detect if the driver reported a value as "old frequency" which
* is not equal to what the cpufreq core thinks is "old frequency".
*/
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((likely(cpufreq_cpu_data[freqs->cpu])) &&
(likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{
if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC)
panic("CPU Frequency is out of sync.");
printk(KERN_WARNING "Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur);
freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
}
}
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
if (likely(cpufreq_cpu_data[freqs->cpu]))
cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
break;
}
up_read(&cpufreq_notifier_rwsem);
}
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
......@@ -617,8 +699,8 @@ static int cpufreq_resume(struct sys_device * sysdev)
if (cpufreq_driver->flags & CPUFREQ_PANIC_RESUME_OUTOFSYNC)
panic("CPU Frequency is out of sync.");
printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing"
"core thinks of %u, is %u kHz.\n", cpu_policy->cur, cur_freq);
printk(KERN_WARNING "Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur);
freqs.cpu = cpu;
freqs.old = cpu_policy->cur;
......@@ -626,6 +708,8 @@ static int cpufreq_resume(struct sys_device * sysdev)
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
cpu_policy->cur = cur_freq;
}
}
......@@ -1005,87 +1089,6 @@ int cpufreq_update_policy(unsigned int cpu)
EXPORT_SYMBOL(cpufreq_update_policy);
/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/
/**
* adjust_jiffies - adjust the system "loops_per_jiffy"
*
* This function alters the system "loops_per_jiffy" for the clock
* speed change. Note that loops_per_jiffy cannot be updated on SMP
* systems as each CPU might be scaled differently. So, use the arch
* per-CPU loops_per_jiffy value wherever possible.
*/
#ifndef CONFIG_SMP
static unsigned long l_p_j_ref;
static unsigned int l_p_j_ref_freq;
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{
if (ci->flags & CPUFREQ_CONST_LOOPS)
return;
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
(val == CPUFREQ_RESUMECHANGE))
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
}
#else
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
#endif
/**
* cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
*
* This function calls the transition notifiers and the "adjust_jiffies" function. It is called
* twice on all CPU frequency changes that have external effects.
*/
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{
BUG_ON(irqs_disabled());
freqs->flags = cpufreq_driver->flags;
down_read(&cpufreq_notifier_rwsem);
switch (state) {
case CPUFREQ_PRECHANGE:
/* detect if the driver reported a value as "old frequency" which
* is not equal to what the cpufreq core thinks is "old frequency".
*/
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{
if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC)
panic("CPU Frequency is out of sync.");
printk(KERN_WARNING "Warning: CPU frequency out of sync: "
"cpufreq and timing core thinks of %u, is %u kHz.\n",
cpufreq_cpu_data[freqs->cpu]->cur, freqs->old);
freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
}
}
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
break;
}
up_read(&cpufreq_notifier_rwsem);
}
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/
......
......@@ -82,6 +82,13 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
{
struct cpufreq_freqs *freq = data;
/* Don't update cur_freq if CPU is managed and we're
* waking up: else we won't remember what frequency
* we need to set the CPU to.
*/
if (cpu_is_managed[freq->cpu] && (val == CPUFREQ_RESUMECHANGE))
return 0;
cpu_cur_freq[freq->cpu] = freq->new;
return 0;
......@@ -147,6 +154,9 @@ EXPORT_SYMBOL_GPL(cpufreq_setmax);
#ifdef CONFIG_CPU_FREQ_24_API
#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01
static unsigned int warning_print = 0;
/*********************** cpufreq_sysctl interface ********************/
static int
......@@ -162,6 +172,13 @@ cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
return 0;
}
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
if (write) {
unsigned int freq;
......@@ -197,6 +214,13 @@ cpufreq_sysctl(ctl_table *table, int __user *name, int nlen,
if (!cpu_online(cpu))
return -EINVAL;
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
if (oldval && oldlenp) {
size_t oldlen;
......@@ -522,6 +546,9 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
else if (policy->min > cpu_cur_freq[cpu])
__cpufreq_driver_target(&current_policy[cpu], policy->min,
CPUFREQ_RELATION_L);
else
__cpufreq_driver_target(&current_policy[cpu], cpu_cur_freq[cpu],
CPUFREQ_RELATION_L);
memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
up(&userspace_sem);
break;
......
......@@ -12,9 +12,12 @@
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#warning This module will be removed from the 2.6. kernel series soon after 2005-01-01
#define CPUFREQ_ALL_CPUS ((NR_CPUS))
static unsigned int warning_print = 0;
/**
* cpufreq_parse_policy - parse a policy string
* @input_string: the string to parse.
......@@ -110,6 +113,13 @@ static int cpufreq_proc_read (
if (off != 0)
goto end;
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n");
for (i=0;i<NR_CPUS;i++) {
if (!cpu_online(i))
......@@ -179,6 +189,13 @@ static int cpufreq_proc_write (
if (copy_from_user(proc_string, buffer, count))
return -EFAULT;
if (!warning_print) {
warning_print++;
printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
"will be removed from (new) 2.6. kernels soon "
"after 2005-01-01\n");
}
proc_string[count] = '\0';
......
......@@ -101,6 +101,11 @@ __acpi_release_global_lock (unsigned int *lock)
:"=r"(n_hi), "=r"(n_lo) \
:"0"(n_hi), "1"(n_lo))
/*
* Refer Intel ACPI _PDC support document for bit definitions
*/
#define ACPI_PDC_EST_CAPABILITY_SMP 0xa
#define ACPI_PDC_EST_CAPABILITY_MSR 0x1
/*
* Refer Intel ACPI _PDC support document for bit definitions
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment