]> git.hungrycats.org Git - linux/commitdiff
[CPUFREQ] Handle P4 TSC scaling.
authorDave Jones <davej@redhat.com>
Fri, 7 May 2004 16:45:54 +0000 (17:45 +0100)
committerDave Jones <davej@delerium.codemonkey.org.uk>
Fri, 7 May 2004 16:45:54 +0000 (17:45 +0100)
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

arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
arch/i386/kernel/timers/timer_tsc.c
drivers/cpufreq/cpufreq.c
include/linux/cpufreq.h

index a9be690b461119f451ddf57d3a698d8ad3711c31..ec08f2ef12e89581efd97a4c87cd11c53a682eca 100644 (file)
@@ -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 "
index 1034c6c1bc85873fb1d796a87f2b7acd00ed10f5..532ef1d2d74fc78c68d8ded616ca19413e89f0b6 100644 (file)
@@ -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);
-       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);
+       ret = cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+       if (!ret)
+               cpufreq_init = 1;
+       return ret;
 }
 core_initcall(cpufreq_tsc);
 
index c345cb233cf1eab27f6b19c419b4ef112519c32e..912ce70348da321ef90cd51e5609433b44af0468 100644 (file)
@@ -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:
index 36f58874788f3074f3b9cd74135645a268747dfc..b4204dc7e304f675dde629596516c800ba81cfc7 100644 (file)
@@ -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. */
 };