From 29b8b410c3e7f7b88499a7de78e0f77cc809818d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 4 Jan 2016 11:28:08 +0100 Subject: [PATCH] inmates: x86: Allow to bypass TSC and APIC timer calibration Make use of the command line feature and introduce the "tsc_freq" and "apic_freq" parameters. When provided, these values are used directly instead of running calibrations against the PM timer. This is particularly useful when running micro-benchmarks that are sensitive to the inherent small variations of the calibrations. Signed-off-by: Jan Kiszka --- inmates/lib/x86/timing.c | 55 +++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/inmates/lib/x86/timing.c b/inmates/lib/x86/timing.c index 9dbf028..4f3890b 100644 --- a/inmates/lib/x86/timing.c +++ b/inmates/lib/x86/timing.c @@ -1,7 +1,7 @@ /* * Jailhouse, a Linux-based partitioning hypervisor * - * Copyright (c) Siemens AG, 2013, 2014 + * Copyright (c) Siemens AG, 2013-2016 * * Authors: * Jan Kiszka @@ -59,18 +59,23 @@ unsigned long tsc_init(void) unsigned long start_pm, end_pm; u64 start_tsc, end_tsc; - start_pm = pm_timer_read(); - start_tsc = rdtsc(); - asm volatile("mfence" : : : "memory"); + tsc_freq = cmdline_parse_int("tsc_freq", 0); - while (pm_timer_read() - start_pm < 100 * NS_PER_MSEC) - cpu_relax(); + if (tsc_freq == 0) { + start_pm = pm_timer_read(); + start_tsc = rdtsc(); + asm volatile("mfence" : : : "memory"); + + while (pm_timer_read() - start_pm < 100 * NS_PER_MSEC) + cpu_relax(); + + end_pm = pm_timer_read(); + end_tsc = rdtsc(); + asm volatile("mfence" : : : "memory"); - end_pm = pm_timer_read(); - end_tsc = rdtsc(); - asm volatile("mfence" : : : "memory"); + tsc_freq = (end_tsc - start_tsc) * NS_PER_SEC / (end_pm - start_pm); + } - tsc_freq = (end_tsc - start_tsc) * NS_PER_SEC / (end_pm - start_pm); tsc_overflow = (0x100000000L * NS_PER_SEC) / tsc_freq; return tsc_freq; @@ -99,26 +104,36 @@ void delay_us(unsigned long microsecs) unsigned long apic_timer_init(unsigned int vector) { + unsigned long long apic_freq; unsigned long start, end; unsigned long tmr; - write_msr(X2APIC_TDCR, 3); + apic_freq = cmdline_parse_int("apic_freq", 0); - start = pm_timer_read(); - write_msr(X2APIC_TMICT, 0xffffffff); + if (apic_freq == 0) { + write_msr(X2APIC_TDCR, 3); - while (pm_timer_read() - start < 100 * NS_PER_MSEC) - cpu_relax(); + start = pm_timer_read(); + write_msr(X2APIC_TMICT, 0xffffffff); + + while (pm_timer_read() - start < 100 * NS_PER_MSEC) + cpu_relax(); + + end = pm_timer_read(); + tmr = read_msr(X2APIC_TMCCT); - end = pm_timer_read(); - tmr = read_msr(X2APIC_TMCCT); + write_msr(X2APIC_TMICT, 0); - divided_apic_freq = (0xffffffffULL - tmr) * NS_PER_SEC / (end - start); + divided_apic_freq = (0xffffffffULL - tmr) * NS_PER_SEC / (end - start); + apic_freq = (divided_apic_freq * 16 + 500) / 1000; + } else { + divided_apic_freq = apic_freq / 16; + apic_freq /= 1000; + } - write_msr(X2APIC_TMICT, 0); write_msr(X2APIC_LVTT, vector); - return (divided_apic_freq * 16 + 500) / 1000; + return apic_freq; } void apic_timer_set(unsigned long timeout_ns) -- 2.39.2