Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=6b37f5a20c0e5c334c010a587058354215433e92
Commit:     6b37f5a20c0e5c334c010a587058354215433e92
Parent:     fbc16f2c2a0e16dbd75ac85d3b6db97f92b642ba
Author:     Joerg Roedel <[EMAIL PROTECTED]>
AuthorDate: Wed May 2 19:27:06 2007 +0200
Committer:  Andi Kleen <[EMAIL PROTECTED]>
CommitDate: Wed May 2 19:27:06 2007 +0200

    [PATCH] x86-64: fix cpu MHz reporting on constant_tsc cpus
    
    This patch fixes the reporting of cpu_mhz in /proc/cpuinfo on CPUs with
    a constant TSC rate and a kernel with disabled cpufreq.
    
    Signed-off-by: Mark Langsdorf <[EMAIL PROTECTED]>
    Signed-off-by: Joerg Roedel <[EMAIL PROTECTED]>
    Signed-off-by: Andi Kleen <[EMAIL PROTECTED]>
    
     arch/x86_64/kernel/apic.c     |    2 -
     arch/x86_64/kernel/time.c     |   58 
+++++++++++++++++++++++++++++++++++++++---
     arch/x86_64/kernel/tsc.c      |   12 +++++---
     arch/x86_64/kernel/tsc_sync.c |    2 -
     include/asm-x86_64/proto.h    |    1
     5 files changed, 65 insertions(+), 10 deletions(-)
---
 arch/x86_64/kernel/apic.c     |    2 +-
 arch/x86_64/kernel/time.c     |   58 ++++++++++++++++++++++++++++++++++++++--
 arch/x86_64/kernel/tsc.c      |   12 +++++---
 arch/x86_64/kernel/tsc_sync.c |    2 +-
 include/asm-x86_64/proto.h    |    1 +
 5 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index bd3e45d..3421f21 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -843,7 +843,7 @@ static int __init calibrate_APIC_clock(void)
                } while ((tsc - tsc_start) < TICK_COUNT &&
                                (apic - apic_start) < TICK_COUNT);
 
-               result = (apic_start - apic) * 1000L * cpu_khz /
+               result = (apic_start - apic) * 1000L * tsc_khz /
                                        (tsc - tsc_start);
        }
        printk("result %d\n", result);
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 811b8f9..5f862e2 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -43,6 +43,7 @@
 #include <asm/apic.h>
 #include <asm/hpet.h>
 #include <asm/mpspec.h>
+#include <asm/nmi.h>
 
 static char *timename = NULL;
 
@@ -249,6 +250,51 @@ static unsigned long get_cmos_time(void)
        return mktime(year, mon, day, hour, min, sec);
 }
 
+/* calibrate_cpu is used on systems with fixed rate TSCs to determine
+ * processor frequency */
+#define TICK_COUNT 100000000
+static unsigned int __init tsc_calibrate_cpu_khz(void)
+{
+       int tsc_start, tsc_now;
+       int i, no_ctr_free;
+       unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
+       unsigned long flags;
+
+       for (i = 0; i < 4; i++)
+               if (avail_to_resrv_perfctr_nmi_bit(i))
+                       break;
+       no_ctr_free = (i == 4);
+       if (no_ctr_free) {
+               i = 3;
+               rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
+               wrmsrl(MSR_K7_EVNTSEL3, 0);
+               rdmsrl(MSR_K7_PERFCTR3, pmc3);
+       } else {
+               reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+               reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+       local_irq_save(flags);
+       /* start meauring cycles, incrementing from 0 */
+       wrmsrl(MSR_K7_PERFCTR0 + i, 0);
+       wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
+       rdtscl(tsc_start);
+       do {
+               rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
+               tsc_now = get_cycles_sync();
+       } while ((tsc_now - tsc_start) < TICK_COUNT);
+
+       local_irq_restore(flags);
+       if (no_ctr_free) {
+               wrmsrl(MSR_K7_EVNTSEL3, 0);
+               wrmsrl(MSR_K7_PERFCTR3, pmc3);
+               wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
+       } else {
+               release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+               release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+       }
+
+       return pmc_now * tsc_khz / (tsc_now - tsc_start);
+}
 
 /*
  * pit_calibrate_tsc() uses the speaker output (channel 2) of
@@ -336,14 +382,20 @@ void __init time_init(void)
        if (hpet_use_timer) {
                /* set tick_nsec to use the proper rate for HPET */
                tick_nsec = TICK_NSEC_HPET;
-               cpu_khz = hpet_calibrate_tsc();
+               tsc_khz = hpet_calibrate_tsc();
                timename = "HPET";
        } else {
                pit_init();
-               cpu_khz = pit_calibrate_tsc();
+               tsc_khz = pit_calibrate_tsc();
                timename = "PIT";
        }
 
