Commit b982274d 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 ea59d34d 1a9325fb
PowerNow! and Cool'n'Quiet are AMD names for frequency
management capabilities in AMD processors. As the hardware
implementation changes in new generations of the processors,
there is a different cpu-freq driver for each generation.
Note that the driver's will not load on the "wrong" hardware,
so it is safe to try each driver in turn when in doubt as to
which is the correct driver.
Note that the functionality to change frequency (and voltage)
is not available in all processors. The drivers will refuse
to load on processors without this capability. The capability
is detected with the cpuid instruction.
The drivers use BIOS supplied tables to obtain frequency and
voltage information appropriate for a particular platform.
Frequency transitions will be unavailable if the BIOS does
not supply these tables.
6th Generation: powernow-k6
7th Generation: powernow-k7: Athlon, Duron, Geode.
8th Generation: powernow-k8: Athlon, Athlon 64, Opteron, Sempron.
Documentation on this functionality in 8th generation processors
is available in the "BIOS and Kernel Developer's Guide", publication
26094, in chapter 9, available for download from www.amd.com.
BIOS supplied data, for powernow-k7 and for powernow-k8, may be
from either the PSB table or from ACPI objects. The ACPI support
is only available if the kernel config sets CONFIG_ACPI_PROCESSOR.
The powernow-k8 driver will attempt to use ACPI if so configured,
and fall back to PST if that fails.
The powernow-k7 driver will try to use the PSB support first, and
fall back to ACPI if the PSB support fails. A module parameter,
acpi_force, is provided to force ACPI support to be used instead
of PSB support.
......@@ -230,8 +230,9 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver sa1100_driver = {
.flags = (CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC),
.flags = CPUFREQ_STICKY |
CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC,
.verify = sa11x0_verify_speed,
.target = sa1100_target,
.get = sa11x0_getspeed,
......
......@@ -329,8 +329,9 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver sa1110_driver = {
.flags = (CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC),
.flags = CPUFREQ_STICKY |
CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC,
.verify = sa11x0_verify_speed,
.target = sa1110_target,
.get = sa11x0_getspeed,
......
......@@ -254,6 +254,7 @@ static int elanfreq_cpu_exit(struct cpufreq_policy *policy)
static int __init elanfreq_setup(char *str)
{
max_freq = simple_strtoul(str, &str, 0);
printk(KERN_WARNING "You're using the deprecated elanfreq command line option. Use elanfreq.max_freq instead, please!\n");
return 1;
}
__setup("elanfreq=", elanfreq_setup);
......@@ -300,7 +301,7 @@ static void __exit elanfreq_exit(void)
}
MODULE_PARM (max_freq, "i");
module_param (max_freq, int, 0444);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
......
......@@ -124,7 +124,7 @@ static int stock_freq;
/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */
static int pci_busclk = 0;
MODULE_PARM(pci_busclk, "i");
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
......@@ -133,7 +133,7 @@ MODULE_PARM(pci_busclk, "i");
* 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_PARM(max_duration, "i");
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)
......
......@@ -36,6 +36,7 @@
static unsigned int numscales=16, numvscales;
static unsigned int fsb;
static int minvid, maxvid;
static unsigned int minmult, maxmult;
static int can_scale_voltage;
static int vrmrev;
......@@ -45,11 +46,15 @@ static int debug;
static void dprintk(const char *fmt, ...)
{
char s[256];
va_list args;
if (debug == 0)
return;
va_start(args, fmt);
printk(fmt, args);
vsprintf(s, fmt, args);
printk(s);
va_end(args);
}
......@@ -65,7 +70,7 @@ static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table;
static unsigned int calc_speed (int mult, int fsb)
static unsigned int calc_speed(int mult, int fsb)
{
int khz;
khz = (mult/10)*fsb;
......@@ -76,7 +81,7 @@ static unsigned int calc_speed (int mult, int fsb)
}
static int longhaul_get_cpu_mult (void)
static int longhaul_get_cpu_mult(void)
{
unsigned long invalue=0,lo, hi;
......@@ -97,7 +102,7 @@ static int longhaul_get_cpu_mult (void)
* Sets a new clock ratio, and -if applicable- a new Front Side Bus
*/
static void longhaul_setstate (unsigned int clock_ratio_index)
static void longhaul_setstate(unsigned int clock_ratio_index)
{
int speed, mult;
struct cpufreq_freqs freqs;
......@@ -193,7 +198,7 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
#define ROUNDING 0xf
static int _guess (int guess, int maxmult)
static int _guess(int guess)
{
int target;
......@@ -206,7 +211,7 @@ static int _guess (int guess, int maxmult)
}
static int guess_fsb(int maxmult)
static int guess_fsb(void)
{
int speed = (cpu_khz/1000);
int i;
......@@ -216,18 +221,17 @@ static int guess_fsb(int maxmult)
speed &= ~ROUNDING;
for (i=0; i<3; i++) {
if (_guess(speeds[i],maxmult) == speed)
if (_guess(speeds[i]) == speed)
return speeds[i];
}
return 0;
}
static int __init longhaul_get_ranges (void)
static int __init longhaul_get_ranges(void)
{
struct cpuinfo_x86 *c = cpu_data;
unsigned long invalue;
unsigned int minmult=0, maxmult=0;
unsigned int multipliers[32]= {
50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
-1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
......@@ -248,7 +252,7 @@ static int __init longhaul_get_ranges (void)
if (c->x86_model==6)
fsb = eblcr_fsb_table_v1[invalue];
else
fsb = guess_fsb(maxmult);
fsb = guess_fsb();
break;
case 2:
......@@ -398,7 +402,7 @@ static int longhaul_verify(struct cpufreq_policy *policy)
}
static int longhaul_target (struct cpufreq_policy *policy,
static int longhaul_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
......@@ -422,7 +426,7 @@ static unsigned int longhaul_get(unsigned int cpu)
return (calc_speed (longhaul_get_cpu_mult(), fsb));
}
static int __init longhaul_cpu_init (struct cpufreq_policy *policy)
static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
char *cpuname=NULL;
......@@ -536,7 +540,7 @@ static struct cpufreq_driver longhaul_driver = {
.attr = longhaul_attr,
};
static int __init longhaul_init (void)
static int __init longhaul_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
......@@ -553,8 +557,17 @@ static int __init longhaul_init (void)
return -ENODEV;
}
static void __exit longhaul_exit (void)
static void __exit longhaul_exit(void)
{
int i=0;
unsigned int new_clock_ratio;
while (clock_ratio[i] != maxmult)
i++;
new_clock_ratio = longhaul_table[i].index & 0xFF;
longhaul_setstate(new_clock_ratio);
cpufreq_unregister_driver(&longhaul_driver);
kfree(longhaul_table);
}
......
......@@ -27,6 +27,7 @@
#include <linux/smp.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/cpumask.h>
#include <asm/processor.h>
#include <asm/msr.h>
......@@ -132,34 +133,28 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
#endif
/* notifiers */
for_each_cpu(i) {
if (cpu_isset(i, affected_cpu_map)) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
for_each_cpu_mask(i, affected_cpu_map) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
/* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software
* Developer's Manual, Volume 3
*/
for_each_cpu(i) {
if (cpu_isset(i, affected_cpu_map)) {
cpumask_t this_cpu = cpumask_of_cpu(i);
for_each_cpu_mask(i, affected_cpu_map) {
cpumask_t this_cpu = cpumask_of_cpu(i);
set_cpus_allowed(current, this_cpu);
BUG_ON(smp_processor_id() != i);
set_cpus_allowed(current, this_cpu);
BUG_ON(smp_processor_id() != i);
cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
}
cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
}
set_cpus_allowed(current, cpus_allowed);
/* notifiers */
for_each_cpu(i) {
if (cpu_isset(i, affected_cpu_map)) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
for_each_cpu_mask(i, affected_cpu_map) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
return 0;
......
......@@ -733,10 +733,22 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
continue;
}
/* verify only 1 entry from the lo frequency table */
if ((fid < HI_FID_TABLE_BOTTOM) && (cntlofreq++)) {
printk(KERN_ERR PFX "Too many lo freq table entries\n");
goto err_out_mem;
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");
goto err_out_mem;
}
dprintk(KERN_INFO PFX "double low frequency table entry, ignoring it.\n");
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
continue;
} else
cntlofreq = i;
}
if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
......@@ -857,12 +869,9 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
if (smp_processor_id() != pol->cpu) {
printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu);
goto sched_out;
goto err_out;
}
/* from this point, do not exit without restoring preempt and cpu */
preempt_disable();
if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing targ, change pending bit set\n");
goto err_out;
......@@ -900,8 +909,6 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
ret = 0;
err_out:
preempt_enable_no_resched();
sched_out:
set_cpus_allowed(current, oldmask);
schedule();
......
......@@ -67,28 +67,19 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
/**
* speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
* @notify: whether to call cpufreq_notify_transition for CPU speed changes
*
* Tries to change the SpeedStep state.
*/
static void speedstep_set_state (unsigned int state, unsigned int notify)
static void speedstep_set_state (unsigned int state)
{
u32 pmbase;
u8 pm2_blk;
u8 value;
unsigned long flags;
struct cpufreq_freqs freqs;
if (!speedstep_chipset_dev || (state > 0x1))
return;
freqs.old = speedstep_get_processor_frequency(speedstep_processor);
freqs.new = speedstep_freqs[state].frequency;
freqs.cpu = 0; /* speedstep.c is UP only driver */
if (notify)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* get PMBASE */
pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
if (!(pmbase & 0x01))
......@@ -143,9 +134,6 @@ static void speedstep_set_state (unsigned int state, unsigned int notify)
printk (KERN_ERR "cpufreq: change failed - I/O error\n");
}
if (notify)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return;
}
......@@ -252,11 +240,47 @@ static int speedstep_target (struct cpufreq_policy *policy,
unsigned int relation)
{
unsigned int newstate = 0;
struct cpufreq_freqs freqs;
cpumask_t cpus_allowed, affected_cpu_map;
int i;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate))
return -EINVAL;
speedstep_set_state(newstate, 1);
/* 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 */
#ifdef CONFIG_SMP
affected_cpu_map = cpu_sibling_map[policy->cpu];
#else
affected_cpu_map = cpumask_of_cpu(policy->cpu);
#endif
for_each_cpu_mask(i, affected_cpu_map) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
/* switch to physical CPU where state is to be changed */
set_cpus_allowed(current, affected_cpu_map);
speedstep_set_state(newstate);
/* allow to be run on all CPUs */
set_cpus_allowed(current, cpus_allowed);
for_each_cpu_mask(i, affected_cpu_map) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
return 0;
}
......@@ -279,21 +303,35 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
{
int result = 0;
unsigned int speed;
cpumask_t cpus_allowed,affected_cpu_map;
/* capability check */
if (policy->cpu != 0)
if (policy->cpu != 0) /* FIXME: better support for SMT in cpufreq core. Up until then, it's better to register only one CPU */
return -ENODEV;
/* 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[policy->cpu];
#else
affected_cpu_map = cpumask_of_cpu(policy->cpu);
#endif
set_cpus_allowed(current, affected_cpu_map);
/* detect low and high frequency */
result = speedstep_get_freqs(speedstep_processor,
&speedstep_freqs[SPEEDSTEP_LOW].frequency,
&speedstep_freqs[SPEEDSTEP_HIGH].frequency,
&speedstep_set_state);
if (result)
if (result) {
set_cpus_allowed(current, cpus_allowed);
return result;
}
/* get current speed setting */
speed = speedstep_get_processor_frequency(speedstep_processor);
set_cpus_allowed(current, cpus_allowed);
if (!speed)
return -EIO;
......
......@@ -252,11 +252,10 @@ unsigned int speedstep_detect_processor (void)
* specific.
* M-P4-Ms may have either ebx=0xe or 0xf [see above]
* M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf]
* So, how to distinguish all those processors with
* ebx=0xf? I don't know. Sort them out, and wait
* for someone to complain.
* also, M-P4M HTs have ebx=0x8, too
* For now, they are distinguished by the model_id string
*/
if (ebx == 0x0e)
if ((ebx == 0x0e) || (strstr(c->x86_model_id,"Mobile Intel(R) Pentium(R) 4") != NULL))
return SPEEDSTEP_PROCESSOR_P4M;
break;
default:
......@@ -321,9 +320,7 @@ EXPORT_SYMBOL_GPL(speedstep_detect_processor);
unsigned int speedstep_get_freqs(unsigned int processor,
unsigned int *low_speed,
unsigned int *high_speed,
void (*set_state) (unsigned int state,
unsigned int notify)
)
void (*set_state) (unsigned int state))
{
unsigned int prev_speed;
unsigned int ret = 0;
......@@ -340,7 +337,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
local_irq_save(flags);
/* switch to low state */
set_state(SPEEDSTEP_LOW, 0);
set_state(SPEEDSTEP_LOW);
*low_speed = speedstep_get_processor_frequency(processor);
if (!*low_speed) {
ret = -EIO;
......@@ -348,7 +345,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
}
/* switch to high state */
set_state(SPEEDSTEP_HIGH, 0);
set_state(SPEEDSTEP_HIGH);
*high_speed = speedstep_get_processor_frequency(processor);
if (!*high_speed) {
ret = -EIO;
......@@ -362,7 +359,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
/* switch to previous state, if necessary */
if (*high_speed != prev_speed)
set_state(SPEEDSTEP_LOW, 0);
set_state(SPEEDSTEP_LOW);
out:
local_irq_restore(flags);
......
......@@ -44,4 +44,4 @@ extern unsigned int speedstep_get_processor_frequency(unsigned int processor);
extern unsigned int speedstep_get_freqs(unsigned int processor,
unsigned int *low_speed,
unsigned int *high_speed,
void (*set_state) (unsigned int state, unsigned int notify));
void (*set_state) (unsigned int state));
......@@ -139,37 +139,24 @@ static int speedstep_get_state (void)
: "a" (command), "b" (function), "c" (0), "d" (smi_port), "S" (0)
);
return state;
return (state & 1);
}
/**
* speedstep_set_state - set the SpeedStep state
* @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
* @notify: whether to call cpufreq_notify_transition
*
*/
static void speedstep_set_state (unsigned int state, unsigned int notify)
static void speedstep_set_state (unsigned int state)
{
unsigned int old_state, result = 0, command, new_state;
unsigned int result = 0, command, new_state;
unsigned long flags;
struct cpufreq_freqs freqs;
unsigned int function=SET_SPEEDSTEP_STATE;
unsigned int retry = 0;
if (state > 0x1)
return;
old_state = speedstep_get_state();
freqs.old = speedstep_freqs[old_state].frequency;
freqs.new = speedstep_freqs[state].frequency;
freqs.cpu = 0; /* speedstep.c is UP only driver */
if (old_state == state)
return;
if (notify)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* Disable IRQs */
local_irq_save(flags);
......@@ -198,9 +185,6 @@ static void speedstep_set_state (unsigned int state, unsigned int notify)
printk(KERN_ERR "cpufreq: change failed with new_state %u and result %u\n", new_state, result);
}
if (notify)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return;
}
......@@ -217,11 +201,21 @@ 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))
return -EINVAL;
speedstep_set_state(newstate, 1);
freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
freqs.new = speedstep_freqs[newstate].frequency;
freqs.cpu = 0; /* speedstep.c is UP only driver */
if (freqs.old == freqs.new)
return 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
speedstep_set_state(newstate);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0;
}
......
......@@ -722,7 +722,12 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
return cpufreq_driver->target(policy, target_freq, relation);
int retval = -EINVAL;
lock_cpu_hotplug();
if (cpu_online(policy->cpu))
retval = cpufreq_driver->target(policy, target_freq, relation);
unlock_cpu_hotplug();
return retval;
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
......
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