diff options
author | sephe <sephe@FreeBSD.org> | 2017-02-21 02:15:58 +0000 |
---|---|---|
committer | sephe <sephe@FreeBSD.org> | 2017-02-21 02:15:58 +0000 |
commit | 3421658e7a78f61b5da3afde75c88bcfbf419eca (patch) | |
tree | 9a9431f1138aa41acb5fd1dd4dfd6453ae9ae693 /sys/dev/hyperv | |
parent | 2c8109bc38532d079c2863e35eb0ec524fa33754 (diff) | |
download | FreeBSD-src-3421658e7a78f61b5da3afde75c88bcfbf419eca.zip FreeBSD-src-3421658e7a78f61b5da3afde75c88bcfbf419eca.tar.gz |
MFC 311743
hyperv: Add method to read 64bit Hyper-V specific time value.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D9057
Diffstat (limited to 'sys/dev/hyperv')
-rw-r--r-- | sys/dev/hyperv/include/hyperv.h | 12 | ||||
-rw-r--r-- | sys/dev/hyperv/utilities/vmbus_timesync.c | 5 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c | 18 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hyperv.c | 15 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_et.c | 17 |
5 files changed, 50 insertions, 17 deletions
diff --git a/sys/dev/hyperv/include/hyperv.h b/sys/dev/hyperv/include/hyperv.h index 0eda9f0..f0161fc 100644 --- a/sys/dev/hyperv/include/hyperv.h +++ b/sys/dev/hyperv/include/hyperv.h @@ -79,9 +79,17 @@ struct hyperv_guid { #define HYPERV_GUID_STRLEN 40 -int hyperv_guid2str(const struct hyperv_guid *, char *, size_t); +typedef uint64_t (*hyperv_tc64_t)(void); -extern u_int hyperv_features; /* CPUID_HV_MSR_ */ +int hyperv_guid2str(const struct hyperv_guid *, char *, + size_t); + +/* + * hyperv_tc64 could be NULL, if there were no suitable Hyper-V + * specific timecounter. + */ +extern hyperv_tc64_t hyperv_tc64; +extern u_int hyperv_features; /* CPUID_HV_MSR_ */ #endif /* _KERNEL */ diff --git a/sys/dev/hyperv/utilities/vmbus_timesync.c b/sys/dev/hyperv/utilities/vmbus_timesync.c index 7610027..66b1e48 100644 --- a/sys/dev/hyperv/utilities/vmbus_timesync.c +++ b/sys/dev/hyperv/utilities/vmbus_timesync.c @@ -52,8 +52,7 @@ __FBSDID("$FreeBSD$"); VMBUS_ICVER_LE(VMBUS_IC_VERSION(4, 0), (sc)->ic_msgver) #define VMBUS_TIMESYNC_DORTT(sc) \ - (VMBUS_TIMESYNC_MSGVER4((sc)) &&\ - (hyperv_features & CPUID_HV_MSR_TIME_REFCNT)) + (VMBUS_TIMESYNC_MSGVER4((sc)) && hyperv_tc64 != NULL) static int vmbus_timesync_probe(device_t); static int vmbus_timesync_attach(device_t); @@ -117,7 +116,7 @@ vmbus_timesync(struct vmbus_ic_softc *sc, uint64_t hvtime, uint64_t sent_tc, uint64_t hv_ns, vm_ns, rtt = 0; if (VMBUS_TIMESYNC_DORTT(sc)) - rtt = rdmsr(MSR_HV_TIME_REF_COUNT) - sent_tc; + rtt = hyperv_tc64() - sent_tc; hv_ns = (hvtime - VMBUS_ICMSG_TS_BASE + rtt) * HYPERV_TIMER_NS_FACTOR; nanotime(&vm_ts); diff --git a/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c b/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c index cb815bb..d1c1b83 100644 --- a/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c +++ b/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c @@ -133,8 +133,8 @@ hyperv_tsc_vdso_timehands(struct vdso_timehands *vdso_th, } #define HYPERV_TSC_TIMECOUNT(fence) \ -static u_int \ -hyperv_tsc_timecount_##fence(struct timecounter *tc) \ +static uint64_t \ +hyperv_tc64_tsc_##fence(void) \ { \ struct hyperv_reftsc *tsc_ref = hyperv_ref_tsc.tsc_ref; \ uint32_t seq; \ @@ -162,6 +162,13 @@ hyperv_tsc_timecount_##fence(struct timecounter *tc) \ /* Fallback to the generic timecounter, i.e. rdmsr. */ \ return (rdmsr(MSR_HV_TIME_REF_COUNT)); \ } \ + \ +static u_int \ +hyperv_tsc_timecount_##fence(struct timecounter *tc __unused) \ +{ \ + \ + return (hyperv_tc64_tsc_##fence()); \ +} \ struct __hack HYPERV_TSC_TIMECOUNT(lfence); @@ -170,6 +177,7 @@ HYPERV_TSC_TIMECOUNT(mfence); static void hyperv_tsc_tcinit(void *dummy __unused) { + hyperv_tc64_t tc64 = NULL; uint64_t val, orig; if ((hyperv_features & @@ -182,11 +190,13 @@ hyperv_tsc_tcinit(void *dummy __unused) case CPU_VENDOR_AMD: hyperv_tsc_timecounter.tc_get_timecount = hyperv_tsc_timecount_mfence; + tc64 = hyperv_tc64_tsc_mfence; break; case CPU_VENDOR_INTEL: hyperv_tsc_timecounter.tc_get_timecount = hyperv_tsc_timecount_lfence; + tc64 = hyperv_tc64_tsc_lfence; break; default: @@ -211,6 +221,10 @@ hyperv_tsc_tcinit(void *dummy __unused) /* Register "enlightened" timecounter. */ tc_init(&hyperv_tsc_timecounter); + /* Install 64 bits timecounter method for other modules to use. */ + KASSERT(tc64 != NULL, ("tc64 is not set")); + hyperv_tc64 = tc64; + /* Add device for mmap(2). */ make_dev(&hyperv_tsc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0444, HYPERV_REFTSC_DEVNAME); diff --git a/sys/dev/hyperv/vmbus/hyperv.c b/sys/dev/hyperv/vmbus/hyperv.c index 2df313b..144bff5 100644 --- a/sys/dev/hyperv/vmbus/hyperv.c +++ b/sys/dev/hyperv/vmbus/hyperv.c @@ -77,6 +77,8 @@ u_int hyperv_recommends; static u_int hyperv_pm_features; static u_int hyperv_features3; +hyperv_tc64_t hyperv_tc64; + static struct timecounter hyperv_timecounter = { .tc_get_timecount = hyperv_get_timecount, .tc_poll_pps = NULL, @@ -96,6 +98,13 @@ hyperv_get_timecount(struct timecounter *tc __unused) return rdmsr(MSR_HV_TIME_REF_COUNT); } +static uint64_t +hyperv_tc64_rdmsr(void) +{ + + return (rdmsr(MSR_HV_TIME_REF_COUNT)); +} + uint64_t hypercall_post_message(bus_addr_t msg_paddr) { @@ -232,6 +241,12 @@ hyperv_init(void *dummy __unused) if (hyperv_features & CPUID_HV_MSR_TIME_REFCNT) { /* Register Hyper-V timecounter */ tc_init(&hyperv_timecounter); + + /* + * Install 64 bits timecounter method for other modules + * to use. + */ + hyperv_tc64 = hyperv_tc64_rdmsr; } } SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init, diff --git a/sys/dev/hyperv/vmbus/vmbus_et.c b/sys/dev/hyperv/vmbus/vmbus_et.c index feb639c..722e5bf 100644 --- a/sys/dev/hyperv/vmbus/vmbus_et.c +++ b/sys/dev/hyperv/vmbus/vmbus_et.c @@ -48,13 +48,10 @@ __FBSDID("$FreeBSD$"); MSR_HV_STIMER_CFG_SINT_MASK) /* - * Two additionally required features: + * Additionally required feature: * - SynIC is needed for interrupt generation. - * - Time reference counter is needed to set ABS reference count to - * STIMER0_COUNT. */ -#define CPUID_HV_ET_MASK (CPUID_HV_MSR_TIME_REFCNT | \ - CPUID_HV_MSR_SYNIC | \ +#define CPUID_HV_ET_MASK (CPUID_HV_MSR_SYNIC | \ CPUID_HV_MSR_SYNTIMER) static void vmbus_et_identify(driver_t *, device_t); @@ -102,7 +99,7 @@ vmbus_et_start(struct eventtimer *et __unused, sbintime_t first, { uint64_t current; - current = rdmsr(MSR_HV_TIME_REF_COUNT); + current = hyperv_tc64(); current += hyperv_sbintime2count(first); wrmsr(MSR_HV_STIMER0_COUNT, current); @@ -131,7 +128,8 @@ vmbus_et_identify(driver_t *driver, device_t parent) { if (device_get_unit(parent) != 0 || device_find_child(parent, VMBUS_ET_NAME, -1) != NULL || - (hyperv_features & CPUID_HV_ET_MASK) != CPUID_HV_ET_MASK) + (hyperv_features & CPUID_HV_ET_MASK) != CPUID_HV_ET_MASK || + hyperv_tc64 == NULL) return; device_add_child(parent, VMBUS_ET_NAME, -1); @@ -187,9 +185,8 @@ vmbus_et_attach(device_t dev) vmbus_et.et_start = vmbus_et_start; /* - * Delay a bit to make sure that MSR_HV_TIME_REF_COUNT will - * not return 0, since writing 0 to STIMER0_COUNT will disable - * STIMER0. + * Delay a bit to make sure that hyperv_tc64 will not return 0, + * since writing 0 to STIMER0_COUNT will disable STIMER0. */ DELAY(100); smp_rendezvous(NULL, vmbus_et_config, NULL, NULL); |