+       cpu_khz = tsc_khz;
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
+               boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+               boot_cpu_data.x86 == 16)
+               cpu_khz = tsc_calibrate_cpu_khz();
+
        if (unsynchronized_tsc())
                mark_tsc_unstable();
 
@@ -352,7 +404,7 @@ void __init time_init(void)
        else
                vgetcpu_mode = VGETCPU_LSL;
 
-       set_cyc2ns_scale(cpu_khz);
+       set_cyc2ns_scale(tsc_khz);
        printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
                cpu_khz / 1000, cpu_khz % 1000);
        init_tsc_clocksource();
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c
index 1a0edbb..5c84992 100644
--- a/arch/x86_64/kernel/tsc.c
+++ b/arch/x86_64/kernel/tsc.c
@@ -13,6 +13,8 @@ static int notsc __initdata = 0;
 
 unsigned int cpu_khz;          /* TSC clocks / usec, not used here */
 EXPORT_SYMBOL(cpu_khz);
+unsigned int tsc_khz;
+EXPORT_SYMBOL(tsc_khz);
 
 static unsigned int cyc2ns_scale __read_mostly;
 
@@ -77,7 +79,7 @@ static void handle_cpufreq_delayed_get(struct work_struct *v)
 static unsigned int  ref_freq = 0;
 static unsigned long loops_per_jiffy_ref = 0;
 
-static unsigned long cpu_khz_ref = 0;
+static unsigned long tsc_khz_ref = 0;
 
 static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
                                 void *data)
@@ -99,7 +101,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, 
unsigned long val,
        if (!ref_freq) {
                ref_freq = freq->old;
                loops_per_jiffy_ref = *lpj;
-               cpu_khz_ref = cpu_khz;
+               tsc_khz_ref = tsc_khz;
        }
        if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||
                (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
@@ -107,12 +109,12 @@ static int time_cpufreq_notifier(struct notifier_block 
*nb, unsigned long val,
                *lpj =
                cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
 
-               cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
+               tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
                if (!(freq->flags & CPUFREQ_CONST_LOOPS))
                        mark_tsc_unstable();
        }
 
-       set_cyc2ns_scale(cpu_khz_ref);
+       set_cyc2ns_scale(tsc_khz_ref);
 
        return 0;
 }
@@ -213,7 +215,7 @@ EXPORT_SYMBOL_GPL(mark_tsc_unstable);
 void __init init_tsc_clocksource(void)
 {
        if (!notsc) {
-               clocksource_tsc.mult = clocksource_khz2mult(cpu_khz,
+               clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
                                                        clocksource_tsc.shift);
                if (check_tsc_unstable())
                        clocksource_tsc.rating = 0;
diff --git a/arch/x86_64/kernel/tsc_sync.c b/arch/x86_64/kernel/tsc_sync.c
index 014f0db..72d444d 100644
--- a/arch/x86_64/kernel/tsc_sync.c
+++ b/arch/x86_64/kernel/tsc_sync.c
@@ -50,7 +50,7 @@ static __cpuinit void check_tsc_warp(void)
        /*
         * The measurement runs for 20 msecs:
         */
-       end = start + cpu_khz * 20ULL;
+       end = start + tsc_khz * 20ULL;
        now = start;
 
        for (i = 0; ; i++) {
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index f64949f..7842702 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -92,6 +92,7 @@ extern unsigned long table_start, table_end;
 
 extern int exception_trace;
 extern unsigned cpu_khz;
+extern unsigned tsc_khz;
 
 extern void no_iommu_init(void);
 extern int force_iommu, no_iommu;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to