[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 <mark.langsdorf@amd.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Andi Kleen <ak@suse.de> 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(-)
This commit is contained in:
parent
fbc16f2c2a
commit
6b37f5a20c
@ -843,7 +843,7 @@ static int __init calibrate_APIC_clock(void)
|
|||||||
} while ((tsc - tsc_start) < TICK_COUNT &&
|
} while ((tsc - tsc_start) < TICK_COUNT &&
|
||||||
(apic - apic_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);
|
(tsc - tsc_start);
|
||||||
}
|
}
|
||||||
printk("result %d\n", result);
|
printk("result %d\n", result);
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <asm/hpet.h>
|
#include <asm/hpet.h>
|
||||||
#include <asm/mpspec.h>
|
#include <asm/mpspec.h>
|
||||||
|
#include <asm/nmi.h>
|
||||||
|
|
||||||
static char *timename = NULL;
|
static char *timename = NULL;
|
||||||
|
|
||||||
@ -249,6 +250,51 @@ static unsigned long get_cmos_time(void)
|
|||||||
return mktime(year, mon, day, hour, min, sec);
|
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
|
* pit_calibrate_tsc() uses the speaker output (channel 2) of
|
||||||
@ -336,14 +382,20 @@ void __init time_init(void)
|
|||||||
if (hpet_use_timer) {
|
if (hpet_use_timer) {
|
||||||
/* set tick_nsec to use the proper rate for HPET */
|
/* set tick_nsec to use the proper rate for HPET */
|
||||||
tick_nsec = TICK_NSEC_HPET;
|
tick_nsec = TICK_NSEC_HPET;
|
||||||
cpu_khz = hpet_calibrate_tsc();
|
tsc_khz = hpet_calibrate_tsc();
|
||||||
timename = "HPET";
|
timename = "HPET";
|
||||||
} else {
|
} else {
|
||||||
pit_init();
|
pit_init();
|
||||||
cpu_khz = pit_calibrate_tsc();
|
tsc_khz = pit_calibrate_tsc();
|
||||||
timename = "PIT";
|
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())
|
if (unsynchronized_tsc())
|
||||||
mark_tsc_unstable();
|
mark_tsc_unstable();
|
||||||
|
|
||||||
@ -352,7 +404,7 @@ void __init time_init(void)
|
|||||||
else
|
else
|
||||||
vgetcpu_mode = VGETCPU_LSL;
|
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",
|
printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
|
||||||
cpu_khz / 1000, cpu_khz % 1000);
|
cpu_khz / 1000, cpu_khz % 1000);
|
||||||
init_tsc_clocksource();
|
init_tsc_clocksource();
|
||||||
|
@ -13,6 +13,8 @@ static int notsc __initdata = 0;
|
|||||||
|
|
||||||
unsigned int cpu_khz; /* TSC clocks / usec, not used here */
|
unsigned int cpu_khz; /* TSC clocks / usec, not used here */
|
||||||
EXPORT_SYMBOL(cpu_khz);
|
EXPORT_SYMBOL(cpu_khz);
|
||||||
|
unsigned int tsc_khz;
|
||||||
|
EXPORT_SYMBOL(tsc_khz);
|
||||||
|
|
||||||
static unsigned int cyc2ns_scale __read_mostly;
|
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 int ref_freq = 0;
|
||||||
static unsigned long loops_per_jiffy_ref = 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,
|
static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
||||||
void *data)
|
void *data)
|
||||||
@ -99,7 +101,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
|||||||
if (!ref_freq) {
|
if (!ref_freq) {
|
||||||
ref_freq = freq->old;
|
ref_freq = freq->old;
|
||||||
loops_per_jiffy_ref = *lpj;
|
loops_per_jiffy_ref = *lpj;
|
||||||
cpu_khz_ref = cpu_khz;
|
tsc_khz_ref = tsc_khz;
|
||||||
}
|
}
|
||||||
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
|
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
|
||||||
(val == CPUFREQ_POSTCHANGE && 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 =
|
*lpj =
|
||||||
cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
|
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))
|
if (!(freq->flags & CPUFREQ_CONST_LOOPS))
|
||||||
mark_tsc_unstable();
|
mark_tsc_unstable();
|
||||||
}
|
}
|
||||||
|
|
||||||
set_cyc2ns_scale(cpu_khz_ref);
|
set_cyc2ns_scale(tsc_khz_ref);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -213,7 +215,7 @@ EXPORT_SYMBOL_GPL(mark_tsc_unstable);
|
|||||||
void __init init_tsc_clocksource(void)
|
void __init init_tsc_clocksource(void)
|
||||||
{
|
{
|
||||||
if (!notsc) {
|
if (!notsc) {
|
||||||
clocksource_tsc.mult = clocksource_khz2mult(cpu_khz,
|
clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
|
||||||
clocksource_tsc.shift);
|
clocksource_tsc.shift);
|
||||||
if (check_tsc_unstable())
|
if (check_tsc_unstable())
|
||||||
clocksource_tsc.rating = 0;
|
clocksource_tsc.rating = 0;
|
||||||
|
@ -50,7 +50,7 @@ static __cpuinit void check_tsc_warp(void)
|
|||||||
/*
|
/*
|
||||||
* The measurement runs for 20 msecs:
|
* The measurement runs for 20 msecs:
|
||||||
*/
|
*/
|
||||||
end = start + cpu_khz * 20ULL;
|
end = start + tsc_khz * 20ULL;
|
||||||
now = start;
|
now = start;
|
||||||
|
|
||||||
for (i = 0; ; i++) {
|
for (i = 0; ; i++) {
|
||||||
|
@ -92,6 +92,7 @@ extern unsigned long table_start, table_end;
|
|||||||
|
|
||||||
extern int exception_trace;
|
extern int exception_trace;
|
||||||
extern unsigned cpu_khz;
|
extern unsigned cpu_khz;
|
||||||
|
extern unsigned tsc_khz;
|
||||||
|
|
||||||
extern void no_iommu_init(void);
|
extern void no_iommu_init(void);
|
||||||
extern int force_iommu, no_iommu;
|
extern int force_iommu, no_iommu;
|
||||||
|
Loading…
Reference in New Issue
Block a user