cpufreq: x86 tsc cpufreq notifier

cpufreq: x86 tsc cpufreq notifier

Post by Dominik Brodowsk » Sun, 22 Dec 2002 19:50:08



The fast_gettimeoffset_quotient and the cpu_khz values should only be
updated on UP -- on SMP, these values might be different for each CPU, so
using the default values obtained at boot time should be safest.
Additionally, to get rid of accumulating rounding errors, reference values
are saved.
cpu_data[cpu].loops_per_jiffy is independent of the TSC and will be changed
in a different cpufreq notifier instead.

        Dominik

diff -ruN linux-original/arch/i386/kernel/timers/timer_tsc.c linux/arch/i386/kernel/timers/timer_tsc.c
--- linux-original/arch/i386/kernel/timers/timer_tsc.c  2002-12-21 14:53:44.000000000 +0100

 #ifdef CONFIG_CPU_FREQ

+static unsigned long fast_gettimeoffset_ref = 0;
+static unsigned long cpu_khz_ref = 0;
+static unsigned int  ref_freq = 0;
+
 static int
-time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+tsc_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                       void *data)
 {
        struct cpufreq_freqs *freq = data;
-       unsigned int i;

-       if (!cpu_has_tsc)
+       if (!use_tsc)
                return 0;

+       if (!fast_gettimeoffset_ref) {
+               fast_gettimeoffset_ref = fast_gettimeoffset_quotient;
+               cpu_khz_ref = cpu_khz;
+               ref_freq = freq->old;
+       }
+
        switch (val) {
        case CPUFREQ_PRECHANGE:
-               if ((freq->old < freq->new) &&
-               ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
-                       cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
-                       fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
+               if (freq->old < freq->new) {
+                       fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
+                       cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
                }
-               for (i=0; i<NR_CPUS; i++)
-                       if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
-                               cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
                break;
-
        case CPUFREQ_POSTCHANGE:
-               if ((freq->new < freq->old) &&
-               ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
-                       cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
-                       fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
+               if (freq->new < freq->old) {
+                       fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
+                       cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
                }
-               for (i=0; i<NR_CPUS; i++)
-                       if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
-                               cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
                break;
        }

        return 0;
 }

-static struct notifier_block time_cpufreq_notifier_block = {
-       .notifier_call  = time_cpufreq_notifier
+static struct notifier_block tsc_cpufreq_notifier_block = {
+       .notifier_call  = tsc_cpufreq_notifier
 };
 #endif

                                "0" (eax), "1" (edx));
                                printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
                        }
-#ifdef CONFIG_CPU_FREQ
-                       cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+#if defined(CONFIG_CPU_FREQ) && !defined(CONFIG_UP)
+                       cpufreq_register_notifier(&tsc_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
 #endif
                        return 0;
                }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in

More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

 
 
 

1. add write_seqlock to cpufreq change notifier for TSC

The CPU frequency change detection code can change the values used to
compute time of day with TSC; but there was no locking around it.

--- timer_tsc.c.orig    2003-03-18 14:52:25.000000000 -0800

 {
        struct cpufreq_freqs *freq = data;

+       write_seqlock(&xtime_lock);
        if (!ref_freq) {
                ref_freq = freq->old;

                }
 #endif
        }
+       write_sequnlock(&xtime_lock);

        return 0;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in

More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

2. zmodem for HP-unix

3. [RESEND] cpufreq: move /proc/cpufreq interface code to drivers/cpufreq

4. Playing mp3 or wav files on a Sun Sparc

5. cpufreq: x86 per-CPU loops_per_jiffy notifier

6. Print spooler /tmp limits

7. cpufreq: add support for cpufreq governors

8. kiosk mode for NCD X terminals

9. cpufreq: cpufreq governor interface

10. Fwd: [PATCH] cpufreq (1/7): fix cpufreq core breakage(s)

11. [RESEND] cpufreq: move frequency table helpers to drivers/cpufreq/

12. Fwd: [PATCH] cpufreq (4/7): updated cpufreq ref-counting and locking scheme