Commit e79b352d authored by Linus Torvalds's avatar Linus Torvalds

Merge

parents 10cba765 6deb6e5b
......@@ -92,3 +92,7 @@ values:
cpu - number of the affected CPU
old - old 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,
return 0;
}
static int integrator_cpufreq_init(struct cpufreq_policy *policy)
static unsigned int integrator_get(unsigned int cpu)
{
unsigned long cpus_allowed;
unsigned int cpu = policy->cpu;
unsigned int current_freq;
u_int cm_osc;
struct icst525_vco vco;
......@@ -175,15 +175,22 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
vco.v = cm_osc & 255;
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 */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.max_freq = 160000;
policy->cpuinfo.min_freq = 12000;
policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
policy->cur = policy->min = policy->max =
icst525_khz(&cclk_params, vco); /* current freq */
set_cpus_allowed(current, cpus_allowed);
policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
return 0;
}
......@@ -191,6 +198,7 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
static struct cpufreq_driver integrator_driver = {
.verify = integrator_verify_policy,
.target = integrator_set_target,
.get = integrator_get,
.init = integrator_cpufreq_init,
.name = "integrator",
};
......
......@@ -180,7 +180,7 @@ static int sa1100_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int cur = sa11x0_getspeed();
unsigned int cur = sa11x0_getspeed(0);
unsigned int new_ppcr;
struct cpufreq_freqs freqs;
......@@ -221,7 +221,7 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
{
if (policy->cpu != 0)
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->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
......@@ -230,15 +230,17 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver sa1100_driver = {
.flags = (CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC),
.verify = sa11x0_verify_speed,
.target = sa1100_target,
.get = sa11x0_getspeed,
.init = sa1100_cpu_init,
.name = "sa1100",
};
static int __init sa1100_dram_init(void)
{
cpufreq_gov_userspace_init();
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
return cpufreq_register_driver(&sa1100_driver);
else
......
......@@ -238,7 +238,7 @@ static int sa1110_target(struct cpufreq_policy *policy,
return -EINVAL;
}
freqs.old = sa11x0_getspeed();
freqs.old = sa11x0_getspeed(0);
freqs.new = sa11x0_ppcr_to_freq(ppcr);
freqs.cpu = 0;
......@@ -320,7 +320,7 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
{
if (policy->cpu != 0)
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->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
......@@ -329,8 +329,11 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
}
static struct cpufreq_driver sa1110_driver = {
.flags = (CPUFREQ_PANIC_OUTOFSYNC |
CPUFREQ_PANIC_RESUME_OUTOFSYNC),
.verify = sa11x0_verify_speed,
.target = sa1110_target,
.get = sa11x0_getspeed,
.init = sa1110_cpu_init,
.name = "sa1110",
};
......@@ -354,8 +357,6 @@ static int __init sa1110_clk_init(void)
sdram->tck, sdram->trcd, sdram->trp,
sdram->twr, sdram->refresh, sdram->cas_latency);
cpufreq_gov_userspace_init();
memcpy(&sdram_params, sdram, sizeof(sdram_params));
return cpufreq_register_driver(&sa1110_driver);
......
......@@ -96,11 +96,13 @@ int sa11x0_verify_speed(struct cpufreq_policy *policy)
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;
}
EXPORT_SYMBOL(sa11x0_getspeed);
#else
/*
* We still need to provide this so building without cpufreq works.
......
......@@ -22,5 +22,5 @@ struct cpufreq_policy;
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
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);
......@@ -2,15 +2,15 @@ obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
obj-$(CONFIG_X86_LONGRUN) += longrun.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_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.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_ACPI_DEBUG
......
......@@ -77,7 +77,7 @@ static struct cpufreq_frequency_table elanfreq_table[] = {
* 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 */
......@@ -121,7 +121,7 @@ static void elanfreq_set_cpu_state (unsigned int state) {
struct cpufreq_freqs freqs;
freqs.old = elanfreq_get_cpu_frequency();
freqs.old = elanfreq_get_cpu_frequency(0);
freqs.new = elan_multiplier[state].clock;
freqs.cpu = 0; /* elanfreq.c is UP only driver */
......@@ -209,7 +209,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
/* max freq */
if (!max_freq)
max_freq = elanfreq_get_cpu_frequency();
max_freq = elanfreq_get_cpu_frequency(0);
/* table init */
for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
......@@ -220,7 +220,7 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
/* cpuinfo and default policy values */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
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);
if (result)
......@@ -267,6 +267,7 @@ static struct freq_attr* elanfreq_attr[] = {
static struct cpufreq_driver elanfreq_driver = {
.get = elanfreq_get_cpu_frequency,
.verify = elanfreq_verify,
.target = elanfreq_target,
.init = elanfreq_cpu_init,
......
......@@ -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.
*/
static int gx_get_cpuspeed(void)
static unsigned int gx_get_cpuspeed(unsigned int cpu)
{
if ((gx_params->pci_suscfg & SUSMOD) == 0)
return stock_freq;
......@@ -271,7 +271,7 @@ static void gx_set_cpuspeed(unsigned int khz)
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);
......@@ -405,7 +405,7 @@ static int cpufreq_gx_target(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)
return -ENODEV;
......@@ -419,7 +419,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f];
}
stock_freq = maxfreq;
curfreq = gx_get_cpuspeed();
curfreq = gx_get_cpuspeed(0);
dprintk("cpu max frequency is %d.\n", maxfreq);
dprintk("cpu current frequency is %dkHz.\n",curfreq);
......@@ -446,6 +446,7 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
* MediaGX/Geode GX initialize cpufreq driver
*/
static struct cpufreq_driver gx_suspmod_driver = {
.get = gx_get_cpuspeed,
.verify = cpufreq_gx_verify,
.target = cpufreq_gx_target,
.init = cpufreq_gx_cpu_init,
......
......@@ -82,6 +82,10 @@ static int longhaul_get_cpu_mult (void)
if (lo & (1<<27))
invalue+=16;
}
if (longhaul_version==4) {
if (lo & (1<<27))
invalue+=16;
}
return eblcr_table[invalue];
}
......@@ -158,6 +162,22 @@ static void longhaul_setstate (unsigned int clock_ratio_index)
longhaul.bits.RevisionKey = 3;
wrmsrl (MSR_VIA_LONGHAUL, longhaul.val);
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);
......@@ -207,7 +227,7 @@ static int guess_fsb(int maxmult)
static int __init longhaul_get_ranges (void)
{
struct cpuinfo_x86 *c = cpu_data;
unsigned long invalue;
unsigned long invalue,invalue2;
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,
......@@ -234,8 +254,6 @@ static int __init longhaul_get_ranges (void)
case 2:
rdmsrl (MSR_VIA_LONGHAUL, longhaul.val);
//TODO: Nehemiah may have borken MaxMHzBR.
// need to extrapolate from FSB.
invalue = longhaul.bits.MaxMHzBR;
if (longhaul.bits.MaxMHzBR4)
invalue += 16;
......@@ -258,6 +276,38 @@ static int __init longhaul_get_ranges (void)
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",
......@@ -380,6 +430,13 @@ static int longhaul_target (struct cpufreq_policy *policy,
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)
{
struct cpuinfo_x86 *c = cpu_data;
......@@ -423,12 +480,27 @@ static int __init longhaul_cpu_init (struct cpufreq_policy *policy)
break;
case 9:
cpuname = "C3 'Nehemiah' [C5N]";
longhaul_version=2;
longhaul_version=4;
numscales=32;
memcpy (clock_ratio, nehemiah_clock_ratio, sizeof(nehemiah_clock_ratio));
memcpy (eblcr_table, nehemiah_eblcr, sizeof(nehemiah_eblcr));
switch (c->x86_mask) {
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;
default:
cpuname = "Unknown";
......@@ -472,6 +544,7 @@ static struct freq_attr* longhaul_attr[] = {
static struct cpufreq_driver longhaul_driver = {
.verify = longhaul_verify,
.target = longhaul_target,
.get = longhaul_get,
.init = longhaul_cpu_init,
.exit = longhaul_cpu_exit,
.name = "longhaul",
......
......@@ -234,14 +234,15 @@ static int __initdata ezrat_eblcr[32] = {
/*
* VIA C3 Nehemiah */
static int __initdata nehemiah_clock_ratio[32] = {
static int __initdata nehemiah_a_clock_ratio[32] = {
100, /* 0000 -> 10.0x */
160, /* 0001 -> 16.0x */
-1, /* 0010 -> RESERVED */
-1, /* 0010 -> RESERVED */
90, /* 0011 -> 9.0x */
95, /* 0100 -> 9.5x */
-1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */
-1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */
55, /* 0111 -> 5.5x */
60, /* 1000 -> 6.0x */
70, /* 1001 -> 7.0x */
......@@ -250,8 +251,42 @@ static int __initdata nehemiah_clock_ratio[32] = {
65, /* 1100 -> 6.5x */
75, /* 1101 -> 7.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 */
110, /* 0001 -> 11.0x */
120, /* 0010 -> 12.0x */
......@@ -266,18 +301,88 @@ static int __initdata nehemiah_clock_ratio[32] = {
130, /* 1011 -> 13.0x */
145, /* 1100 -> 14.5x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED */
-1, /* 1110 -> RESERVED (13.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 */
160, /* 0001 -> 16.0x */
-1, /* 0010 -> RESERVED */
-1, /* 0010 -> RESERVED */
100, /* 0011 -> 10.0x */
55, /* 0100 -> 5.5x */
-1, /* 0101 -> RESERVED */
-1, /* 0110 -> RESERVED */
-1, /* 0101 -> 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 */
90, /* 1000 -> 9.0x */
70, /* 1001 -> 7.0x */
......@@ -287,7 +392,6 @@ static int __initdata nehemiah_eblcr[32] = {
75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */
65, /* 1111 -> 6.5x */
90, /* 0000 -> 9.0x */
110, /* 0001 -> 11.0x */
120, /* 0010 -> 12.0x */
......@@ -302,9 +406,46 @@ static int __initdata nehemiah_eblcr[32] = {
140, /* 1011 -> 14.0x */
120, /* 1100 -> 12.0x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED */
-1, /* 1111 -> RESERVED */
-1, /* 1110 -> RESERVED (13.0x) */
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.
* 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)
rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
msr_lo &= 0x0000007F;
msr_hi &= 0x0000007F;
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);
if ( longrun_high_freq <= longrun_low_freq ) {
/* Assume degenerate Longrun table */
policy->min = policy->max = longrun_high_freq;
} else {
policy->min = longrun_low_freq + msr_lo *
((longrun_high_freq - longrun_low_freq) / 100);
policy->max = longrun_low_freq + msr_hi *
((longrun_high_freq - longrun_low_freq) / 100);
}
policy->cpu = 0;
}
......@@ -70,10 +75,15 @@ static int longrun_set_policy(struct cpufreq_policy *policy)
if (!policy)
return -EINVAL;
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 ( longrun_high_freq <= longrun_low_freq ) {
/* Assume degenerate Longrun table */
pctg_lo = pctg_hi = 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)
pctg_hi = 100;
......@@ -128,6 +138,17 @@ static int longrun_verify_policy(struct cpufreq_policy *policy)
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
......@@ -250,8 +271,10 @@ static int __init longrun_cpu_init(struct cpufreq_policy *policy)
static struct cpufreq_driver longrun_driver = {
.flags = CPUFREQ_CONST_LOOPS,
.verify = longrun_verify_policy,
.setpolicy = longrun_set_policy,
.get = longrun_get,
.init = longrun_cpu_init,
.name = "longrun",
.owner = THIS_MODULE,
......
......@@ -51,55 +51,16 @@ enum {
static int has_N44_O17_errata[NR_CPUS];
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)
{
u32 l, h;
cpumask_t cpus_allowed, affected_cpu_map;
struct cpufreq_freqs freqs;
int j;
if (!cpu_online(cpu) || (newstate > DC_DISABLE) ||
(newstate == DC_RESV))
if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV))
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);
#if 0
if (l & 0x01)
......@@ -125,16 +86,6 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
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;
}
......@@ -158,11 +109,59 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
unsigned int relation)
{
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))
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;
}
......@@ -177,11 +176,23 @@ static int cpufreq_p4_verify(struct cpufreq_policy *policy)
static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
{
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. "
"The speedstep_centrino module offers voltage scaling"
" in addition of frequency scaling. You should use "
"that instead of p4-clockmod, if possible.\n");
/* on P-4s, the TSC runs with constant frequency independent wether
* throttling is active or not. */
p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS;
return speedstep_get_processor_frequency(SPEEDSTEP_PROCESSOR_PM);
}
......@@ -190,6 +201,10 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
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) {
printk(KERN_WARNING PFX "Warning: Pentium 4-M detected. "
"The speedstep-ich or acpi cpufreq modules offer "
......@@ -249,6 +264,33 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy)
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[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
......@@ -259,6 +301,7 @@ static struct cpufreq_driver p4clockmod_driver = {
.target = cpufreq_p4_target,
.init = cpufreq_p4_cpu_init,
.exit = cpufreq_p4_cpu_exit,
.get = cpufreq_p4_get,
.name = "p4-clockmod",
.owner = THIS_MODULE,
.attr = p4clockmod_attr,
......
......@@ -185,6 +185,11 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
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[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
......@@ -195,6 +200,7 @@ static struct cpufreq_driver powernow_k6_driver = {
.target = powernow_k6_target,
.init = powernow_k6_cpu_init,
.exit = powernow_k6_cpu_exit,
.get = powernow_k6_get,
.name = "powernow-k6",
.owner = THIS_MODULE,
.attr = powernow_k6_attr,
......
......@@ -540,6 +540,20 @@ static int __init fixup_sgtc(void)
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)
{
union msr_fidvidstatus fidvidstatus;
......@@ -590,7 +604,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
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);
......@@ -610,6 +624,7 @@ static struct freq_attr* powernow_table_attr[] = {
static struct cpufreq_driver powernow_driver = {
.verify = powernow_verify,
.target = powernow_target,
.get = powernow_get,
.init = powernow_cpu_init,
.exit = powernow_cpu_exit,
.name = "powernow-k7",
......
......@@ -32,14 +32,14 @@
#include <asm/io.h>
#include <asm/delay.h>
#ifdef CONFIG_ACPI_PROCESSOR
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif
#define PFX "powernow-k8: "
#define BFX PFX "BIOS error: "
#define VERSION "version 1.00.08b"
#define VERSION "version 1.00.09b"
#include "powernow-k8.h"
/* serialize freq changes */
......@@ -450,13 +450,10 @@ static int check_supported_cpu(unsigned int cpu)
goto out;
eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
if ((eax & CPUID_XFAM_MOD) == ATHLON64_XFAM_MOD) {
dprintk(KERN_DEBUG PFX "AMD Althon 64 Processor found\n");
} else if ((eax & CPUID_XFAM_MOD) == OPTERON_XFAM_MOD) {
dprintk(KERN_DEBUG PFX "AMD Opteron Processor found\n");
} else {
printk(KERN_INFO PFX
"AMD Athlon 64 or AMD Opteron processor required\n");
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
((eax & CPUID_XFAM) != CPUID_XFAM_K8) ||
((eax & CPUID_XMOD) > CPUID_XMOD_REV_E)) {
printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
goto out;
}
......@@ -524,11 +521,12 @@ static void print_basics(struct powernow_k8_data *data)
{
int 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,
data->powernow_table[j].index & 0xff,
data->powernow_table[j].frequency/1000,
data->powernow_table[j].index >> 8,
find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)
printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
data->powernow_table[j].index & 0xff,
data->powernow_table[j].frequency/1000,
data->powernow_table[j].index >> 8,
find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
}
if (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)
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)
{
if (!data->acpi_data.state_count)
......@@ -723,7 +721,14 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
/* verify frequency is OK */
if ((powernow_table[i].frequency > (MAX_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;
continue;
}
......@@ -1025,6 +1030,32 @@ static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
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[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
......@@ -1035,6 +1066,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.target = powernowk8_target,
.init = powernowk8_cpu_init,
.exit = powernowk8_cpu_exit,
.get = powernowk8_get,
.name = "powernow-k8",
.owner = THIS_MODULE,
.attr = powernow_k8_attr,
......
......@@ -29,7 +29,7 @@ struct powernow_k8_data {
* frequency is in kHz */
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
* used to determine valid frequency/vid/fid states */
struct acpi_processor_performance acpi_data;
......@@ -38,13 +38,15 @@ struct powernow_k8_data {
/* processor's cpuid instruction support */
#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */
#define CPUID_XFAM_MOD 0x0ff00ff0 /* extended fam, fam + model */
#define ATHLON64_XFAM_MOD 0x00000f40 /* extended fam, fam + model */
#define OPTERON_XFAM_MOD 0x00000f50 /* extended fam, fam + model */
#define CPUID_GET_MAX_CAPABILITIES 0x80000000
#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
#define P_STATE_TRANSITION_CAPABLE 6
#define CPUID_PROCESSOR_SIGNATURE 1 /* function 1 */
#define CPUID_XFAM 0x0ff00000 /* extended family */
#define CPUID_XFAM_K8 0
#define CPUID_XMOD 0x000f0000 /* extended model */
#define CPUID_XMOD_REV_E 0x00020000
#define CPUID_USE_XFAM_XMOD 0x00000f00
#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 */
/* writes (wrmsr - opcode 0f 30), the register number is placed in ecx, and */
......
......@@ -38,13 +38,37 @@
#define dprintk(msg...) do { } while(0)
#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
{
const struct cpu_id *cpu_id;
const char *model_name;
unsigned max_freq; /* max clock in kHz */
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 */
static struct cpu_model *centrino_model;
......@@ -67,8 +91,8 @@ static struct cpu_model *centrino_model;
* M.
*/
/* Ultra Low Voltage Intel Pentium M processor 900MHz */
static struct cpufreq_frequency_table op_900[] =
/* Ultra Low Voltage Intel Pentium M processor 900MHz (Banias) */
static struct cpufreq_frequency_table banias_900[] =
{
OP(600, 844),
OP(800, 988),
......@@ -76,8 +100,8 @@ static struct cpufreq_frequency_table op_900[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Ultra Low Voltage Intel Pentium M processor 1000MHz */
static struct cpufreq_frequency_table op_1000[] =
/* Ultra Low Voltage Intel Pentium M processor 1000MHz (Banias) */
static struct cpufreq_frequency_table banias_1000[] =
{
OP(600, 844),
OP(800, 972),
......@@ -86,8 +110,8 @@ static struct cpufreq_frequency_table op_1000[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Low Voltage Intel Pentium M processor 1.10GHz */
static struct cpufreq_frequency_table op_1100[] =
/* Low Voltage Intel Pentium M processor 1.10GHz (Banias) */
static struct cpufreq_frequency_table banias_1100[] =
{
OP( 600, 956),
OP( 800, 1020),
......@@ -98,8 +122,8 @@ static struct cpufreq_frequency_table op_1100[] =
};
/* Low Voltage Intel Pentium M processor 1.20GHz */
static struct cpufreq_frequency_table op_1200[] =
/* Low Voltage Intel Pentium M processor 1.20GHz (Banias) */
static struct cpufreq_frequency_table banias_1200[] =
{
OP( 600, 956),
OP( 800, 1004),
......@@ -110,8 +134,8 @@ static struct cpufreq_frequency_table op_1200[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Intel Pentium M processor 1.30GHz */
static struct cpufreq_frequency_table op_1300[] =
/* Intel Pentium M processor 1.30GHz (Banias) */
static struct cpufreq_frequency_table banias_1300[] =
{
OP( 600, 956),
OP( 800, 1260),
......@@ -121,8 +145,8 @@ static struct cpufreq_frequency_table op_1300[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Intel Pentium M processor 1.40GHz */
static struct cpufreq_frequency_table op_1400[] =
/* Intel Pentium M processor 1.40GHz (Banias) */
static struct cpufreq_frequency_table banias_1400[] =
{
OP( 600, 956),
OP( 800, 1180),
......@@ -132,8 +156,8 @@ static struct cpufreq_frequency_table op_1400[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Intel Pentium M processor 1.50GHz */
static struct cpufreq_frequency_table op_1500[] =
/* Intel Pentium M processor 1.50GHz (Banias) */
static struct cpufreq_frequency_table banias_1500[] =
{
OP( 600, 956),
OP( 800, 1116),
......@@ -144,8 +168,8 @@ static struct cpufreq_frequency_table op_1500[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Intel Pentium M processor 1.60GHz */
static struct cpufreq_frequency_table op_1600[] =
/* Intel Pentium M processor 1.60GHz (Banias) */
static struct cpufreq_frequency_table banias_1600[] =
{
OP( 600, 956),
OP( 800, 1036),
......@@ -156,8 +180,8 @@ static struct cpufreq_frequency_table op_1600[] =
{ .frequency = CPUFREQ_TABLE_END }
};
/* Intel Pentium M processor 1.70GHz */
static struct cpufreq_frequency_table op_1700[] =
/* Intel Pentium M processor 1.70GHz (Banias) */
static struct cpufreq_frequency_table banias_1700[] =
{
OP( 600, 956),
OP( 800, 1004),
......@@ -169,26 +193,31 @@ static struct cpufreq_frequency_table op_1700[] =
};
#undef OP
#define _CPU(max, name) \
{ "Intel(R) Pentium(R) M processor " name "MHz", (max)*1000, op_##max }
#define CPU(max) _CPU(max, #max)
#define _BANIAS(cpuid, max, name) \
{ .cpu_id = cpuid, \
.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
operating points */
static struct cpu_model models[] =
{
_CPU( 900, " 900"),
CPU(1000),
CPU(1100),
CPU(1200),
CPU(1300),
CPU(1400),
CPU(1500),
CPU(1600),
CPU(1700),
_BANIAS(&cpu_id_banias, 900, " 900"),
BANIAS(1000),
BANIAS(1100),
BANIAS(1200),
BANIAS(1300),
BANIAS(1400),
BANIAS(1500),
BANIAS(1600),
BANIAS(1700),
{ 0, }
};
#undef CPU
#undef _BANIAS
#undef BANIAS
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;
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;
if (model->model_name == NULL) {
printk(KERN_INFO PFX "no support for CPU model \"%s\": "
......@@ -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; }
#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 */
static unsigned extract_clock(unsigned msr)
{
......@@ -225,9 +265,11 @@ static unsigned extract_clock(unsigned msr)
}
/* 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;
if (cpu)
return 0;
rdmsr(MSR_IA32_PERF_STATUS, l, h);
return extract_clock(l);
......@@ -322,7 +364,7 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
goto err_kfree;
}
cur_freq = get_cur_freq();
cur_freq = get_cur_freq(0);
for (i=0; i<p.state_count; i++) {
centrino_model->op_points[i].index = p.states[i].control;
......@@ -357,13 +399,8 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV;
/* Only Intel Pentium M stepping 5 for now - add new CPUs as
they appear after making sure they use PERF_CTL in the same
way. */
if (cpu->x86_vendor != X86_VENDOR_INTEL ||
cpu->x86 != 6 ||
cpu->x86_model != 9 ||
cpu->x86_mask != 5) {
if ((centrino_verify_cpu_id(cpu, &cpu_id_banias)) &&
(centrino_verify_cpu_id(cpu, &cpu_id_dothan_a1))) {
printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: "
"send /proc/cpuinfo to " MAINTAINER "\n");
return -ENODEV;
......@@ -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->cpuinfo.transition_latency = 10; /* 10uS transition latency */
policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
policy->cur = freq;
dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n",
......@@ -516,6 +553,7 @@ static struct cpufreq_driver centrino_driver = {
.exit = centrino_cpu_exit,
.verify = centrino_verify,
.target = centrino_target,
.get = get_cur_freq,
.attr = centrino_attr,
.owner = THIS_MODULE,
};
......
......@@ -179,7 +179,7 @@ static int speedstep_activate (void)
/**
* 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
* functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
* chipset, or zero on failure.
......@@ -322,6 +322,10 @@ static int speedstep_cpu_exit(struct cpufreq_policy *policy)
return 0;
}
static unsigned int speedstep_get(unsigned int cpu)
{
return speedstep_get_processor_frequency(speedstep_processor);
}
static struct freq_attr* speedstep_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
......@@ -335,6 +339,7 @@ static struct cpufreq_driver speedstep_driver = {
.target = speedstep_target,
.init = speedstep_cpu_init,
.exit = speedstep_cpu_exit,
.get = speedstep_get,
.owner = THIS_MODULE,
.attr = speedstep_attr,
};
......
......@@ -36,6 +36,8 @@ static int smi_port = 0;
static int smi_cmd = 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
......@@ -258,9 +260,10 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
&speedstep_freqs[SPEEDSTEP_HIGH].frequency);
if (result) {
/* 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");
if (!speedstep_processor)
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor)
return -ENODEV;
......@@ -298,13 +301,23 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
return 0;
}
static int speedstep_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_put_attr(policy->cpu);
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)
{
......@@ -327,6 +340,7 @@ static struct cpufreq_driver speedstep_driver = {
.target = speedstep_target,
.init = speedstep_cpu_init,
.exit = speedstep_cpu_exit,
.get = speedstep_get,
.resume = speedstep_resume,
.owner = THIS_MODULE,
.attr = speedstep_attr,
......
......@@ -27,6 +27,8 @@ static unsigned long hpet_last;
struct timer_opts timer_tsc;
#endif
static inline void cpufreq_delayed_get(void);
int tsc_disable __initdata = 0;
extern spinlock_t i8253_lock;
......@@ -241,6 +243,9 @@ static void mark_offset_tsc(void)
clock_fallback();
}
/* ... but give the TSC a fair chance */
if (lost_count > 25)
cpufreq_delayed_get();
} else
lost_count = 0;
/* update the monotonic base value */
......@@ -324,15 +329,40 @@ static void mark_offset_tsc_hpet(void)
#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
* loops_per_jiffy value to function properly. An exception to this
* are modern Intel Pentium 4 processors, where the TSC runs at a constant
* speed independent of frequency scaling.
* loops_per_jiffy value to function properly.
*/
static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0;
static unsigned int variable_tsc = 1;
#ifndef CONFIG_SMP
static unsigned long fast_gettimeoffset_ref = 0;
......@@ -356,14 +386,15 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
if (variable_tsc)
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
(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);
#ifndef CONFIG_SMP
if (cpu_khz)
cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
if (use_tsc) {
if (variable_tsc) {
if (!(freq->flags & CPUFREQ_CONST_LOOPS)) {
fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
set_cyc2ns_scale(cpu_khz/1000);
}
......@@ -382,14 +413,17 @@ static struct notifier_block time_cpufreq_notifier_block = {
static int __init cpufreq_tsc(void)
{
/* P4 and above CPU TSC freq doesn't change when CPU frequency changes*/
if ((boot_cpu_data.x86 >= 15) && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL))
variable_tsc = 0;
return cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
int ret;
INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);
ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
if (!ret)
cpufreq_init = 1;
return ret;
}
core_initcall(cpufreq_tsc);
#else /* CONFIG_CPU_FREQ */
static inline void cpufreq_delayed_get(void) { return; }
#endif
......
......@@ -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;
}
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 =
cpufreq_scale(ft->udelay_val_ref,
ft->ref_freq,
......
......@@ -532,7 +532,8 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
cpu_khz_ref = cpu_khz;
}
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 =
cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
......
......@@ -33,9 +33,10 @@ static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
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 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
......@@ -161,6 +162,7 @@ show_one(cpuinfo_min_freq, cpuinfo.min_freq);
show_one(cpuinfo_max_freq, cpuinfo.max_freq);
show_one(scaling_min_freq, min);
show_one(scaling_max_freq, max);
show_one(scaling_cur_freq, cur);
/**
* cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
......@@ -188,6 +190,18 @@ static ssize_t store_##file_name \
store_one(scaling_min_freq,min);
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
*/
......@@ -268,6 +282,12 @@ struct freq_attr _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) \
struct freq_attr _name = { \
.attr = { .name = __stringify(_name), .mode = 0644 }, \
......@@ -275,10 +295,12 @@ struct freq_attr _name = { \
.store = store_##_name, \
}
define_one_ro0400(cpuinfo_cur_freq);
define_one_ro(cpuinfo_min_freq);
define_one_ro(cpuinfo_max_freq);
define_one_ro(scaling_available_governors);
define_one_ro(scaling_driver);
define_one_ro(scaling_cur_freq);
define_one_rw(scaling_min_freq);
define_one_rw(scaling_max_freq);
define_one_rw(scaling_governor);
......@@ -369,6 +391,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
policy->cpu = cpu;
init_MUTEX_LOCKED(&policy->lock);
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update, (void *)(long)cpu);
/* call driver. From then on the cpufreq must be able
* 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)
sysfs_create_file(&policy->kobj, &((*drv_attr)->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);
cpufreq_cpu_data[cpu] = policy;
......@@ -474,11 +501,86 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
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
* frequency reflects the actual hardware.
* We adjust to current frequency first, and need to clean up later. So either call
* to cpufreq_update_policy() or schedule handle_update()).
*/
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigned int new_freq)
{
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)
{
......@@ -498,25 +600,37 @@ static int cpufreq_resume(struct sys_device * sysdev)
if (!cpu_policy)
return -EINVAL;
if (cpufreq_driver->resume)
ret = cpufreq_driver->resume(cpu_policy);
if (ret) {
printk(KERN_ERR "cpufreq: resume failed in ->resume step on CPU %u\n", cpu_policy->cpu);
goto out;
}
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
unsigned int cur_freq = 0;
if (cpufreq_driver->setpolicy)
ret = cpufreq_driver->setpolicy(cpu_policy);
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 (cpufreq_driver->get)
cur_freq = cpufreq_driver->get(cpu_policy->cpu);
if (ret)
printk(KERN_ERR "cpufreq: resume failed in ->setpolicy/target step on CPU %u\n", cpu_policy->cpu);
if (!cur_freq || !cpu_policy->cur) {
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:
schedule_work(&cpu_policy->update);
cpufreq_cpu_put(cpu_policy);
return ret;
}
......@@ -904,16 +1018,20 @@ static unsigned int l_p_j_ref_freq;
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{
if (ci->flags & CPUFREQ_CONST_LOOPS)
return;
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new))
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
(val == CPUFREQ_RESUMECHANGE))
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
}
#else
#define adjust_jiffies(x...) do {} while (0)
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) { return; }
#endif
......@@ -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)
{
if (irqs_disabled())
return; /* Only valid if we're in the resume process where
* everyone knows what CPU frequency we are at */
BUG_ON(irqs_disabled());
freqs->flags = cpufreq_driver->flags;
down_read(&cpufreq_notifier_rwsem);
switch (state) {
case CPUFREQ_PRECHANGE:
/* detect if the driver reported a value as "old frequency" which
* is not equal to what the cpufreq core thinks is "old frequency".
*/
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{
if (cpufreq_driver->flags & CPUFREQ_PANIC_OUTOFSYNC)
panic("CPU Frequency is out of sync.");
printk(KERN_WARNING "Warning: CPU frequency out of sync: "
"cpufreq and timing core thinks of %u, is %u kHz.\n",
cpufreq_cpu_data[freqs->cpu]->cur, freqs->old);
freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
}
}
notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
......@@ -970,6 +1104,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL;
if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS;
spin_lock_irqsave(&cpufreq_driver_lock, flags);
if (cpufreq_driver) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
......
......@@ -145,19 +145,6 @@ int cpufreq_setmax(unsigned int cpu)
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
......@@ -542,20 +529,6 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
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 = {
.name = "userspace",
......@@ -564,21 +537,12 @@ struct cpufreq_governor cpufreq_gov_userspace = {
};
EXPORT_SYMBOL(cpufreq_gov_userspace);
static int already_init = 0;
int cpufreq_gov_userspace_init(void)
static int __init cpufreq_gov_userspace_init(void)
{
if (!already_init) {
down(&userspace_sem);
cpufreq_sa11x0_compat();
cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
already_init = 1;
up(&userspace_sem);
}
cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return cpufreq_register_governor(&cpufreq_gov_userspace);
}
EXPORT_SYMBOL(cpufreq_gov_userspace_init);
static void __exit cpufreq_gov_userspace_exit(void)
......
......@@ -758,7 +758,8 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void *
struct cpufreq_freqs *freqs = p;
int i;
if (phase == CPUFREQ_POSTCHANGE) {
if ((phase == CPUFREQ_POSTCHANGE) ||
(phase == CPUFREQ_RESUMECHANGE)){
for (i = 0; i < SCI_NPORTS; i++) {
struct uart_port *port = &sci_ports[i];
......
......@@ -21,6 +21,7 @@
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#define CPUFREQ_NAME_LEN 16
......@@ -81,6 +82,9 @@ struct cpufreq_policy {
struct semaphore lock; /* CPU ->setpolicy or ->target may
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 kobject kobj;
......@@ -96,11 +100,13 @@ struct cpufreq_policy {
#define CPUFREQ_PRECHANGE (0)
#define CPUFREQ_POSTCHANGE (1)
#define CPUFREQ_RESUMECHANGE (8)
struct cpufreq_freqs {
unsigned int cpu; /* cpu nr */
unsigned int old;
unsigned int new;
u8 flags; /* flags of cpufreq_driver, see below. */
};
......@@ -187,6 +193,9 @@ struct cpufreq_driver {
unsigned int target_freq,
unsigned int relation);
/* should be defined, if possible */
unsigned int (*get) (unsigned int cpu);
/* optional */
int (*exit) (struct cpufreq_policy *policy);
int (*resume) (struct cpufreq_policy *policy);
......@@ -195,8 +204,19 @@ struct cpufreq_driver {
/* flags */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
all ->init() calls failed */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
* 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_unregister_driver(struct cpufreq_driver *driver_data);
......@@ -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_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 */
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
/*********************************************************************
* CPUFREQ USERSPACE GOVERNOR *
*********************************************************************/
int cpufreq_gov_userspace_init(void);
#ifdef CONFIG_CPU_FREQ_24_API
int cpufreq_setmax(unsigned int cpu);
int cpufreq_set(unsigned int kHz, unsigned int cpu);
unsigned int cpufreq_get(unsigned int 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