Commit 314a29b2 authored by Dave Jones's avatar Dave Jones Committed by Dave Jones

[CPUFREQ] Handle P4 TSC scaling.

Currently, the TSC cpufreq notifiers does almost nothing on P4s, as we
assumed the TSC to be constant independent of _all_ frequency transitions.
Extensive testing by Karol Kozimor has shown, though, that only _throttling_
does not affect the TSC, but _scaling_ does.
                                                                                
So:
- pass the CPUFREQ_CONST_LOOPS flags (to be exact, all flags) to cpufreq
  transition notifiers
- skip TSC value changes if this flag is set
- set this flag for P4 / P4-Ms only in p4-clockmod [On Pentium-M banias
  the TSC _is_ affected by p4-clock modulation
parent 460d0bf0
......@@ -51,6 +51,7 @@ enum {
static int has_N44_O17_errata[NR_CPUS];
static unsigned int stock_freq;
static struct cpufreq_driver p4clockmod_driver;
static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
{
......@@ -193,6 +194,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 "
......
......@@ -353,14 +353,11 @@ static inline void cpufreq_delayed_get(void)
}
/* 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;
......@@ -386,13 +383,13 @@ 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) ||
(val == CPUFREQ_RESUMECHANGE)) {
if (variable_tsc)
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);
}
......@@ -411,13 +408,12 @@ static struct notifier_block time_cpufreq_notifier_block = {
static int __init cpufreq_tsc(void)
{
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;
/* 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);
return ret;
}
core_initcall(cpufreq_tsc);
......
......@@ -1018,7 +1018,7 @@ static unsigned int l_p_j_ref_freq;
static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{
if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
if (ci->flags & CPUFREQ_CONST_LOOPS)
return;
if (!l_p_j_ref_freq) {
......@@ -1045,6 +1045,8 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
{
BUG_ON(irqs_disabled());
freqs->flags = cpufreq_driver->flags;
down_read(&cpufreq_notifier_rwsem);
switch (state) {
case CPUFREQ_PRECHANGE:
......
......@@ -106,6 +106,7 @@ struct cpufreq_freqs {
unsigned int cpu; /* cpu nr */
unsigned int old;
unsigned int new;
u8 flags; /* flags of cpufreq_driver, see below. */
};
......
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