Commit e79b352d authored by Linus Torvalds's avatar Linus Torvalds

Merge

parents 10cba765 6deb6e5b
...@@ -92,3 +92,7 @@ values: ...@@ -92,3 +92,7 @@ values:
cpu - number of the affected CPU cpu - number of the affected CPU
old - old frequency old - old frequency
new - new frequency new - new frequency
If the cpufreq core detects the frequency has changed while the system
was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
second argument.
...@@ -152,10 +152,10 @@ static int integrator_set_target(struct cpufreq_policy *policy, ...@@ -152,10 +152,10 @@ static int integrator_set_target(struct cpufreq_policy *policy,
return 0; return 0;
} }
static int integrator_cpufreq_init(struct cpufreq_policy *policy) static unsigned int integrator_get(unsigned int cpu)
{ {
unsigned long cpus_allowed; unsigned long cpus_allowed;
unsigned int cpu = policy->cpu; unsigned int current_freq;
u_int cm_osc; u_int cm_osc;
struct icst525_vco vco; struct icst525_vco vco;
...@@ -175,15 +175,22 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy) ...@@ -175,15 +175,22 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
vco.v = cm_osc & 255; vco.v = cm_osc & 255;
vco.r = 22; vco.r = 22;
current_freq = icst525_khz(&cclk_params, vco); /* current freq */
set_cpus_allowed(current, cpus_allowed);
return current_freq;
}
static int integrator_cpufreq_init(struct cpufreq_policy *policy)
{
/* set default policy and cpuinfo */ /* set default policy and cpuinfo */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.max_freq = 160000; policy->cpuinfo.max_freq = 160000;
policy->cpuinfo.min_freq = 12000; policy->cpuinfo.min_freq = 12000;
policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */ policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
policy->cur = policy->min = policy->max = policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
icst525_khz(&cclk_params, vco); /* current freq */
set_cpus_allowed(current, cpus_allowed);
return 0; return 0;
} }
...@@ -191,6 +198,7 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy) ...@@ -191,6 +198,7 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
static struct cpufreq_driver integrator_driver = { static struct cpufreq_driver integrator_driver = {
.verify = integrator_verify_policy, .verify = integrator_verify_policy,
.target = integrator_set_target, .target = integrator_set_target,
.get = integrator_get,
.init = integrator_cpufreq_init, .init = integrator_cpufreq_init,
.name = "integrator", .name = "integrator",
}; };
......
...@@ -180,7 +180,7 @@ static int sa1100_target(struct cpufreq_policy *policy, ...@@ -180,7 +180,7 @@ static int sa1100_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
unsigned int cur = sa11x0_getspeed(); unsigned int cur = sa11x0_getspeed(0);
unsigned int new_ppcr; unsigned int new_ppcr;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
...@@ -221,7 +221,7 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy) ...@@ -221,7 +221,7 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
{ {
if (policy->cpu != 0) if (policy->cpu != 0)
return -EINVAL; return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed(); policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 59000; policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000; policy->cpuinfo.max_freq = 287000;
...@@ -230,15 +230,17 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy) ...@@ -230,15 +230,17 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
} }
static struct cpufreq_driver sa1100_driver = { static struct cpufreq_driver sa1100_driver = {
.flags = (CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC),
.verify = sa11x0_verify_speed, .verify = sa11x0_verify_speed,
.target = sa1100_target, .target = sa1100_target,
.get = sa11x0_getspeed,
.init = sa1100_cpu_init, .init = sa1100_cpu_init,
.name = "sa1100", .name = "sa1100",
}; };
static int __init sa1100_dram_init(void) static int __init sa1100_dram_init(void)
{ {
cpufreq_gov_userspace_init();
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
return cpufreq_register_driver(&sa1100_driver); return cpufreq_register_driver(&sa1100_driver);
else else
......
...@@ -238,7 +238,7 @@ static int sa1110_target(struct cpufreq_policy *policy, ...@@ -238,7 +238,7 @@ static int sa1110_target(struct cpufreq_policy *policy,
return -EINVAL; return -EINVAL;
} }
freqs.old = sa11x0_getspeed(); freqs.old = sa11x0_getspeed(0);
freqs.new = sa11x0_ppcr_to_freq(ppcr); freqs.new = sa11x0_ppcr_to_freq(ppcr);
freqs.cpu = 0; freqs.cpu = 0;
...@@ -320,7 +320,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) ...@@ -320,7 +320,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
{ {
if (policy->cpu != 0) if (policy->cpu != 0)
return -EINVAL; return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed(); policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 59000; policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000; policy->cpuinfo.max_freq = 287000;
...@@ -329,8 +329,11 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy) ...@@ -329,8 +329,11 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
} }
static struct cpufreq_driver sa1110_driver = { static struct cpufreq_driver sa1110_driver = {
.flags = (CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC),
.verify = sa11x0_verify_speed, .verify = sa11x0_verify_speed,
.target = sa1110_target, .target = sa1110_target,
.get = sa11x0_getspeed,
.init = sa1110_cpu_init, .init = sa1110_cpu_init,
.name = "sa1110", .name = "sa1110",
}; };
...@@ -354,8 +357,6 @@ static int __init sa1110_clk_init(void) ...@@ -354,8 +357,6 @@ static int __init sa1110_clk_init(void)
sdram->tck, sdram->trcd, sdram->trp, sdram->tck, sdram->trcd, sdram->trp,
sdram->twr, sdram->refresh, sdram->cas_latency); sdram->twr, sdram->refresh, sdram->cas_latency);
cpufreq_gov_userspace_init();
memcpy(&sdram_params, sdram, sizeof(sdram_params)); memcpy(&sdram_params, sdram, sizeof(sdram_params));
return cpufreq_register_driver(&sa1110_driver); return cpufreq_register_driver(&sa1110_driver);
......
...@@ -96,11 +96,13 @@ int sa11x0_verify_speed(struct cpufreq_policy *policy) ...@@ -96,11 +96,13 @@ int sa11x0_verify_speed(struct cpufreq_policy *policy)
return 0; return 0;
} }
unsigned int sa11x0_getspeed(void) unsigned int sa11x0_getspeed(unsigned int cpu)
{ {
if (cpu)
return 0;
return cclk_frequency_100khz[PPCR & 0xf] * 100; return cclk_frequency_100khz[PPCR & 0xf] * 100;
} }
EXPORT_SYMBOL(sa11x0_getspeed);
#else #else
/* /*
* We still need to provide this so building without cpufreq works. * We still need to provide this so building without cpufreq works.
......
...@@ -22,5 +22,5 @@ struct cpufreq_policy; ...@@ -22,5 +22,5 @@ struct cpufreq_policy;
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern int sa11x0_verify_speed(struct cpufreq_policy *policy); extern int sa11x0_verify_speed(struct cpufreq_policy *policy);
extern unsigned int sa11x0_getspeed(void); extern unsigned int sa11x0_getspeed(unsigned int cpu);
extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx); extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx);
...@@ -2,15 +2,15 @@ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o ...@@ -2,15 +2,15 @@ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
obj-$(CONFIG_X86_LONGRUN) += longrun.o obj-$(CONFIG_X86_LONGRUN) += longrun.o
obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o
obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
ifdef CONFIG_X86_ACPI_CPUFREQ ifdef CONFIG_X86_ACPI_CPUFREQ
ifdef CONFIG_ACPI_DEBUG ifdef CONFIG_ACPI_DEBUG
......
...@@ -77,7 +77,7 @@ static struct cpufreq_frequency_table elanfreq_table[] = { ...@@ -77,7 +77,7 @@ static struct cpufreq_frequency_table elanfreq_table[] = {
* and have the rest of the chip running with 33 MHz. * and have the rest of the chip running with 33 MHz.
*/ */
static unsigned int elanfreq_get_cpu_frequency(void) static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
{ {
u8 clockspeed_reg; /* Clock Speed Register */ u8 clockspeed_reg; /* Clock Speed Register */
...@@ -121,7 +121,7 @@ static void elanfreq_set_cpu_state (unsigned int state) { ...@@ -121,7 +121,7 @@ static void elanfreq_set_cpu_state (unsigned int state) {
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
freqs.old = elanfreq_get_cpu_frequency(); freqs.old = elanfreq_get_cpu_frequency(0);
freqs.new = elan_multiplier[state].clock; freqs.new = elan_multiplier[state].clock;
freqs.cpu = 0; /* elanfreq.c is UP only driver */ freqs.cpu = 0; /* elanfreq.c is UP only driver */
...@@ -209,7 +209,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) ...@@ -209,7 +209,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
/* max freq */ /* max freq */
if (!max_freq) if (!max_freq)
max_freq = elanfreq_get_cpu_frequency(); max_freq = elanfreq_get_cpu_frequency(0);
/* table init */ /* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) { for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
...@@ -220,7 +220,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy) ...@@ -220,7 +220,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = elanfreq_get_cpu_frequency(); policy->cur = elanfreq_get_cpu_frequency(0);
result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table); result = cpufreq_frequency_table_cpuinfo(policy, elanfreq_table);
if (result) if (result)
...@@ -267,6 +267,7 @@ static struct freq_attr* elanfreq_attr[] = { ...@@ -267,6 +267,7 @@ static struct freq_attr* elanfreq_attr[] = {
static struct cpufreq_driver elanfreq_driver = { static struct cpufreq_driver elanfreq_driver = {
.get = elanfreq_get_cpu_frequency,
.verify = elanfreq_verify, .verify = elanfreq_verify,
.target = elanfreq_target, .target = elanfreq_target,
.init = elanfreq_cpu_init, .init = elanfreq_cpu_init,
......
...@@ -215,7 +215,7 @@ static __init struct pci_dev *gx_detect_chipset(void) ...@@ -215,7 +215,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
* *
* 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 int gx_get_cpuspeed(void) static unsigned int gx_get_cpuspeed(unsigned int cpu)
{ {
if ((gx_params->pci_suscfg & SUSMOD) == 0) if ((gx_params->pci_suscfg & SUSMOD) == 0)
return stock_freq; return stock_freq;
...@@ -271,7 +271,7 @@ static void gx_set_cpuspeed(unsigned int khz) ...@@ -271,7 +271,7 @@ static void gx_set_cpuspeed(unsigned int khz)
freqs.cpu = 0; freqs.cpu = 0;
freqs.old = gx_get_cpuspeed(); 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);
...@@ -405,7 +405,7 @@ static int cpufreq_gx_target(struct cpufreq_policy *policy, ...@@ -405,7 +405,7 @@ static int cpufreq_gx_target(struct cpufreq_policy *policy,
static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
{ {
int maxfreq, curfreq; unsigned int maxfreq, curfreq;
if (!policy || policy->cpu != 0) if (!policy || policy->cpu != 0)
return -ENODEV; return -ENODEV;
...@@ -419,7 +419,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) ...@@ -419,7 +419,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
} }
stock_freq = maxfreq; stock_freq = maxfreq;
curfreq = gx_get_cpuspeed(); curfreq = gx_get_cpuspeed(0);
dprintk("cpu max frequency is %d.\n", maxfreq); dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq); dprintk("cpu current frequency is %dkHz.\n",curfreq);
...@@ -446,6 +446,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) ...@@ -446,6 +446,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
* MediaGX/Geode GX initialize cpufreq driver * MediaGX/Geode GX initialize cpufreq driver
*/ */
static struct cpufreq_driver gx_suspmod_driver = { static struct cpufreq_driver gx_suspmod_driver = {
.get = gx_get_cpuspeed,
.verify = cpufreq_gx_verify, .verify = cpufreq_gx_verify,
.target = cpufreq_gx_target, .target = cpufreq_gx_target,
.init = cpufreq_gx_cpu_init, .init = cpufreq_gx_cpu_init,
......
...@@ -82,6 +82,10 @@ static int longhaul_get_cpu_mult (void) ...@@ -82,6 +82,10 @@ static int longhaul_get_cpu_mult (void)
if (lo & (1<<27)) if (lo & (1<<27))
invalue+=16; invalue+=16;
} }
if (longhaul_version==4) {
if (lo & (1<<27))
invalue+=16;
}
return eblcr_table[invalue]; return eblcr_table[invalue];
} }
...@@ -158,6 +162,22 @@ static void longhaul_setstate (unsigned int clock_ratio_index) ...@@ -158,6 +162,22 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
longhaul.bits.RevisionKey = 3; longhaul.bits.RevisionKey = 3;
wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
break; break;
case 4:
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);
break;
} }
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
...@@ -207,7 +227,7 @@ static int guess_fsb(int maxmult) ...@@ -207,7 +227,7 @@ static int guess_fsb(int maxmult)
static int __init longhaul_get_ranges (void) static int __init longhaul_get_ranges (void)
{ {
struct cpuinfo_x86 *c = cpu_data; struct cpuinfo_x86 *c = cpu_data;
unsigned long invalue; unsigned long invalue,invalue2;
unsigned int minmult=0, maxmult=0; unsigned int minmult=0, maxmult=0;
unsigned int multipliers[32]= { unsigned int multipliers[32]= {
50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
...@@ -234,8 +254,6 @@ static int __init longhaul_get_ranges (void) ...@@ -234,8 +254,6 @@ static int __init longhaul_get_ranges (void)
case 2: case 2:
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
//TODO: Nehemiah may have borken MaxMHzBR.
// need to extrapolate from FSB.
invalue = longhaul.bits.MaxMHzBR; invalue = longhaul.bits.MaxMHzBR;
if (longhaul.bits.MaxMHzBR4) if (longhaul.bits.MaxMHzBR4)
invalue += 16; invalue += 16;
...@@ -258,6 +276,38 @@ static int __init longhaul_get_ranges (void) ...@@ -258,6 +276,38 @@ static int __init longhaul_get_ranges (void)
break; break;
} }
break; break;
case 4:
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
//TODO: Nehemiah may have borken MaxMHzBR.
// need to extrapolate from FSB.
invalue2 = longhaul.bits.MinMHzBR;
invalue = longhaul.bits.MaxMHzBR;
if (longhaul.bits.MaxMHzBR4)
invalue += 16;
maxmult=multipliers[invalue];
maxmult=longhaul_get_cpu_mult();
printk(KERN_INFO PFX " invalue: %ld maxmult: %d \n", invalue, maxmult);
printk(KERN_INFO PFX " invalue2: %ld \n", invalue2);
minmult=50;
switch (longhaul.bits.MaxMHzFSB) {
case 0x0: fsb=133;
break;
case 0x1: fsb=100;
break;
case 0x2: printk (KERN_INFO PFX "Invalid (reserved) FSB!\n");
return -EINVAL;
case 0x3: fsb=66;
break;
}
break;
} }
dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n", dprintk (KERN_INFO PFX "MinMult=%d.%dx MaxMult=%d.%dx\n",
...@@ -380,6 +430,13 @@ static int longhaul_target (struct cpufreq_policy *policy, ...@@ -380,6 +430,13 @@ static int longhaul_target (struct cpufreq_policy *policy,
return 0; return 0;
} }
static unsigned int longhaul_get(unsigned int cpu)
{
if (cpu)
return 0;
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; struct cpuinfo_x86 *c = cpu_data;
...@@ -423,12 +480,27 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy) ...@@ -423,12 +480,27 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy)
break; break;
case 9: case 9:
cpuname = "C3 'Nehemiah' [C5N]"; longhaul_version=4;
longhaul_version=2;
numscales=32; numscales=32;
memcpy (clock_ratio, nehemiah_clock_ratio, sizeof(nehemiah_clock_ratio)); switch (c->x86_mask) {
memcpy (eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr)); case 0 ... 1:
cpuname = "C3 'Nehemiah A' [C5N]";
memcpy (clock_ratio, nehemiah_a_clock_ratio, sizeof(nehemiah_a_clock_ratio));
memcpy (eblcr_table, nehemiah_a_eblcr, sizeof(nehemiah_a_eblcr));
break;
case 2 ... 4:
cpuname = "C3 'Nehemiah B' [C5N]";
memcpy (clock_ratio, nehemiah_b_clock_ratio, sizeof(nehemiah_b_clock_ratio));
memcpy (eblcr_table, nehemiah_b_eblcr, sizeof(nehemiah_b_eblcr));
break;
case 5 ... 15:
cpuname = "C3 'Nehemiah C' [C5N]";
memcpy (clock_ratio, nehemiah_c_clock_ratio, sizeof(nehemiah_c_clock_ratio));
memcpy (eblcr_table, nehemiah_c_eblcr, sizeof(nehemiah_c_eblcr));
break;
}
break; break;
default: default:
cpuname = "Unknown"; cpuname = "Unknown";
...@@ -472,6 +544,7 @@ static struct freq_attr* longhaul_attr[] = { ...@@ -472,6 +544,7 @@ static struct freq_attr* longhaul_attr[] = {
static struct cpufreq_driver longhaul_driver = { static struct cpufreq_driver longhaul_driver = {
.verify = longhaul_verify, .verify = longhaul_verify,
.target = longhaul_target, .target = longhaul_target,
.get = longhaul_get,
.init = longhaul_cpu_init, .init = longhaul_cpu_init,
.exit = longhaul_cpu_exit, .exit = longhaul_cpu_exit,
.name = "longhaul", .name = "longhaul",
......
...@@ -234,14 +234,15 @@ static int __initdata ezrat_eblcr[32] = { ...@@ -234,14 +234,15 @@ static int __initdata ezrat_eblcr[32] = {
/* /*
* VIA C3 Nehemiah */ * VIA C3 Nehemiah */
static int __initdata nehemiah_clock_ratio[32] = {
static int __initdata nehemiah_a_clock_ratio[32] = {
100, /* 0000 -> 10.0x */ 100, /* 0000 -> 10.0x */
160, /* 0001 -> 16.0x */ 160, /* 0001 -> 16.0x */
-1, /* 0010 -> RESERVED */ -1, /* 0010 -> RESERVED */
90, /* 0011 -> 9.0x */ 90, /* 0011 -> 9.0x */
95, /* 0100 -> 9.5x */ 95, /* 0100 -> 9.5x */
-1, /* 0101 -> RESERVED */ -1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */ -1, /* 0110 -> RESERVED */
55, /* 0111 -> 5.5x */ 55, /* 0111 -> 5.5x */
60, /* 1000 -> 6.0x */ 60, /* 1000 -> 6.0x */
70, /* 1001 -> 7.0x */ 70, /* 1001 -> 7.0x */
...@@ -250,8 +251,42 @@ static int __initdata nehemiah_clock_ratio[32] = { ...@@ -250,8 +251,42 @@ static int __initdata nehemiah_clock_ratio[32] = {
65, /* 1100 -> 6.5x */ 65, /* 1100 -> 6.5x */
75, /* 1101 -> 7.5x */ 75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */ 85, /* 1110 -> 8.5x */
120, /* 1111 -> 12.0x */ 120, /* 1111 -> 12.0x */
100, /* 0000 -> 10.0x */
-1, /* 0001 -> RESERVED */
120, /* 0010 -> 12.0x */
90, /* 0011 -> 9.0x */
105, /* 0100 -> 10.5x */
115, /* 0101 -> 11.5x */
125, /* 0110 -> 12.5x */
135, /* 0111 -> 13.5x */
140, /* 1000 -> 14.0x */
150, /* 1001 -> 15.0x */
160, /* 1010 -> 16.0x */
130, /* 1011 -> 13.0x */
145, /* 1100 -> 14.5x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED (13.0x) */
120, /* 1111 -> 12.0x */
};
static int __initdata nehemiah_b_clock_ratio[32] = {
100, /* 0000 -> 10.0x */
160, /* 0001 -> 16.0x */
-1, /* 0010 -> RESERVED */
90, /* 0011 -> 9.0x */
95, /* 0100 -> 9.5x */
-1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */
55, /* 0111 -> 5.5x */
60, /* 1000 -> 6.0x */
70, /* 1001 -> 7.0x */
80, /* 1010 -> 8.0x */
50, /* 1011 -> 5.0x */
65, /* 1100 -> 6.5x */
75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */
120, /* 1111 -> 12.0x */
100, /* 0000 -> 10.0x */ 100, /* 0000 -> 10.0x */
110, /* 0001 -> 11.0x */ 110, /* 0001 -> 11.0x */
120, /* 0010 -> 12.0x */ 120, /* 0010 -> 12.0x */
...@@ -266,18 +301,88 @@ static int __initdata nehemiah_clock_ratio[32] = { ...@@ -266,18 +301,88 @@ static int __initdata nehemiah_clock_ratio[32] = {
130, /* 1011 -> 13.0x */ 130, /* 1011 -> 13.0x */
145, /* 1100 -> 14.5x */ 145, /* 1100 -> 14.5x */
155, /* 1101 -> 15.5x */ 155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED */ -1, /* 1110 -> RESERVED (13.0x) */
120, /* 1111 -> 12.0x */ 120, /* 1111 -> 12.0x */
}; };
static int __initdata nehemiah_eblcr[32] = { static int __initdata nehemiah_c_clock_ratio[32] = {
100, /* 0000 -> 10.0x */
160, /* 0001 -> 16.0x */
40, /* 0010 -> RESERVED */
90, /* 0011 -> 9.0x */
95, /* 0100 -> 9.5x */
-1, /* 0101 -> RESERVED */
45, /* 0110 -> RESERVED */
55, /* 0111 -> 5.5x */
60, /* 1000 -> 6.0x */
70, /* 1001 -> 7.0x */
80, /* 1010 -> 8.0x */
50, /* 1011 -> 5.0x */
65, /* 1100 -> 6.5x */
75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */
120, /* 1111 -> 12.0x */
100, /* 0000 -> 10.0x */
110, /* 0001 -> 11.0x */
120, /* 0010 -> 12.0x */
90, /* 0011 -> 9.0x */
105, /* 0100 -> 10.5x */
115, /* 0101 -> 11.5x */
125, /* 0110 -> 12.5x */
135, /* 0111 -> 13.5x */
140, /* 1000 -> 14.0x */
150, /* 1001 -> 15.0x */
160, /* 1010 -> 16.0x */
130, /* 1011 -> 13.0x */
145, /* 1100 -> 14.5x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED (13.0x) */
120, /* 1111 -> 12.0x */
};
static int __initdata nehemiah_a_eblcr[32] = {
50, /* 0000 -> 5.0x */ 50, /* 0000 -> 5.0x */
160, /* 0001 -> 16.0x */ 160, /* 0001 -> 16.0x */
-1, /* 0010 -> RESERVED */ -1, /* 0010 -> RESERVED */
100, /* 0011 -> 10.0x */ 100, /* 0011 -> 10.0x */
55, /* 0100 -> 5.5x */ 55, /* 0100 -> 5.5x */
-1, /* 0101 -> RESERVED */ -1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */ -1, /* 0110 -> RESERVED */
95, /* 0111 -> 9.5x */
90, /* 1000 -> 9.0x */
70, /* 1001 -> 7.0x */
80, /* 1010 -> 8.0x */
60, /* 1011 -> 6.0x */
120, /* 1100 -> 12.0x */
75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */
65, /* 1111 -> 6.5x */
90, /* 0000 -> 9.0x */
-1, /* 0001 -> RESERVED */
120, /* 0010 -> 12.0x */
100, /* 0011 -> 10.0x */
135, /* 0100 -> 13.5x */
115, /* 0101 -> 11.5x */
125, /* 0110 -> 12.5x */
105, /* 0111 -> 10.5x */
130, /* 1000 -> 13.0x */
150, /* 1001 -> 15.0x */
160, /* 1010 -> 16.0x */
140, /* 1011 -> 14.0x */
120, /* 1100 -> 12.0x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED (13.0x) */
145 /* 1111 -> 14.5x */
/* end of table */
};
static int __initdata nehemiah_b_eblcr[32] = {
50, /* 0000 -> 5.0x */
160, /* 0001 -> 16.0x */
-1, /* 0010 -> RESERVED */
100, /* 0011 -> 10.0x */
55, /* 0100 -> 5.5x */
-1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */
95, /* 0111 -> 9.5x */ 95, /* 0111 -> 9.5x */
90, /* 1000 -> 9.0x */ 90, /* 1000 -> 9.0x */
70, /* 1001 -> 7.0x */ 70, /* 1001 -> 7.0x */
...@@ -287,7 +392,6 @@ static int __initdata nehemiah_eblcr[32] = { ...@@ -287,7 +392,6 @@ static int __initdata nehemiah_eblcr[32] = {
75, /* 1101 -> 7.5x */ 75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */ 85, /* 1110 -> 8.5x */
65, /* 1111 -> 6.5x */ 65, /* 1111 -> 6.5x */
90, /* 0000 -> 9.0x */ 90, /* 0000 -> 9.0x */
110, /* 0001 -> 11.0x */ 110, /* 0001 -> 11.0x */
120, /* 0010 -> 12.0x */ 120, /* 0010 -> 12.0x */
...@@ -302,9 +406,46 @@ static int __initdata nehemiah_eblcr[32] = { ...@@ -302,9 +406,46 @@ static int __initdata nehemiah_eblcr[32] = {
140, /* 1011 -> 14.0x */ 140, /* 1011 -> 14.0x */
120, /* 1100 -> 12.0x */ 120, /* 1100 -> 12.0x */
155, /* 1101 -> 15.5x */ 155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED */ -1, /* 1110 -> RESERVED (13.0x) */
-1, /* 1111 -> RESERVED */ 145 /* 1111 -> 14.5x */
/* end of table */
}; };
static int __initdata nehemiah_c_eblcr[32] = {
50, /* 0000 -> 5.0x */
160, /* 0001 -> 16.0x */
40, /* 0010 -> RESERVED */
100, /* 0011 -> 10.0x */
55, /* 0100 -> 5.5x */
-1, /* 0101 -> RESERVED */
45, /* 0110 -> RESERVED */
95, /* 0111 -> 9.5x */
90, /* 1000 -> 9.0x */
70, /* 1001 -> 7.0x */
80, /* 1010 -> 8.0x */
60, /* 1011 -> 6.0x */
120, /* 1100 -> 12.0x */
75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */
65, /* 1111 -> 6.5x */
90, /* 0000 -> 9.0x */
110, /* 0001 -> 11.0x */
120, /* 0010 -> 12.0x */
100, /* 0011 -> 10.0x */
135, /* 0100 -> 13.5x */
115, /* 0101 -> 11.5x */
125, /* 0110 -> 12.5x */
105, /* 0111 -> 10.5x */
130, /* 1000 -> 13.0x */
150, /* 1001 -> 15.0x */
160, /* 1010 -> 16.0x */
140, /* 1011 -> 14.0x */
120, /* 1100 -> 12.0x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED (13.0x) */
145 /* 1111 -> 14.5x */
/* end of table */
};
/* /*
* Voltage scales. Div/Mod by 1000 to get actual voltage. * Voltage scales. Div/Mod by 1000 to get actual voltage.
* Which scale to use depends on the VRM type in use. * Which scale to use depends on the VRM type in use.
......
...@@ -46,11 +46,16 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy) ...@@ -46,11 +46,16 @@ static void __init longrun_get_policy(struct cpufreq_policy *policy)
rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
msr_lo &= 0x0000007F; msr_lo &= 0x0000007F;
msr_hi &= 0x0000007F; msr_hi &= 0x0000007F;
policy->min = longrun_low_freq + msr_lo * if ( longrun_high_freq <= longrun_low_freq ) {
((longrun_high_freq - longrun_low_freq) / 100); /* Assume degenerate Longrun table */
policy->max = longrun_low_freq + msr_hi * policy->min = policy->max = longrun_high_freq;
((longrun_high_freq - longrun_low_freq) / 100); } else {
policy->min = longrun_low_freq + msr_lo *
((longrun_high_freq - longrun_low_freq) / 100);
policy->max = longrun_low_freq + msr_hi *
((longrun_high_freq - longrun_low_freq) / 100);
}
policy->cpu = 0; policy->cpu = 0;
} }
...@@ -70,10 +75,15 @@ static int longrun_set_policy(struct cpufreq_policy *policy) ...@@ -70,10 +75,15 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
if (!policy) if (!policy)
return -EINVAL; return -EINVAL;
pctg_lo = (policy->min - longrun_low_freq) / if ( longrun_high_freq <= longrun_low_freq ) {
((longrun_high_freq - longrun_low_freq) / 100); /* Assume degenerate Longrun table */
pctg_hi = (policy->max - longrun_low_freq) / pctg_lo = pctg_hi = 100;
((longrun_high_freq - longrun_low_freq) / 100); } else {
pctg_lo = (policy->min - longrun_low_freq) /
((longrun_high_freq - longrun_low_freq) / 100);
pctg_hi = (policy->max - longrun_low_freq) /
((longrun_high_freq - longrun_low_freq) / 100);
}
if (pctg_hi > 100) if (pctg_hi > 100)
pctg_hi = 100; pctg_hi = 100;
...@@ -128,6 +138,17 @@ static int longrun_verify_policy(struct cpufreq_policy *policy) ...@@ -128,6 +138,17 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
return 0; return 0;
} }
static unsigned int longrun_get(unsigned int cpu)
{
u32 eax, ebx, ecx, edx;
if (cpu)
return 0;
cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
return (eax * 1000);
}
/** /**
* longrun_determine_freqs - determines the lowest and highest possible core frequency * longrun_determine_freqs - determines the lowest and highest possible core frequency
...@@ -250,8 +271,10 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy) ...@@ -250,8 +271,10 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy)
static struct cpufreq_driver longrun_driver = { static struct cpufreq_driver longrun_driver = {
.flags = CPUFREQ_CONST_LOOPS,
.verify = longrun_verify_policy, .verify = longrun_verify_policy,
.setpolicy = longrun_set_policy, .setpolicy = longrun_set_policy,
.get = longrun_get,
.init = longrun_cpu_init, .init = longrun_cpu_init,
.name = "longrun", .name = "longrun",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -51,55 +51,16 @@ enum { ...@@ -51,55 +51,16 @@ enum {
static int has_N44_O17_errata[NR_CPUS]; static int has_N44_O17_errata[NR_CPUS];
static unsigned int stock_freq; static unsigned int stock_freq;
static struct cpufreq_driver p4clockmod_driver;
static unsigned int cpufreq_p4_get(unsigned int cpu);
static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
{ {
u32 l, h; u32 l, h;
cpumask_t cpus_allowed, affected_cpu_map;
struct cpufreq_freqs freqs;
int j;
if (!cpu_online(cpu) || (newstate > DC_DISABLE) || if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV))
(newstate == DC_RESV))
return -EINVAL; return -EINVAL;
/* switch to physical CPU where state is to be changed*/
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[cpu];
#else
affected_cpu_map = cpumask_of_cpu(cpu);
#endif
set_cpus_allowed(current, affected_cpu_map);
BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map));
/* get current state */
rdmsr(MSR_IA32_THERM_CONTROL, l, h);
if (l & 0x10) {
l = l >> 1;
l &= 0x7;
} else
l = DC_DISABLE;
if (l == newstate) {
set_cpus_allowed(current, cpus_allowed);
return 0;
} else if (l == DC_RESV) {
printk(KERN_ERR PFX "BIG FAT WARNING: currently in invalid setting\n");
}
/* notifiers */
freqs.old = stock_freq * l / 8;
freqs.new = stock_freq * newstate / 8;
for_each_cpu(j) {
if (cpu_isset(j, affected_cpu_map)) {
freqs.cpu = j;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
}
rdmsr(MSR_IA32_THERM_STATUS, l, h); rdmsr(MSR_IA32_THERM_STATUS, l, h);
#if 0 #if 0
if (l & 0x01) if (l & 0x01)
...@@ -125,16 +86,6 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) ...@@ -125,16 +86,6 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
wrmsr(MSR_IA32_THERM_CONTROL, l, h); wrmsr(MSR_IA32_THERM_CONTROL, l, h);
} }
set_cpus_allowed(current, cpus_allowed);
/* notifiers */
for_each_cpu(j) {
if (cpu_isset(j, affected_cpu_map)) {
freqs.cpu = j;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
}
return 0; return 0;
} }
...@@ -158,11 +109,59 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, ...@@ -158,11 +109,59 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
unsigned int relation) unsigned int relation)
{ {
unsigned int newstate = DC_RESV; unsigned int newstate = DC_RESV;
struct cpufreq_freqs freqs;
cpumask_t cpus_allowed, affected_cpu_map;
int i;
if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate))
return -EINVAL; return -EINVAL;
cpufreq_p4_setdc(policy->cpu, p4clockmod_table[newstate].index); freqs.old = cpufreq_p4_get(policy->cpu);
freqs.new = stock_freq * p4clockmod_table[newstate].index / 8;
if (freqs.new == freqs.old)
return 0;
/* switch to physical CPU where state is to be changed*/
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
/* notifiers */
for_each_cpu(i) {
if (cpu_isset(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);
set_cpus_allowed(current, this_cpu);
BUG_ON(smp_processor_id() != i);
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);
}
}
return 0; return 0;
} }
...@@ -177,11 +176,23 @@ static int cpufreq_p4_verify(struct cpufreq_policy *policy) ...@@ -177,11 +176,23 @@ static int cpufreq_p4_verify(struct cpufreq_policy *policy)
static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{ {
if ((c->x86 == 0x06) && (c->x86_model == 0x09)) { if ((c->x86 == 0x06) && (c->x86_model == 0x09)) {
/* Pentium M */ /* Pentium M (Banias) */
printk(KERN_WARNING PFX "Warning: Pentium M detected. "
"The speedstep_centrino module offers voltage scaling"
" in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n");
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
}
if ((c->x86 == 0x06) && (c->x86_model == 0x13)) {
/* Pentium M (Dothan) */
printk(KERN_WARNING PFX "Warning: Pentium M detected. " printk(KERN_WARNING PFX "Warning: Pentium M detected. "
"The speedstep_centrino module offers voltage scaling" "The speedstep_centrino module offers voltage scaling"
" in addition of frequency scaling. You should use " " in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n"); "that instead of p4-clockmod, if possible.\n");
/* on P-4s, the TSC runs with constant frequency independent wether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM); return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
} }
...@@ -190,6 +201,10 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) ...@@ -190,6 +201,10 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
return 0; return 0;
} }
/* on P-4s, the TSC runs with constant frequency independent wether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) { if (speedstep_detect_processor() == SPEEDSTEP_PROCESSOR_P4M) {
printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. " printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
"The speedstep-ich or acpi cpufreq modules offer " "The speedstep-ich or acpi cpufreq modules offer "
...@@ -249,6 +264,33 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) ...@@ -249,6 +264,33 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static unsigned int cpufreq_p4_get(unsigned int cpu)
{
cpumask_t cpus_allowed, affected_cpu_map;
u32 l, h;
cpus_allowed = current->cpus_allowed;
affected_cpu_map = cpumask_of_cpu(cpu);
set_cpus_allowed(current, affected_cpu_map);
BUG_ON(!cpu_isset(smp_processor_id(), affected_cpu_map));
rdmsr(MSR_IA32_THERM_CONTROL, l, h);
set_cpus_allowed(current, cpus_allowed);
if (l & 0x10) {
l = l >> 1;
l &= 0x7;
} else
l = DC_DISABLE;
if (l != DC_DISABLE)
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, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
...@@ -259,6 +301,7 @@ static struct cpufreq_driver p4clockmod_driver = { ...@@ -259,6 +301,7 @@ static struct cpufreq_driver p4clockmod_driver = {
.target = cpufreq_p4_target, .target = cpufreq_p4_target,
.init = cpufreq_p4_cpu_init, .init = cpufreq_p4_cpu_init,
.exit = cpufreq_p4_cpu_exit, .exit = cpufreq_p4_cpu_exit,
.get = cpufreq_p4_get,
.name = "p4-clockmod", .name = "p4-clockmod",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.attr = p4clockmod_attr, .attr = p4clockmod_attr,
......
...@@ -185,6 +185,11 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy) ...@@ -185,6 +185,11 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static unsigned int powernow_k6_get(unsigned int cpu)
{
return busfreq * powernow_k6_get_cpu_multiplier();
}
static struct freq_attr* powernow_k6_attr[] = { static struct freq_attr* powernow_k6_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
...@@ -195,6 +200,7 @@ static struct cpufreq_driver powernow_k6_driver = { ...@@ -195,6 +200,7 @@ static struct cpufreq_driver powernow_k6_driver = {
.target = powernow_k6_target, .target = powernow_k6_target,
.init = powernow_k6_cpu_init, .init = powernow_k6_cpu_init,
.exit = powernow_k6_cpu_exit, .exit = powernow_k6_cpu_exit,
.get = powernow_k6_get,
.name = "powernow-k6", .name = "powernow-k6",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.attr = powernow_k6_attr, .attr = powernow_k6_attr,
......
...@@ -540,6 +540,20 @@ static int __init fixup_sgtc(void) ...@@ -540,6 +540,20 @@ static int __init fixup_sgtc(void)
return sgtc; return sgtc;
} }
static unsigned int powernow_get(unsigned int cpu)
{
union msr_fidvidstatus fidvidstatus;
unsigned int cfid;
if (cpu)
return 0;
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
cfid = fidvidstatus.bits.CFID;
return (fsb * fid_codes[cfid] / 10);
}
static int __init powernow_cpu_init (struct cpufreq_policy *policy) static int __init powernow_cpu_init (struct cpufreq_policy *policy)
{ {
union msr_fidvidstatus fidvidstatus; union msr_fidvidstatus fidvidstatus;
...@@ -590,7 +604,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -590,7 +604,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
policy->cpuinfo.transition_latency = 20 * latency / fsb; policy->cpuinfo.transition_latency = 20 * latency / fsb;
policy->cur = maximum_speed; policy->cur = powernow_get(0);
cpufreq_frequency_table_get_attr(powernow_table, policy->cpu); cpufreq_frequency_table_get_attr(powernow_table, policy->cpu);
...@@ -610,6 +624,7 @@ static struct freq_attr* powernow_table_attr[] = { ...@@ -610,6 +624,7 @@ static struct freq_attr* powernow_table_attr[] = {
static struct cpufreq_driver powernow_driver = { static struct cpufreq_driver powernow_driver = {
.verify = powernow_verify, .verify = powernow_verify,
.target = powernow_target, .target = powernow_target,
.get = powernow_get,
.init = powernow_cpu_init, .init = powernow_cpu_init,
.exit = powernow_cpu_exit, .exit = powernow_cpu_exit,
.name = "powernow-k7", .name = "powernow-k7",
......
...@@ -32,14 +32,14 @@ ...@@ -32,14 +32,14 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/delay.h> #include <asm/delay.h>
#ifdef CONFIG_ACPI_PROCESSOR #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#include <linux/acpi.h> #include <linux/acpi.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#endif #endif
#define PFX "powernow-k8: " #define PFX "powernow-k8: "
#define BFX PFX "BIOS error: " #define BFX PFX "BIOS error: "
#define VERSION "version 1.00.08b" #define VERSION "version 1.00.09b"
#include "powernow-k8.h" #include "powernow-k8.h"
/* serialize freq changes */ /* serialize freq changes */
...@@ -450,13 +450,10 @@ static int check_supported_cpu(unsigned int cpu) ...@@ -450,13 +450,10 @@ static int check_supported_cpu(unsigned int cpu)
goto out; goto out;
eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE); eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) { if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n"); ((eax & CPUID_XFAM) != CPUID_XFAM_K8) ||
} else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) { ((eax & CPUID_XMOD) > CPUID_XMOD_REV_E)) {
dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n"); printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
} else {
printk(KERN_INFO PFX
"AMD Athlon 64 or AMD Opteron processor required\n");
goto out; goto out;
} }
...@@ -524,11 +521,12 @@ static void print_basics(struct powernow_k8_data *data) ...@@ -524,11 +521,12 @@ static void print_basics(struct powernow_k8_data *data)
{ {
int j; int j;
for (j = 0; j < data->numps; j++) { for (j = 0; j < data->numps; j++) {
printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j, if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)
data->powernow_table[j].index & 0xff, printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
data->powernow_table[j].frequency/1000, data->powernow_table[j].index & 0xff,
data->powernow_table[j].index >> 8, data->powernow_table[j].frequency/1000,
find_millivolts_from_vid(data, data->powernow_table[j].index >> 8)); data->powernow_table[j].index >> 8,
find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
} }
if (data->batps) if (data->batps)
printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps); printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);
...@@ -666,7 +664,7 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -666,7 +664,7 @@ static int find_psb_table(struct powernow_k8_data *data)
return -ENODEV; return -ENODEV;
} }
#ifdef CONFIG_ACPI_PROCESSOR #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
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)
{ {
if (!data->acpi_data.state_count) if (!data->acpi_data.state_count)
...@@ -723,7 +721,14 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) ...@@ -723,7 +721,14 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
/* verify frequency is OK */ /* verify frequency is OK */
if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) || if ((powernow_table[i].frequency > (MAX_FREQ * 1000)) ||
(powernow_table[i].frequency < (MIN_FREQ * 1000))) { (powernow_table[i].frequency < (MIN_FREQ * 1000))) {
dprintk(KERN_INFO PFX "invalid freq %u kHz\n", powernow_table[i].frequency); dprintk(KERN_INFO PFX "invalid freq %u kHz, ignoring\n", powernow_table[i].frequency);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
continue;
}
/* verify voltage is OK - BIOSs are using "off" to indicate invalid */
if (vid == 0x1f) {
dprintk(KERN_INFO PFX "invalid vid %u, ignoring\n", vid);
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
continue; continue;
} }
...@@ -1025,6 +1030,32 @@ static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol) ...@@ -1025,6 +1030,32 @@ static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
return 0; return 0;
} }
static unsigned int powernowk8_get (unsigned int cpu)
{
struct powernow_k8_data *data = powernow_data[cpu];
cpumask_t oldmask = current->cpus_allowed;
unsigned int khz = 0;
set_cpus_allowed(current, cpumask_of_cpu(cpu));
if (smp_processor_id() != cpu) {
printk(KERN_ERR PFX "limiting to CPU %d failed in powernowk8_get\n", cpu);
set_cpus_allowed(current, oldmask);
return 0;
}
preempt_disable();
if (query_current_values_with_pending_wait(data))
goto out;
khz = find_khz_freq_from_fid(data->currfid);
out:
preempt_enable_no_resched();
set_cpus_allowed(current, oldmask);
return khz;
}
static struct freq_attr* powernow_k8_attr[] = { static struct freq_attr* powernow_k8_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
NULL, NULL,
...@@ -1035,6 +1066,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = { ...@@ -1035,6 +1066,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.target = powernowk8_target, .target = powernowk8_target,
.init = powernowk8_cpu_init, .init = powernowk8_cpu_init,
.exit = powernowk8_cpu_exit, .exit = powernowk8_cpu_exit,
.get = powernowk8_get,
.name = "powernow-k8", .name = "powernow-k8",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.attr = powernow_k8_attr, .attr = powernow_k8_attr,
......
...@@ -29,7 +29,7 @@ struct powernow_k8_data { ...@@ -29,7 +29,7 @@ struct powernow_k8_data {
* frequency is in kHz */ * frequency is in kHz */
struct cpufreq_frequency_table *powernow_table; struct cpufreq_frequency_table *powernow_table;
#ifdef CONFIG_ACPI_PROCESSOR #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
/* the acpi table needs to be kept. it's only available if ACPI was /* the acpi table needs to be kept. it's only available if ACPI was
* used to determine valid frequency/vid/fid states */ * used to determine valid frequency/vid/fid states */
struct acpi_processor_performance acpi_data; struct acpi_processor_performance acpi_data;
...@@ -38,13 +38,15 @@ struct powernow_k8_data { ...@@ -38,13 +38,15 @@ struct powernow_k8_data {
/* processor's cpuid instruction support */ /* processor's cpuid instruction support */
#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */ #define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */
#define CPUID_XFAM_MOD 0x0ff00ff0 /* extended fam, fam + model */ #define CPUID_XFAM 0x0ff00000 /* extended family */
#define ATHLON64_XFAM_MOD 0x00000f40 /* extended fam, fam + model */ #define CPUID_XFAM_K8 0
#define OPTERON_XFAM_MOD 0x00000f50 /* extended fam, fam + model */ #define CPUID_XMOD 0x000f0000 /* extended model */
#define CPUID_GET_MAX_CAPABILITIES 0x80000000 #define CPUID_XMOD_REV_E 0x00020000
#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007 #define CPUID_USE_XFAM_XMOD 0x00000f00
#define P_STATE_TRANSITION_CAPABLE 6 #define CPUID_GET_MAX_CAPABILITIES 0x80000000
#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
#define P_STATE_TRANSITION_CAPABLE 6
/* Model Specific Registers for p-state transitions. MSRs are 64-bit. For */ /* Model Specific Registers for p-state transitions. MSRs are 64-bit. For */
/* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and */ /* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and */
......
...@@ -38,13 +38,37 @@ ...@@ -38,13 +38,37 @@
#define dprintk(msg...) do { } while(0) #define dprintk(msg...) do { } while(0)
#endif #endif
struct cpu_id
{
__u8 x86; /* CPU family */
__u8 x86_vendor; /* CPU vendor */
__u8 x86_model; /* model */
__u8 x86_mask; /* stepping */
};
static const struct cpu_id cpu_id_banias = {
.x86_vendor = X86_VENDOR_INTEL,
.x86 = 6,
.x86_model = 9,
.x86_mask = 5,
};
static const struct cpu_id cpu_id_dothan_a1 = {
.x86_vendor = X86_VENDOR_INTEL,
.x86 = 6,
.x86_model = 13,
.x86_mask = 1,
};
struct cpu_model struct cpu_model
{ {
const struct cpu_id *cpu_id;
const char *model_name; const char *model_name;
unsigned max_freq; /* max clock in kHz */ unsigned max_freq; /* max clock in kHz */
struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */
}; };
static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x);
/* Operating points for current CPU */ /* Operating points for current CPU */
static struct cpu_model *centrino_model; static struct cpu_model *centrino_model;
...@@ -67,8 +91,8 @@ static struct cpu_model *centrino_model; ...@@ -67,8 +91,8 @@ static struct cpu_model *centrino_model;
* M. * M.
*/ */
/* Ultra Low Voltage Intel Pentium M processor 900MHz */ /* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */
static struct cpufreq_frequency_table op_900[] = static struct cpufreq_frequency_table banias_900[] =
{ {
OP(600, 844), OP(600, 844),
OP(800, 988), OP(800, 988),
...@@ -76,8 +100,8 @@ static struct cpufreq_frequency_table op_900[] = ...@@ -76,8 +100,8 @@ static struct cpufreq_frequency_table op_900[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Ultra Low Voltage Intel Pentium M processor 1000MHz */ /* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */
static struct cpufreq_frequency_table op_1000[] = static struct cpufreq_frequency_table banias_1000[] =
{ {
OP(600, 844), OP(600, 844),
OP(800, 972), OP(800, 972),
...@@ -86,8 +110,8 @@ static struct cpufreq_frequency_table op_1000[] = ...@@ -86,8 +110,8 @@ static struct cpufreq_frequency_table op_1000[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Low Voltage Intel Pentium M processor 1.10GHz */ /* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */
static struct cpufreq_frequency_table op_1100[] = static struct cpufreq_frequency_table banias_1100[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1020), OP( 800, 1020),
...@@ -98,8 +122,8 @@ static struct cpufreq_frequency_table op_1100[] = ...@@ -98,8 +122,8 @@ static struct cpufreq_frequency_table op_1100[] =
}; };
/* Low Voltage Intel Pentium M processor 1.20GHz */ /* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */
static struct cpufreq_frequency_table op_1200[] = static struct cpufreq_frequency_table banias_1200[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1004), OP( 800, 1004),
...@@ -110,8 +134,8 @@ static struct cpufreq_frequency_table op_1200[] = ...@@ -110,8 +134,8 @@ static struct cpufreq_frequency_table op_1200[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Intel Pentium M processor 1.30GHz */ /* Intel Pentium M processor 1.30GHz (Banias) */
static struct cpufreq_frequency_table op_1300[] = static struct cpufreq_frequency_table banias_1300[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1260), OP( 800, 1260),
...@@ -121,8 +145,8 @@ static struct cpufreq_frequency_table op_1300[] = ...@@ -121,8 +145,8 @@ static struct cpufreq_frequency_table op_1300[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Intel Pentium M processor 1.40GHz */ /* Intel Pentium M processor 1.40GHz (Banias) */
static struct cpufreq_frequency_table op_1400[] = static struct cpufreq_frequency_table banias_1400[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1180), OP( 800, 1180),
...@@ -132,8 +156,8 @@ static struct cpufreq_frequency_table op_1400[] = ...@@ -132,8 +156,8 @@ static struct cpufreq_frequency_table op_1400[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Intel Pentium M processor 1.50GHz */ /* Intel Pentium M processor 1.50GHz (Banias) */
static struct cpufreq_frequency_table op_1500[] = static struct cpufreq_frequency_table banias_1500[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1116), OP( 800, 1116),
...@@ -144,8 +168,8 @@ static struct cpufreq_frequency_table op_1500[] = ...@@ -144,8 +168,8 @@ static struct cpufreq_frequency_table op_1500[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Intel Pentium M processor 1.60GHz */ /* Intel Pentium M processor 1.60GHz (Banias) */
static struct cpufreq_frequency_table op_1600[] = static struct cpufreq_frequency_table banias_1600[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1036), OP( 800, 1036),
...@@ -156,8 +180,8 @@ static struct cpufreq_frequency_table op_1600[] = ...@@ -156,8 +180,8 @@ static struct cpufreq_frequency_table op_1600[] =
{ .frequency = CPUFREQ_TABLE_END } { .frequency = CPUFREQ_TABLE_END }
}; };
/* Intel Pentium M processor 1.70GHz */ /* Intel Pentium M processor 1.70GHz (Banias) */
static struct cpufreq_frequency_table op_1700[] = static struct cpufreq_frequency_table banias_1700[] =
{ {
OP( 600, 956), OP( 600, 956),
OP( 800, 1004), OP( 800, 1004),
...@@ -169,26 +193,31 @@ static struct cpufreq_frequency_table op_1700[] = ...@@ -169,26 +193,31 @@ static struct cpufreq_frequency_table op_1700[] =
}; };
#undef OP #undef OP
#define _CPU(max, name) \ #define _BANIAS(cpuid, max, name) \
{ "Intel(R) Pentium(R) M processor " name "MHz", (max)*1000, op_##max } { .cpu_id = cpuid, \
#define CPU(max) _CPU(max, #max) .model_name = "Intel(R) Pentium(R) M processor " name "MHz", \
.max_freq = (max)*1000, \
.op_points = banias_##max, \
}
#define BANIAS(max) _BANIAS(&cpu_id_banias, max, #max)
/* CPU models, their operating frequency range, and freq/voltage /* CPU models, their operating frequency range, and freq/voltage
operating points */ operating points */
static struct cpu_model models[] = static struct cpu_model models[] =
{ {
_CPU( 900, " 900"), _BANIAS(&cpu_id_banias, 900, " 900"),
CPU(1000), BANIAS(1000),
CPU(1100), BANIAS(1100),
CPU(1200), BANIAS(1200),
CPU(1300), BANIAS(1300),
CPU(1400), BANIAS(1400),
CPU(1500), BANIAS(1500),
CPU(1600), BANIAS(1600),
CPU(1700), BANIAS(1700),
{ 0, } { 0, }
}; };
#undef CPU #undef _BANIAS
#undef BANIAS
static int centrino_cpu_init_table(struct cpufreq_policy *policy) static int centrino_cpu_init_table(struct cpufreq_policy *policy)
{ {
...@@ -196,7 +225,8 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) ...@@ -196,7 +225,8 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
struct cpu_model *model; struct cpu_model *model;
for(model = models; model->model_name != NULL; model++) for(model = models; model->model_name != NULL; model++)
if (strcmp(cpu->x86_model_id, model->model_name) == 0) if ((strcmp(cpu->x86_model_id, model->model_name) == 0) &&
(!centrino_verify_cpu_id(cpu, model->cpu_id)))
break; break;
if (model->model_name == NULL) { if (model->model_name == NULL) {
printk(KERN_INFO PFX "no support for CPU model \"%s\": " printk(KERN_INFO PFX "no support for CPU model \"%s\": "
...@@ -217,6 +247,16 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy) ...@@ -217,6 +247,16 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; } static inline int centrino_cpu_init_table(struct cpufreq_policy *policy) { return -ENODEV; }
#endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */ #endif /* CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE */
static int centrino_verify_cpu_id(struct cpuinfo_x86 *c, const struct cpu_id *x)
{
if ((c->x86 == x->x86) &&
(c->x86_vendor == x->x86_vendor) &&
(c->x86_model == x->x86_model) &&
(c->x86_mask == x->x86_mask))
return 0;
return -ENODEV;
}
/* Extract clock in kHz from PERF_CTL value */ /* Extract clock in kHz from PERF_CTL value */
static unsigned extract_clock(unsigned msr) static unsigned extract_clock(unsigned msr)
{ {
...@@ -225,9 +265,11 @@ static unsigned extract_clock(unsigned msr) ...@@ -225,9 +265,11 @@ static unsigned extract_clock(unsigned msr)
} }
/* Return the current CPU frequency in kHz */ /* Return the current CPU frequency in kHz */
static unsigned get_cur_freq(void) static unsigned int get_cur_freq(unsigned int cpu)
{ {
unsigned l, h; unsigned l, h;
if (cpu)
return 0;
rdmsr(MSR_IA32_PERF_STATUS, l, h); rdmsr(MSR_IA32_PERF_STATUS, l, h);
return extract_clock(l); return extract_clock(l);
...@@ -322,7 +364,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) ...@@ -322,7 +364,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
goto err_kfree; goto err_kfree;
} }
cur_freq = get_cur_freq(); cur_freq = get_cur_freq(0);
for (i=0; i<p.state_count; i++) { for (i=0; i<p.state_count; i++) {
centrino_model->op_points[i].index = p.states[i].control; centrino_model->op_points[i].index = p.states[i].control;
...@@ -357,13 +399,8 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -357,13 +399,8 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
if (!cpu_has(cpu, X86_FEATURE_EST)) if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV; return -ENODEV;
/* Only Intel Pentium M stepping 5 for now - add new CPUs as if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) &&
they appear after making sure they use PERF_CTL in the same (centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) {
way. */
if (cpu->x86_vendor != X86_VENDOR_INTEL ||
cpu->x86 != 6 ||
cpu->x86_model != 9 ||
cpu->x86_mask != 5) {
printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
"send /proc/cpuinfo to " MAINTAINER "\n"); "send /proc/cpuinfo to " MAINTAINER "\n");
return -ENODEV; return -ENODEV;
...@@ -391,10 +428,10 @@ static int centrino_cpu_init(struct cpufreq_policy *policy) ...@@ -391,10 +428,10 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
} }
} }
freq = get_cur_freq(); freq = get_cur_freq(0);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 10; /* 10uS transition latency */ policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
policy->cur = freq; policy->cur = freq;
dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n", dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
...@@ -516,6 +553,7 @@ static struct cpufreq_driver centrino_driver = { ...@@ -516,6 +553,7 @@ static struct cpufreq_driver centrino_driver = {
.exit = centrino_cpu_exit, .exit = centrino_cpu_exit,
.verify = centrino_verify, .verify = centrino_verify,
.target = centrino_target, .target = centrino_target,
.get = get_cur_freq,
.attr = centrino_attr, .attr = centrino_attr,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -179,7 +179,7 @@ static int speedstep_activate (void) ...@@ -179,7 +179,7 @@ static int speedstep_activate (void)
/** /**
* speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
* *
* Detects PIIX4, ICH2-M and ICH3-M so far. The pci_dev points to * 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 * the LPC bridge / PM module which contains all power-management
* functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
* chipset, or zero on failure. * chipset, or zero on failure.
...@@ -322,6 +322,10 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy) ...@@ -322,6 +322,10 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
return 0; return 0;
} }
static unsigned int speedstep_get(unsigned int cpu)
{
return speedstep_get_processor_frequency(speedstep_processor);
}
static struct freq_attr* speedstep_attr[] = { static struct freq_attr* speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
...@@ -335,6 +339,7 @@ static struct cpufreq_driver speedstep_driver = { ...@@ -335,6 +339,7 @@ static struct cpufreq_driver speedstep_driver = {
.target = speedstep_target, .target = speedstep_target,
.init = speedstep_cpu_init, .init = speedstep_cpu_init,
.exit = speedstep_cpu_exit, .exit = speedstep_cpu_exit,
.get = speedstep_get,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.attr = speedstep_attr, .attr = speedstep_attr,
}; };
......
...@@ -36,6 +36,8 @@ static int smi_port = 0; ...@@ -36,6 +36,8 @@ static int smi_port = 0;
static int smi_cmd = 0; static int smi_cmd = 0;
static unsigned int smi_sig = 0; static unsigned int smi_sig = 0;
/* info about the processor */
static unsigned int speedstep_processor = 0;
/* /*
* There are only two frequency states for each processor. Values * There are only two frequency states for each processor. Values
...@@ -258,9 +260,10 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -258,9 +260,10 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
&speedstep_freqs[SPEEDSTEP_HIGH].frequency); &speedstep_freqs[SPEEDSTEP_HIGH].frequency);
if (result) { if (result) {
/* fall back to speedstep_lib.c dection mechanism: try both states out */ /* fall back to speedstep_lib.c dection mechanism: try both states out */
unsigned int speedstep_processor = speedstep_detect_processor();
dprintk(KERN_INFO PFX "could not detect low and high frequencies by SMI call.\n"); dprintk(KERN_INFO PFX "could not detect low and high frequencies by SMI call.\n");
if (!speedstep_processor)
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor) if (!speedstep_processor)
return -ENODEV; return -ENODEV;
...@@ -298,13 +301,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy) ...@@ -298,13 +301,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
return 0; return 0;
} }
static int speedstep_cpu_exit(struct cpufreq_policy *policy) static int speedstep_cpu_exit(struct cpufreq_policy *policy)
{ {
cpufreq_frequency_table_put_attr(policy->cpu); cpufreq_frequency_table_put_attr(policy->cpu);
return 0; return 0;
} }
static unsigned int speedstep_get(unsigned int cpu)
{
if (cpu)
return -ENODEV;
if (!speedstep_processor)
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor)
return 0;
return speedstep_get_processor_frequency(speedstep_processor);
}
static int speedstep_resume(struct cpufreq_policy *policy) static int speedstep_resume(struct cpufreq_policy *policy)
{ {
...@@ -327,6 +340,7 @@ static struct cpufreq_driver speedstep_driver = { ...@@ -327,6 +340,7 @@ static struct cpufreq_driver speedstep_driver = {
.target = speedstep_target, .target = speedstep_target,
.init = speedstep_cpu_init, .init = speedstep_cpu_init,
.exit = speedstep_cpu_exit, .exit = speedstep_cpu_exit,
.get = speedstep_get,
.resume = speedstep_resume, .resume = speedstep_resume,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.attr = speedstep_attr, .attr = speedstep_attr,
......
...@@ -27,6 +27,8 @@ static unsigned long hpet_last; ...@@ -27,6 +27,8 @@ static unsigned long hpet_last;
struct timer_opts timer_tsc; struct timer_opts timer_tsc;
#endif #endif
static inline void cpufreq_delayed_get(void);
int tsc_disable __initdata = 0; int tsc_disable __initdata = 0;
extern spinlock_t i8253_lock; extern spinlock_t i8253_lock;
...@@ -241,6 +243,9 @@ static void mark_offset_tsc(void) ...@@ -241,6 +243,9 @@ static void mark_offset_tsc(void)
clock_fallback(); clock_fallback();
} }
/* ... but give the TSC a fair chance */
if (lost_count > 25)
cpufreq_delayed_get();
} else } else
lost_count = 0; lost_count = 0;
/* update the monotonic base value */ /* update the monotonic base value */
...@@ -324,15 +329,40 @@ static void mark_offset_tsc_hpet(void) ...@@ -324,15 +329,40 @@ static void mark_offset_tsc_hpet(void)
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
#include <linux/workqueue.h>
static unsigned int cpufreq_delayed_issched = 0;
static unsigned int cpufreq_init = 0;
static struct work_struct cpufreq_delayed_get_work;
static void handle_cpufreq_delayed_get(void *v)
{
unsigned int cpu;
for_each_online_cpu(cpu) {
cpufreq_get(cpu);
}
cpufreq_delayed_issched = 0;
}
/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries
* to verify the CPU frequency the timing core thinks the CPU is running
* at is still correct.
*/
static inline void cpufreq_delayed_get(void)
{
if (cpufreq_init && !cpufreq_delayed_issched) {
cpufreq_delayed_issched = 1;
printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n");
schedule_work(&cpufreq_delayed_get_work);
}
}
/* If the CPU frequency is scaled, TSC-based delays will need a different /* If the CPU frequency is scaled, TSC-based delays will need a different
* loops_per_jiffy value to function properly. An exception to this * loops_per_jiffy value to function properly.
* are modern Intel Pentium 4 processors, where the TSC runs at a constant
* speed independent of frequency scaling.
*/ */
static unsigned int ref_freq = 0; static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0; static unsigned long loops_per_jiffy_ref = 0;
static unsigned int variable_tsc = 1;
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
static unsigned long fast_gettimeoffset_ref = 0; static unsigned long fast_gettimeoffset_ref = 0;
...@@ -356,14 +386,15 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, ...@@ -356,14 +386,15 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
} }
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
if (variable_tsc) (val == CPUFREQ_RESUMECHANGE)) {
if (!(freq->flags & CPUFREQ_CONST_LOOPS))
cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
if (cpu_khz) if (cpu_khz)
cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
if (use_tsc) { if (use_tsc) {
if (variable_tsc) { if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq); fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
set_cyc2ns_scale(cpu_khz/1000); set_cyc2ns_scale(cpu_khz/1000);
} }
...@@ -382,14 +413,17 @@ static struct notifier_block time_cpufreq_notifier_block = { ...@@ -382,14 +413,17 @@ static struct notifier_block time_cpufreq_notifier_block = {
static int __init cpufreq_tsc(void) static int __init cpufreq_tsc(void)
{ {
/* P4 and above CPU TSC freq doesn't change when CPU frequency changes*/ int ret;
if ((boot_cpu_data.x86 >= 15) && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)) INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
variable_tsc = 0; ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
if (!ret)
return cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); cpufreq_init = 1;
return ret;
} }
core_initcall(cpufreq_tsc); core_initcall(cpufreq_tsc);
#else /* CONFIG_CPU_FREQ */
static inline void cpufreq_delayed_get(void) { return; }
#endif #endif
......
...@@ -1035,7 +1035,8 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val ...@@ -1035,7 +1035,8 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
ft->clock_tick_ref = cpu_data(cpu).clock_tick; ft->clock_tick_ref = cpu_data(cpu).clock_tick;
} }
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
(val == CPUFREQ_RESUMECHANGE)) {
cpu_data(cpu).udelay_val = cpu_data(cpu).udelay_val =
cpufreq_scale(ft->udelay_val_ref, cpufreq_scale(ft->udelay_val_ref,
ft->ref_freq, ft->ref_freq,
......
...@@ -532,7 +532,8 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, ...@@ -532,7 +532,8 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
cpu_khz_ref = cpu_khz; cpu_khz_ref = cpu_khz;
} }
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
(val == CPUFREQ_RESUMECHANGE)) {
*lpj = *lpj =
cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
......
...@@ -33,9 +33,10 @@ static struct cpufreq_driver *cpufreq_driver; ...@@ -33,9 +33,10 @@ static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED; static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
/* internal prototype */ /* 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 void handle_update(void *data);
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
/** /**
* Two notifier lists: the "policy" list is involved in the * Two notifier lists: the "policy" list is involved in the
...@@ -161,6 +162,7 @@ show_one(cpuinfo_min_freq, cpuinfo.min_freq); ...@@ -161,6 +162,7 @@ show_one(cpuinfo_min_freq, cpuinfo.min_freq);
show_one(cpuinfo_max_freq, cpuinfo.max_freq); show_one(cpuinfo_max_freq, cpuinfo.max_freq);
show_one(scaling_min_freq, min); show_one(scaling_min_freq, min);
show_one(scaling_max_freq, max); show_one(scaling_max_freq, max);
show_one(scaling_cur_freq, cur);
/** /**
* cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
...@@ -188,6 +190,18 @@ static ssize_t store_##file_name \ ...@@ -188,6 +190,18 @@ static ssize_t store_##file_name \
store_one(scaling_min_freq,min); store_one(scaling_min_freq,min);
store_one(scaling_max_freq,max); store_one(scaling_max_freq,max);
/**
* show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
*/
static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf)
{
unsigned int cur_freq = cpufreq_get(policy->cpu);
if (!cur_freq)
return sprintf(buf, "<unknown>");
return sprintf(buf, "%u\n", cur_freq);
}
/** /**
* show_scaling_governor - show the current policy for the specified CPU * show_scaling_governor - show the current policy for the specified CPU
*/ */
...@@ -268,6 +282,12 @@ struct freq_attr _name = { \ ...@@ -268,6 +282,12 @@ struct freq_attr _name = { \
.show = show_##_name, \ .show = show_##_name, \
} }
#define define_one_ro0400(_name) \
struct freq_attr _name = { \
.attr = { .name = __stringify(_name), .mode = 0400 }, \
.show = show_##_name, \
}
#define define_one_rw(_name) \ #define define_one_rw(_name) \
struct freq_attr _name = { \ struct freq_attr _name = { \
.attr = { .name = __stringify(_name), .mode = 0644 }, \ .attr = { .name = __stringify(_name), .mode = 0644 }, \
...@@ -275,10 +295,12 @@ struct freq_attr _name = { \ ...@@ -275,10 +295,12 @@ struct freq_attr _name = { \
.store = store_##_name, \ .store = store_##_name, \
} }
define_one_ro0400(cpuinfo_cur_freq);
define_one_ro(cpuinfo_min_freq); define_one_ro(cpuinfo_min_freq);
define_one_ro(cpuinfo_max_freq); define_one_ro(cpuinfo_max_freq);
define_one_ro(scaling_available_governors); define_one_ro(scaling_available_governors);
define_one_ro(scaling_driver); define_one_ro(scaling_driver);
define_one_ro(scaling_cur_freq);
define_one_rw(scaling_min_freq); define_one_rw(scaling_min_freq);
define_one_rw(scaling_max_freq); define_one_rw(scaling_max_freq);
define_one_rw(scaling_governor); define_one_rw(scaling_governor);
...@@ -369,6 +391,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -369,6 +391,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
policy->cpu = cpu; policy->cpu = cpu;
init_MUTEX_LOCKED(&policy->lock); init_MUTEX_LOCKED(&policy->lock);
init_completion(&policy->kobj_unregister); init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update, (void *)(long)cpu);
/* call driver. From then on the cpufreq must be able /* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU * to accept all calls to ->verify and ->setpolicy for this CPU
...@@ -394,6 +417,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ...@@ -394,6 +417,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
sysfs_create_file(&policy->kobj, &((*drv_attr)->attr)); sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
drv_attr++; drv_attr++;
} }
if (cpufreq_driver->get)
sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
if (cpufreq_driver->target)
sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
spin_lock_irqsave(&cpufreq_driver_lock, flags); spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_cpu_data[cpu] = policy; cpufreq_cpu_data[cpu] = policy;
...@@ -474,11 +501,86 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) ...@@ -474,11 +501,86 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
return 0; return 0;
} }
static void handle_update(void *data)
{
unsigned int cpu = (unsigned int)(long)data;
cpufreq_update_policy(cpu);
}
/** /**
* cpufreq_resume - restore the CPU clock frequency after resume * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
* @cpu: cpu number
* @old_freq: CPU frequency the kernel thinks the CPU runs at
* @new_freq: CPU frequency the CPU actually runs at
* *
* Restore the CPU clock frequency so that our idea of the current * We adjust to current frequency first, and need to clean up later. So either call
* frequency reflects the actual hardware. * 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)
{
struct cpufreq_freqs freqs;
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", old_freq, new_freq);
freqs.cpu = cpu;
freqs.old = old_freq;
freqs.new = new_freq;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
/**
* cpufreq_get - get the current CPU frequency (in kHz)
* @cpu: CPU number
*
* Get the CPU current (static) CPU frequency
*/
unsigned int cpufreq_get(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
unsigned int ret = 0;
if (!policy)
return 0;
if (!cpufreq_driver->get)
goto out;
down(&policy->lock);
ret = cpufreq_driver->get(cpu);
if (ret && policy->cur && !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS))
{
/* verify no discrepancy between actual and saved value exists */
if (unlikely(ret != policy->cur)) {
cpufreq_out_of_sync(cpu, policy->cur, ret);
schedule_work(&policy->update);
}
}
up(&policy->lock);
out:
cpufreq_cpu_put(policy);
return (ret);
}
EXPORT_SYMBOL(cpufreq_get);
/**
* cpufreq_resume - restore proper CPU frequency handling after resume
*
* 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
* 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
* 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored.
*/ */
static int cpufreq_resume(struct sys_device * sysdev) static int cpufreq_resume(struct sys_device * sysdev)
{ {
...@@ -498,25 +600,37 @@ static int cpufreq_resume(struct sys_device * sysdev) ...@@ -498,25 +600,37 @@ static int cpufreq_resume(struct sys_device * sysdev)
if (!cpu_policy) if (!cpu_policy)
return -EINVAL; return -EINVAL;
if (cpufreq_driver->resume) if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
ret = cpufreq_driver->resume(cpu_policy); unsigned int cur_freq = 0;
if (ret) {
printk(KERN_ERR "cpufreq: resume failed in ->resume step on CPU %u\n", cpu_policy->cpu);
goto out;
}
if (cpufreq_driver->setpolicy) if (cpufreq_driver->get)
ret = cpufreq_driver->setpolicy(cpu_policy); cur_freq = cpufreq_driver->get(cpu_policy->cpu);
else
/* CPUFREQ_RELATION_H or CPUFREQ_RELATION_L have the same effect here, as cpu_policy->cur is known
* to be a valid and exact target frequency
*/
ret = cpufreq_driver->target(cpu_policy, cpu_policy->cur, CPUFREQ_RELATION_H);
if (ret) if (!cur_freq || !cpu_policy->cur) {
printk(KERN_ERR "cpufreq: resume failed in ->setpolicy/target step on CPU %u\n", cpu_policy->cpu); printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n");
goto out;
}
if (unlikely(cur_freq != cpu_policy->cur)) {
struct cpufreq_freqs freqs;
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);
freqs.cpu = cpu;
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
}
}
out: out:
schedule_work(&cpu_policy->update);
cpufreq_cpu_put(cpu_policy); cpufreq_cpu_put(cpu_policy);
return ret; return ret;
} }
...@@ -904,16 +1018,20 @@ static unsigned int l_p_j_ref_freq; ...@@ -904,16 +1018,20 @@ static unsigned int l_p_j_ref_freq;
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) 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) { if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy; l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old; l_p_j_ref_freq = ci->old;
} }
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && 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); loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
} }
#else #else
#define adjust_jiffies(x...) do {} while (0) static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
#endif #endif
...@@ -925,13 +1043,29 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) ...@@ -925,13 +1043,29 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
*/ */
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{ {
if (irqs_disabled()) BUG_ON(irqs_disabled());
return; /* Only valid if we're in the resume process where
* everyone knows what CPU frequency we are at */ freqs->flags = cpufreq_driver->flags;
down_read(&cpufreq_notifier_rwsem); down_read(&cpufreq_notifier_rwsem);
switch (state) { switch (state) {
case CPUFREQ_PRECHANGE: 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); notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs); adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break; break;
...@@ -970,6 +1104,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -970,6 +1104,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
((!driver_data->setpolicy) && (!driver_data->target))) ((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL; return -EINVAL;
if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS;
spin_lock_irqsave(&cpufreq_driver_lock, flags); spin_lock_irqsave(&cpufreq_driver_lock, flags);
if (cpufreq_driver) { if (cpufreq_driver) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags); spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
......
...@@ -145,19 +145,6 @@ int cpufreq_setmax(unsigned int cpu) ...@@ -145,19 +145,6 @@ int cpufreq_setmax(unsigned int cpu)
EXPORT_SYMBOL_GPL(cpufreq_setmax); EXPORT_SYMBOL_GPL(cpufreq_setmax);
/**
* cpufreq_get - get the current CPU frequency (in kHz)
* @cpu: CPU number
*
* Get the CPU current (static) CPU frequency
*/
unsigned int cpufreq_get(unsigned int cpu)
{
return cpu_cur_freq[cpu];
}
EXPORT_SYMBOL(cpufreq_get);
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
...@@ -542,20 +529,6 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy, ...@@ -542,20 +529,6 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
return 0; return 0;
} }
/* on ARM SA1100 we need to rely on the values of cpufreq_get() - because
* of this, cpu_cur_freq[] needs to be set early.
*/
#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_SA1100)
extern unsigned int sa11x0_getspeed(void);
static void cpufreq_sa11x0_compat(void)
{
cpu_cur_freq[0] = sa11x0_getspeed();
}
#else
#define cpufreq_sa11x0_compat() do {} while(0)
#endif
struct cpufreq_governor cpufreq_gov_userspace = { struct cpufreq_governor cpufreq_gov_userspace = {
.name = "userspace", .name = "userspace",
...@@ -564,21 +537,12 @@ struct cpufreq_governor cpufreq_gov_userspace = { ...@@ -564,21 +537,12 @@ struct cpufreq_governor cpufreq_gov_userspace = {
}; };
EXPORT_SYMBOL(cpufreq_gov_userspace); EXPORT_SYMBOL(cpufreq_gov_userspace);
static int already_init = 0; static int __init cpufreq_gov_userspace_init(void)
int cpufreq_gov_userspace_init(void)
{ {
if (!already_init) { cpufreq_sysctl_init();
down(&userspace_sem); cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
cpufreq_sa11x0_compat();
cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
already_init = 1;
up(&userspace_sem);
}
return cpufreq_register_governor(&cpufreq_gov_userspace); return cpufreq_register_governor(&cpufreq_gov_userspace);
} }
EXPORT_SYMBOL(cpufreq_gov_userspace_init);
static void __exit cpufreq_gov_userspace_exit(void) static void __exit cpufreq_gov_userspace_exit(void)
......
...@@ -758,7 +758,8 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void * ...@@ -758,7 +758,8 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void *
struct cpufreq_freqs *freqs = p; struct cpufreq_freqs *freqs = p;
int i; int i;
if (phase == CPUFREQ_POSTCHANGE) { if ((phase == CPUFREQ_POSTCHANGE) ||
(phase == CPUFREQ_RESUMECHANGE)){
for (i = 0; i < SCI_NPORTS; i++) { for (i = 0; i < SCI_NPORTS; i++) {
struct uart_port *port = &sci_ports[i]; struct uart_port *port = &sci_ports[i];
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/workqueue.h>
#define CPUFREQ_NAME_LEN 16 #define CPUFREQ_NAME_LEN 16
...@@ -81,6 +82,9 @@ struct cpufreq_policy { ...@@ -81,6 +82,9 @@ struct cpufreq_policy {
struct semaphore lock; /* CPU ->setpolicy or ->target may struct semaphore lock; /* CPU ->setpolicy or ->target may
only be called once a time */ only be called once a time */
struct work_struct update; /* if update_policy() needs to be
* called, but you're in IRQ context */
struct cpufreq_real_policy user_policy; struct cpufreq_real_policy user_policy;
struct kobject kobj; struct kobject kobj;
...@@ -96,11 +100,13 @@ struct cpufreq_policy { ...@@ -96,11 +100,13 @@ struct cpufreq_policy {
#define CPUFREQ_PRECHANGE (0) #define CPUFREQ_PRECHANGE (0)
#define CPUFREQ_POSTCHANGE (1) #define CPUFREQ_POSTCHANGE (1)
#define CPUFREQ_RESUMECHANGE (8)
struct cpufreq_freqs { struct cpufreq_freqs {
unsigned int cpu; /* cpu nr */ unsigned int cpu; /* cpu nr */
unsigned int old; unsigned int old;
unsigned int new; unsigned int new;
u8 flags; /* flags of cpufreq_driver, see below. */
}; };
...@@ -187,6 +193,9 @@ struct cpufreq_driver { ...@@ -187,6 +193,9 @@ struct cpufreq_driver {
unsigned int target_freq, unsigned int target_freq,
unsigned int relation); unsigned int relation);
/* should be defined, if possible */
unsigned int (*get) (unsigned int cpu);
/* optional */ /* optional */
int (*exit) (struct cpufreq_policy *policy); int (*exit) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy); int (*resume) (struct cpufreq_policy *policy);
...@@ -195,8 +204,19 @@ struct cpufreq_driver { ...@@ -195,8 +204,19 @@ struct cpufreq_driver {
/* flags */ /* flags */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if #define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
all ->init() calls failed */ * all ->init() calls failed */
#define CPUFREQ_CONST_LOOPS 0x02 /* loops_per_jiffy or other kernel
* "constants" aren't affected by
* frequency transitions */
#define CPUFREQ_PANIC_OUTOFSYNC 0x04 /* panic if cpufreq's opinion of
* current frequency differs from
* actual frequency */
#define CPUFREQ_PANIC_RESUME_OUTOFSYNC 0x08 /* panic if cpufreq's opinion of
* current frequency differs from
* actual frequency on resume
* from sleep. */
int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
...@@ -234,6 +254,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy); ...@@ -234,6 +254,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy);
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu); int cpufreq_update_policy(unsigned int cpu);
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
unsigned int cpufreq_get(unsigned int cpu);
/* the proc_intf.c needs this */ /* the proc_intf.c needs this */
int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor); int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor);
...@@ -241,13 +264,10 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpu ...@@ -241,13 +264,10 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpu
/********************************************************************* /*********************************************************************
* CPUFREQ USERSPACE GOVERNOR * * CPUFREQ USERSPACE GOVERNOR *
*********************************************************************/ *********************************************************************/
int cpufreq_gov_userspace_init(void);
#ifdef CONFIG_CPU_FREQ_24_API #ifdef CONFIG_CPU_FREQ_24_API
int cpufreq_setmax(unsigned int cpu); int cpufreq_setmax(unsigned int cpu);
int cpufreq_set(unsigned int kHz, unsigned int cpu); int cpufreq_set(unsigned int kHz, unsigned int cpu);
unsigned int cpufreq_get(unsigned int cpu);
/* /proc/sys/cpu */ /* /proc/sys/cpu */
......
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