From: Jan Kiszka <[email protected]>

Use the TSC deadline timer when available. This avoids having to
calibrate the APIC timer in those cases.

Signed-off-by: Jan Kiszka <[email protected]>
---
 inmates/lib/x86/timing.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/inmates/lib/x86/timing.c b/inmates/lib/x86/timing.c
index 9bdadae7..61956886 100644
--- a/inmates/lib/x86/timing.c
+++ b/inmates/lib/x86/timing.c
@@ -41,17 +41,21 @@
 #define PM_TIMER_HZ            3579545
 #define PM_TIMER_OVERFLOW      ((0x1000000 * NS_PER_SEC) / PM_TIMER_HZ)
 
+#define IA32_TSC_DEADLINE      0x6e0
+
 #define X2APIC_LVTT            0x832
+# define LVTT_TSC_DEADLINE     (1 << 18)
 #define X2APIC_TMICT           0x838
 #define X2APIC_TMCCT           0x839
 #define X2APIC_TDCR            0x83e
 
-static unsigned long divided_apic_freq;
+static unsigned long apic_tick_freq;
 static unsigned long pm_timer_last[SMP_MAX_CPUS];
 static unsigned long pm_timer_overflows[SMP_MAX_CPUS];
 static unsigned long tsc_freq, tsc_overflow;
 static unsigned long tsc_last[SMP_MAX_CPUS];
 static unsigned long tsc_overflows[SMP_MAX_CPUS];
+static bool tsc_deadline;
 
 static u64 rdtsc(void)
 {
@@ -85,6 +89,9 @@ unsigned long tsc_init(void)
        unsigned long start_pm, end_pm;
        u64 start_tsc, end_tsc;
 
+       if (tsc_freq)
+               return tsc_freq;
+
        tsc_freq = cmdline_parse_int("tsc_freq", 0);
 
        if (tsc_freq == 0) {
@@ -132,11 +139,19 @@ unsigned long apic_timer_init(unsigned int vector)
 {
        unsigned long apic_freq;
        unsigned long start, end;
-       unsigned long tmr;
+       unsigned long tmr, ecx;
 
        apic_freq = cmdline_parse_int("apic_freq", 0);
 
-       if (apic_freq == 0) {
+       asm volatile("cpuid" : "=c" (ecx) : "a" (1)
+               : "rbx", "rdx", "memory");
+       tsc_deadline = !!(ecx & (1 << 24));
+
+       if (tsc_deadline) {
+               vector |= LVTT_TSC_DEADLINE;
+               apic_tick_freq = tsc_init();
+               apic_freq = apic_tick_freq / 1000;
+       } else if (apic_freq == 0) {
                write_msr(X2APIC_TDCR, 3);
 
                start = pm_timer_read();
@@ -150,21 +165,27 @@ unsigned long apic_timer_init(unsigned int vector)
 
                write_msr(X2APIC_TMICT, 0);
 
-               divided_apic_freq = (0xffffffffULL - tmr) * NS_PER_SEC / (end - 
start);
-               apic_freq = (divided_apic_freq * 16 + 500) / 1000;
+               apic_tick_freq = (0xffffffffULL - tmr) * NS_PER_SEC / (end - 
start);
+               apic_freq = (apic_tick_freq * 16 + 500) / 1000;
        } else {
-               divided_apic_freq = apic_freq / 16;
+               apic_tick_freq = apic_freq / 16;
                apic_freq /= 1000;
        }
 
        write_msr(X2APIC_LVTT, vector);
 
+       /* Required when using TSC deadline mode. */
+       asm volatile("mfence" : : : "memory");
+
        return apic_freq;
 }
 
 void apic_timer_set(unsigned long timeout_ns)
 {
        unsigned long long ticks =
-               (unsigned long long)timeout_ns * divided_apic_freq;
-       write_msr(X2APIC_TMICT, ticks / NS_PER_SEC);
+               (unsigned long long)timeout_ns * apic_tick_freq / NS_PER_SEC;
+       if (tsc_deadline)
+               write_msr(IA32_TSC_DEADLINE, rdtsc() + ticks);
+       else
+               write_msr(X2APIC_TMICT, ticks);
 }
-- 
2.12.3

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to