When running on Hyper-V, make use of its timecounter as delay func in case
authorpatrick <patrick@openbsd.org>
Tue, 31 Aug 2021 15:52:10 +0000 (15:52 +0000)
committerpatrick <patrick@openbsd.org>
Tue, 31 Aug 2021 15:52:10 +0000 (15:52 +0000)
we're still using the i8254 for that.  On Hyper-V Gen 2 VMs there is no
i8254 we can trust, so we need some kind of fallback, especially if there
is no TSC either.

Discussed with the hackroom
ok kettenis@

sys/dev/pv/hyperv.c
sys/dev/pv/pvbus.c

index de753cc..dcebd3a 100644 (file)
@@ -349,6 +349,18 @@ hv_gettime(struct timecounter *tc)
        return (now);
 }
 
+void
+hv_delay(int usecs)
+{
+       uint64_t interval, start;
+
+       /* 10 MHz fixed frequency */
+       interval = (uint64_t)usecs * 10;
+       start = rdmsr(MSR_HV_TIME_REF_COUNT);
+       while (rdmsr(MSR_HV_TIME_REF_COUNT) - start < interval)
+               CPU_BUSY_CYCLE();
+}
+
 int
 hv_init_hypercall(struct hv_softc *sc)
 {
index 19098a2..b7bbe91 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pvbus.c,v 1.22 2020/08/26 03:29:06 visa Exp $ */
+/*     $OpenBSD: pvbus.c,v 1.23 2021/08/31 15:52:10 patrick Exp $      */
 
 /*
  * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -40,6 +40,9 @@
 
 #include <dev/pv/pvvar.h>
 #include <dev/pv/pvreg.h>
+#include <dev/pv/hypervreg.h>
+
+#include "hyperv.h"
 
 int has_hv_cpuid = 0;
 
@@ -297,6 +300,8 @@ pvbus_kvm(struct pvbus_hv *hv)
        hv->hv_features = regs[0];
 }
 
+extern void hv_delay(int usecs);
+
 void
 pvbus_hyperv(struct pvbus_hv *hv)
 {
@@ -312,6 +317,12 @@ pvbus_hyperv(struct pvbus_hv *hv)
            HYPERV_VERSION_EBX_MAJOR_S;
        hv->hv_minor = (regs[1] & HYPERV_VERSION_EBX_MINOR_M) >>
            HYPERV_VERSION_EBX_MINOR_S;
+
+#if NHYPERV > 0
+       if (hv->hv_features & CPUID_HV_MSR_TIME_REFCNT &&
+           delay_func == i8254_delay)
+               delay_func = hv_delay;
+#endif
 }
 
 void