hyperv: Add method to read 64bit Hyper-V specific time value.
MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D9057
This commit is contained in:
parent
acaa6ff02f
commit
5f62cf7ec4
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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; \
|
||||
@ -161,6 +161,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
|
||||
|
||||
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user