Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F81970368
D8763.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D8763.diff
View Options
Index: head/sys/dev/hyperv/include/hyperv.h
===================================================================
--- head/sys/dev/hyperv/include/hyperv.h
+++ head/sys/dev/hyperv/include/hyperv.h
@@ -45,6 +45,7 @@
#define CPUID_HV_MSR_HYPERCALL 0x0020 /* MSR_HV_GUEST_OS_ID
* MSR_HV_HYPERCALL */
#define CPUID_HV_MSR_VP_INDEX 0x0040 /* MSR_HV_VP_INDEX */
+#define CPUID_HV_MSR_REFERENCE_TSC 0x0200 /* MSR_HV_REFERENCE_TSC */
#define CPUID_HV_MSR_GUEST_IDLE 0x0400 /* MSR_HV_GUEST_IDLE */
#ifndef NANOSEC
Index: head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
===================================================================
--- head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
+++ head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
@@ -28,7 +28,37 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/timetc.h>
+
+#include <machine/cpufunc.h>
+#include <machine/cputypes.h>
+#include <machine/md_var.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/include/hyperv_busdma.h>
#include <dev/hyperv/vmbus/hyperv_machdep.h>
+#include <dev/hyperv/vmbus/hyperv_reg.h>
+#include <dev/hyperv/vmbus/hyperv_var.h>
+
+struct hyperv_reftsc_ctx {
+ struct hyperv_reftsc *tsc_ref;
+ struct hyperv_dma tsc_ref_dma;
+};
+
+static struct timecounter hyperv_tsc_timecounter = {
+ .tc_get_timecount = NULL, /* based on CPU vendor. */
+ .tc_poll_pps = NULL,
+ .tc_counter_mask = 0xffffffff,
+ .tc_frequency = HYPERV_TIMER_FREQ,
+ .tc_name = "Hyper-V-TSC",
+ .tc_quality = 3000,
+ .tc_flags = 0,
+ .tc_priv = NULL
+};
+
+static struct hyperv_reftsc_ctx hyperv_ref_tsc;
uint64_t
hypercall_md(volatile void *hc_addr, uint64_t in_val,
@@ -41,3 +71,85 @@
"c" (in_val), "d" (in_paddr), "m" (hc_addr));
return (status);
}
+
+#define HYPERV_TSC_TIMECOUNT(fence) \
+static u_int \
+hyperv_tsc_timecount_##fence(struct timecounter *tc) \
+{ \
+ struct hyperv_reftsc *tsc_ref = hyperv_ref_tsc.tsc_ref; \
+ uint32_t seq; \
+ \
+ while ((seq = atomic_load_acq_int(&tsc_ref->tsc_seq)) != 0) { \
+ uint64_t disc, ret, tsc; \
+ uint64_t scale = tsc_ref->tsc_scale; \
+ int64_t ofs = tsc_ref->tsc_ofs; \
+ \
+ fence(); \
+ tsc = rdtsc(); \
+ \
+ /* ret = ((tsc * scale) >> 64) + ofs */ \
+ __asm__ __volatile__ ("mulq %3" : \
+ "=d" (ret), "=a" (disc) : \
+ "a" (tsc), "r" (scale)); \
+ ret += ofs; \
+ \
+ atomic_thread_fence_acq(); \
+ if (tsc_ref->tsc_seq == seq) \
+ return (ret); \
+ \
+ /* Sequence changed; re-sync. */ \
+ } \
+ /* Fallback to the generic timecounter, i.e. rdmsr. */ \
+ return (rdmsr(MSR_HV_TIME_REF_COUNT)); \
+} \
+struct __hack
+
+HYPERV_TSC_TIMECOUNT(lfence);
+HYPERV_TSC_TIMECOUNT(mfence);
+
+static void
+hyperv_tsc_tcinit(void *dummy __unused)
+{
+ uint64_t val, orig;
+
+ if ((hyperv_features &
+ (CPUID_HV_MSR_TIME_REFCNT | CPUID_HV_MSR_REFERENCE_TSC)) !=
+ (CPUID_HV_MSR_TIME_REFCNT | CPUID_HV_MSR_REFERENCE_TSC) ||
+ (cpu_feature & CPUID_SSE2) == 0) /* SSE2 for mfence/lfence */
+ return;
+
+ switch (cpu_vendor_id) {
+ case CPU_VENDOR_AMD:
+ hyperv_tsc_timecounter.tc_get_timecount =
+ hyperv_tsc_timecount_mfence;
+ break;
+
+ case CPU_VENDOR_INTEL:
+ hyperv_tsc_timecounter.tc_get_timecount =
+ hyperv_tsc_timecount_lfence;
+ break;
+
+ default:
+ /* Unsupport CPU vendors. */
+ return;
+ }
+
+ hyperv_ref_tsc.tsc_ref = hyperv_dmamem_alloc(NULL, PAGE_SIZE, 0,
+ sizeof(struct hyperv_reftsc), &hyperv_ref_tsc.tsc_ref_dma,
+ BUS_DMA_WAITOK | BUS_DMA_ZERO);
+ if (hyperv_ref_tsc.tsc_ref == NULL) {
+ printf("hyperv: reftsc page allocation failed\n");
+ return;
+ }
+
+ orig = rdmsr(MSR_HV_REFERENCE_TSC);
+ val = MSR_HV_REFTSC_ENABLE | (orig & MSR_HV_REFTSC_RSVD_MASK) |
+ ((hyperv_ref_tsc.tsc_ref_dma.hv_paddr >> PAGE_SHIFT) <<
+ MSR_HV_REFTSC_PGSHIFT);
+ wrmsr(MSR_HV_REFERENCE_TSC, val);
+
+ /* Register "enlightened" timecounter. */
+ tc_init(&hyperv_tsc_timecounter);
+}
+SYSINIT(hyperv_tsc_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, hyperv_tsc_tcinit,
+ NULL);
Index: head/sys/dev/hyperv/vmbus/hyperv_reg.h
===================================================================
--- head/sys/dev/hyperv/vmbus/hyperv_reg.h
+++ head/sys/dev/hyperv/vmbus/hyperv_reg.h
@@ -57,6 +57,11 @@
#define MSR_HV_VP_INDEX 0x40000002
+#define MSR_HV_REFERENCE_TSC 0x40000021
+#define MSR_HV_REFTSC_ENABLE 0x0001ULL
+#define MSR_HV_REFTSC_RSVD_MASK 0x0ffeULL
+#define MSR_HV_REFTSC_PGSHIFT 12
+
#define MSR_HV_SCONTROL 0x40000080
#define MSR_HV_SCTRL_ENABLE 0x0001ULL
#define MSR_HV_SCTRL_RSVD_MASK 0xfffffffffffffffeULL
@@ -124,6 +129,17 @@
#define CPUID_LEAF_HV_HWFEATURES 0x40000006
/*
+ * Hyper-V Reference TSC
+ */
+struct hyperv_reftsc {
+ volatile uint32_t tsc_seq;
+ volatile uint32_t tsc_rsvd1;
+ volatile uint64_t tsc_scale;
+ volatile int64_t tsc_ofs;
+} __packed __aligned(PAGE_SIZE);
+CTASSERT(sizeof(struct hyperv_reftsc) == PAGE_SIZE);
+
+/*
* Hyper-V Monitor Notification Facility
*/
struct hyperv_mon_param {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Dec 15, 5:34 PM (9 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
9091816
Default Alt Text
D8763.diff (5 KB)
Attached To
Mode
D8763: hyperv: Implement "enlightened" time counter, which is rdtsc based.
Attached
Detach File
Event Timeline
Log In to Comment