Skip to contentSkip to conversation

x86_64: fix cpu MHz reporting on constant_tsc cpus

PATCH In review Joerg Roedel 2 participants 4 messages Mar 13, 2007 – Mar 16, 2007

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86_64: fix cpu MHz reporting on constant_tsc cpus

From: Mark Langsdorf <[email protected]>
From: Joerg Roedel <[email protected]>

This patch fixes the reporting of cpu_mhz in /proc/cpuinfo on CPUs with a constant TSC rate and a kernel with disabled cpufreq.

Signature · 3 lines
Joerg Roedel
Operating System Research Center
AMD Saxony LLC & Co. KG
arch/x86_64/kernel/apic.c +1 -1
index 723417d..5f291b2 100644
@@ -839,7 +839,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);
arch/x86_64/kernel/nmi.c +10 -9
index 486f4c6..0bbaeda 100644
@@ -168,7 +168,7 @@ void release_evntsel_nmi(unsigned int msr)
 	clear_bit(counter, &__get_cpu_var(evntsel_nmi_owner));
 }
 
-static __cpuinit inline int nmi_known_cpu(void)
+__cpuinit inline int nmi_known_cpu(void)
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
@@ -225,8 +225,8 @@ static unsigned int adjust_for_32bit_ctr(unsigned int hz)
 	 * 32nd bit should be 1, for 33.. to be 1.
 	 * Find the appropriate nmi_hz
 	 */
- 	if ((((u64)cpu_khz * 1000) / retval) > 0x7fffffffULL) {
-		retval = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1;
+ 	if ((((u64)tsc_khz * 1000) / retval) > 0x7fffffffULL) {
+		retval = ((u64)tsc_khz * 1000) / 0x7fffffffUL + 1;
 	}
 	return retval;
 }
@@ -493,7 +493,7 @@ static int setup_k7_watchdog(void)
 
 	/* setup the timer */
 	wrmsr(evntsel_msr, evntsel, 0);
-	wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
+	wrmsrl(perfctr_msr, -((u64)tsc_khz * 1000 / nmi_hz));
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= K7_EVNTSEL_ENABLE;
 	wrmsr(evntsel_msr, evntsel, 0);
@@ -601,7 +601,7 @@ static int setup_p4_watchdog(void)
 
 	wrmsr(evntsel_msr, evntsel, 0);
 	wrmsr(cccr_msr, cccr_val, 0);
-	wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
+	wrmsrl(perfctr_msr, -((u64)tsc_khz * 1000 / nmi_hz));
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	cccr_val |= P4_CCCR_ENABLE;
 	wrmsr(cccr_msr, cccr_val, 0);
@@ -671,7 +671,7 @@ static int setup_intel_arch_watchdog(void)
 	wrmsr(evntsel_msr, evntsel, 0);
 
 	nmi_hz = adjust_for_32bit_ctr(nmi_hz);
-	wrmsr(perfctr_msr, (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
+	wrmsr(perfctr_msr, (u32)(-((u64)tsc_khz * 1000 / nmi_hz)), 0);
 
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
@@ -894,7 +894,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
 	 			apic_write(APIC_LVTPC, APIC_DM_NMI);
 				/* start the cycle over again */
 				wrmsrl(wd->perfctr_msr,
-				       -((u64)cpu_khz * 1000 / nmi_hz));
+				       -((u64)tsc_khz * 1000 / nmi_hz));
 	 		} else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
 				/*
 				 * ArchPerfom/Core Duo needs to re-unmask
@@ -903,11 +903,11 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
 				apic_write(APIC_LVTPC, APIC_DM_NMI);
 				/* ARCH_PERFMON has 32 bit counter writes */
 				wrmsr(wd->perfctr_msr,
-				     (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
+				     (u32)(-((u64)tsc_khz * 1000 / nmi_hz)), 0);
 			} else {
 				/* start the cycle over again */
 				wrmsrl(wd->perfctr_msr,
-				       -((u64)cpu_khz * 1000 / nmi_hz));
+				       -((u64)tsc_khz * 1000 / nmi_hz));
 			}
 			rc = 1;
 		} else 	if (nmi_watchdog == NMI_IO_APIC) {
@@ -1003,6 +1003,7 @@ void __trigger_all_cpu_backtrace(void)
 }
 
 EXPORT_SYMBOL(nmi_active);
+EXPORT_SYMBOL(nmi_known_cpu);
 EXPORT_SYMBOL(nmi_watchdog);
 EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
 EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
arch/x86_64/kernel/setup.c +0 -0
arch/x86_64/kernel/time.c +55 -3

87 lines not on this page · raw message

arch/x86_64/kernel/tsc.c +7 -5
index 1a0edbb..5c84992 100644
@@ -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;
arch/x86_64/kernel/tsc_sync.c +1 -1
index 014f0db..72d444d 100644
@@ -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++) {
include/asm-x86_64/nmi.h +1 -0
index ceb3d8d..6b7520c 100644
@@ -46,6 +46,7 @@ extern int unknown_nmi_panic;
 extern int nmi_watchdog_enabled;
 
 extern int check_nmi_watchdog(void);
+extern int nmi_known_cpu(void);
 extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
 extern int avail_to_resrv_perfctr_nmi(unsigned int);
 extern int reserve_perfctr_nmi(unsigned int);
include/asm-x86_64/proto.h +1 -0
index f54f3ab..e0b1fed 100644
@@ -93,6 +93,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;
#1 lore raw
Quoted 9 lines · Joerg Roedel

From: Mark Langsdorf <[email protected]>
From: Joerg Roedel <[email protected]>

This patch fixes the reporting of cpu_mhz in /proc/cpuinfo on CPUs with a constant TSC rate and a kernel with disabled cpufreq.

+ cpu_khz = tsc_khz;
+ if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
+ nmi_known_cpu()) {
+ cpu_khz = tsc_calibrate_cpu_khz();
+ }

I don't think this will do the right thing on Intel CPUs of which tsc_calibrate_cpu_khz() knows nothing about.

-Andi

#2 lore raw
Quoted 18 lines · Andi Kleen
Quoted 9 lines · Joerg Roedel

From: Mark Langsdorf <[email protected]>
From: Joerg Roedel <[email protected]>

This patch fixes the reporting of cpu_mhz in /proc/cpuinfo on CPUs with a constant TSC rate and a kernel with disabled cpufreq.

arch/x86_64/kernel/time.c +5 -0
+       cpu_khz = tsc_khz;
+       if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
+                       nmi_known_cpu()) {
+               cpu_khz = tsc_calibrate_cpu_khz(); 
+       }
Quoted 2 lines

I don't think this will do the right thing on Intel CPUs of which tsc_calibrate_cpu_khz() knows nothing about.

Yes. You are right. I will fix that and send a new version. Thanks for the review.

Joerg

Signature · 3 lines
Joerg Roedel
Operating System Research Center
AMD Saxony LLC & Co. KG
#3 lore raw
Quoted 4 lines

Yes. You are right. I will fix that and send a new version. Thanks for the review.

I already fixed it up and fixed some other bugs. The changes to tsc_khz in nmi.c were wrong because the performance counters don't tick at tsc frequency.

-Andi