xref: /dflybsd-src/sys/dev/virtual/hyperv/x86_64/hyperv_machdep.c (revision 31517ca9069dca83e19f06f6be74db195f22acb8)
182b77854SSepherosa Ziehau /*-
282b77854SSepherosa Ziehau  * Copyright (c) 2016 Microsoft Corp.
382b77854SSepherosa Ziehau  * All rights reserved.
482b77854SSepherosa Ziehau  *
582b77854SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
682b77854SSepherosa Ziehau  * modification, are permitted provided that the following conditions
782b77854SSepherosa Ziehau  * are met:
882b77854SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
982b77854SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
1082b77854SSepherosa Ziehau  *    disclaimer.
1182b77854SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
1282b77854SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
1382b77854SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
1482b77854SSepherosa Ziehau  *
1582b77854SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1682b77854SSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1782b77854SSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1882b77854SSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1982b77854SSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2082b77854SSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2182b77854SSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2282b77854SSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2382b77854SSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2482b77854SSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2582b77854SSepherosa Ziehau  */
2682b77854SSepherosa Ziehau 
2782b77854SSepherosa Ziehau #include <sys/param.h>
2882b77854SSepherosa Ziehau #include <sys/systimer.h>
2982b77854SSepherosa Ziehau #include <sys/systm.h>
3082b77854SSepherosa Ziehau 
3182b77854SSepherosa Ziehau #include <machine/cpufunc.h>
3282b77854SSepherosa Ziehau #include <machine/specialreg.h>
3382b77854SSepherosa Ziehau #include <machine/msi_machdep.h>
3482b77854SSepherosa Ziehau 
3582b77854SSepherosa Ziehau #include <dev/virtual/hyperv/hyperv_busdma.h>
3682b77854SSepherosa Ziehau #include <dev/virtual/hyperv/hyperv_machdep.h>
3782b77854SSepherosa Ziehau #include <dev/virtual/hyperv/hyperv_reg.h>
3882b77854SSepherosa Ziehau #include <dev/virtual/hyperv/hyperv_var.h>
3982b77854SSepherosa Ziehau 
4082b77854SSepherosa Ziehau struct hyperv_reftsc_ctx {
4182b77854SSepherosa Ziehau 	struct hyperv_reftsc	*tsc_ref;
4282b77854SSepherosa Ziehau 	struct hyperv_dma	tsc_ref_dma;
4382b77854SSepherosa Ziehau };
4482b77854SSepherosa Ziehau 
4582b77854SSepherosa Ziehau static void		hyperv_tsc_cputimer_construct(struct cputimer *,
4682b77854SSepherosa Ziehau 			    sysclock_t);
4782b77854SSepherosa Ziehau static sysclock_t	hyperv_tsc_cputimer_count_mfence(void);
4882b77854SSepherosa Ziehau static sysclock_t	hyperv_tsc_cputimer_count_lfence(void);
4982b77854SSepherosa Ziehau 
5082b77854SSepherosa Ziehau static struct hyperv_reftsc_ctx	hyperv_ref_tsc;
5182b77854SSepherosa Ziehau static hyperv_tc64_t	hyperv_tc64_saved;
5282b77854SSepherosa Ziehau 
5382b77854SSepherosa Ziehau static struct cputimer	hyperv_tsc_cputimer = {
5482b77854SSepherosa Ziehau 	.next		= SLIST_ENTRY_INITIALIZER,
5582b77854SSepherosa Ziehau 	.name		= "Hyper-V-TSC",
5682b77854SSepherosa Ziehau 	.pri		= CPUTIMER_PRI_VMM_HI,
5782b77854SSepherosa Ziehau 	.type		= CPUTIMER_VMM1,
5882b77854SSepherosa Ziehau 	.count		= NULL,	/* determined later */
5982b77854SSepherosa Ziehau 	.fromhz		= cputimer_default_fromhz,
6082b77854SSepherosa Ziehau 	.fromus		= cputimer_default_fromus,
6182b77854SSepherosa Ziehau 	.construct	= hyperv_tsc_cputimer_construct,
6282b77854SSepherosa Ziehau 	.destruct	= cputimer_default_destruct,
6382b77854SSepherosa Ziehau 	.freq		= HYPERV_TIMER_FREQ
6482b77854SSepherosa Ziehau };
6582b77854SSepherosa Ziehau 
66*31517ca9SSepherosa Ziehau static struct cpucounter hyperv_tsc_cpucounter = {
67*31517ca9SSepherosa Ziehau 	.freq		= HYPERV_TIMER_FREQ,
68*31517ca9SSepherosa Ziehau 	.count		= NULL, /* determined later */
69*31517ca9SSepherosa Ziehau 	.flags		= CPUCOUNTER_FLAG_MPSYNC,
70*31517ca9SSepherosa Ziehau 	.prio		= CPUCOUNTER_PRIO_VMM_HI,
71*31517ca9SSepherosa Ziehau 	.type		= CPUCOUNTER_VMM1
72*31517ca9SSepherosa Ziehau };
73*31517ca9SSepherosa Ziehau 
7482b77854SSepherosa Ziehau uint64_t
hypercall_md(volatile void * hc_addr,uint64_t in_val,uint64_t in_paddr,uint64_t out_paddr)7582b77854SSepherosa Ziehau hypercall_md(volatile void *hc_addr, uint64_t in_val,
7682b77854SSepherosa Ziehau     uint64_t in_paddr, uint64_t out_paddr)
7782b77854SSepherosa Ziehau {
7882b77854SSepherosa Ziehau 	uint64_t status;
7982b77854SSepherosa Ziehau 
8082b77854SSepherosa Ziehau 	__asm__ __volatile__ ("mov %0, %%r8" : : "r" (out_paddr): "r8");
8182b77854SSepherosa Ziehau 	__asm__ __volatile__ ("call *%3" : "=a" (status) :
8282b77854SSepherosa Ziehau 	    "c" (in_val), "d" (in_paddr), "m" (hc_addr));
8382b77854SSepherosa Ziehau 	return (status);
8482b77854SSepherosa Ziehau }
8582b77854SSepherosa Ziehau 
8682b77854SSepherosa Ziehau int
hyperv_msi2vector(uint64_t msi_addr __unused,uint32_t msi_data)8782b77854SSepherosa Ziehau hyperv_msi2vector(uint64_t msi_addr __unused, uint32_t msi_data)
8882b77854SSepherosa Ziehau {
8982b77854SSepherosa Ziehau 	return (msi_data & MSI_X86_DATA_INTVEC);
9082b77854SSepherosa Ziehau }
9182b77854SSepherosa Ziehau 
9282b77854SSepherosa Ziehau #define HYPERV_TSC(fence)					\
9382b77854SSepherosa Ziehau static uint64_t							\
9482b77854SSepherosa Ziehau hyperv_tsc_##fence(void)					\
9582b77854SSepherosa Ziehau {								\
9682b77854SSepherosa Ziehau 	struct hyperv_reftsc *tsc_ref = hyperv_ref_tsc.tsc_ref;	\
9782b77854SSepherosa Ziehau 	uint32_t seq;						\
9882b77854SSepherosa Ziehau 								\
9982b77854SSepherosa Ziehau 	while ((seq = tsc_ref->tsc_seq) != 0) {			\
10082b77854SSepherosa Ziehau 		uint64_t disc, ret, tsc;			\
10182b77854SSepherosa Ziehau 		uint64_t scale;					\
10282b77854SSepherosa Ziehau 		int64_t ofs;					\
10382b77854SSepherosa Ziehau 								\
10482b77854SSepherosa Ziehau 		cpu_ccfence();					\
10582b77854SSepherosa Ziehau 		scale = tsc_ref->tsc_scale;			\
10682b77854SSepherosa Ziehau 		ofs = tsc_ref->tsc_ofs;				\
10782b77854SSepherosa Ziehau 								\
10882b77854SSepherosa Ziehau 		cpu_##fence();					\
10982b77854SSepherosa Ziehau 		tsc = rdtsc();					\
11082b77854SSepherosa Ziehau 								\
11182b77854SSepherosa Ziehau 		/* ret = ((tsc * scale) >> 64) + ofs */		\
11282b77854SSepherosa Ziehau 		__asm__ __volatile__ ("mulq %3" :		\
11382b77854SSepherosa Ziehau 		    "=d" (ret), "=a" (disc) :			\
11482b77854SSepherosa Ziehau 		    "a" (tsc), "r" (scale));			\
11582b77854SSepherosa Ziehau 		ret += ofs;					\
11682b77854SSepherosa Ziehau 								\
11782b77854SSepherosa Ziehau 		cpu_ccfence();					\
11882b77854SSepherosa Ziehau 		if (tsc_ref->tsc_seq == seq)			\
11982b77854SSepherosa Ziehau 			return (ret);				\
12082b77854SSepherosa Ziehau 								\
12182b77854SSepherosa Ziehau 		/* Sequence changed; re-sync. */		\
12282b77854SSepherosa Ziehau 	}							\
12382b77854SSepherosa Ziehau 	/* Fallback to the generic rdmsr. */			\
12482b77854SSepherosa Ziehau 	return (rdmsr(MSR_HV_TIME_REF_COUNT));			\
12582b77854SSepherosa Ziehau }								\
12682b77854SSepherosa Ziehau struct __hack
12782b77854SSepherosa Ziehau 
12882b77854SSepherosa Ziehau HYPERV_TSC(lfence);
12982b77854SSepherosa Ziehau HYPERV_TSC(mfence);
13082b77854SSepherosa Ziehau 
13182b77854SSepherosa Ziehau static sysclock_t
hyperv_tsc_cputimer_count_lfence(void)13282b77854SSepherosa Ziehau hyperv_tsc_cputimer_count_lfence(void)
13382b77854SSepherosa Ziehau {
13482b77854SSepherosa Ziehau 	uint64_t val;
13582b77854SSepherosa Ziehau 
13682b77854SSepherosa Ziehau 	val = hyperv_tsc_lfence();
13782b77854SSepherosa Ziehau 	return (val + hyperv_tsc_cputimer.base);
13882b77854SSepherosa Ziehau }
13982b77854SSepherosa Ziehau 
14082b77854SSepherosa Ziehau static sysclock_t
hyperv_tsc_cputimer_count_mfence(void)14182b77854SSepherosa Ziehau hyperv_tsc_cputimer_count_mfence(void)
14282b77854SSepherosa Ziehau {
14382b77854SSepherosa Ziehau 	uint64_t val;
14482b77854SSepherosa Ziehau 
14582b77854SSepherosa Ziehau 	val = hyperv_tsc_mfence();
14682b77854SSepherosa Ziehau 	return (val + hyperv_tsc_cputimer.base);
14782b77854SSepherosa Ziehau }
14882b77854SSepherosa Ziehau 
14982b77854SSepherosa Ziehau static void
hyperv_tsc_cputimer_construct(struct cputimer * timer,sysclock_t oldclock)15082b77854SSepherosa Ziehau hyperv_tsc_cputimer_construct(struct cputimer *timer, sysclock_t oldclock)
15182b77854SSepherosa Ziehau {
15282b77854SSepherosa Ziehau 	timer->base = 0;
15382b77854SSepherosa Ziehau 	timer->base = oldclock - timer->count();
15482b77854SSepherosa Ziehau }
15582b77854SSepherosa Ziehau 
15682b77854SSepherosa Ziehau void
hyperv_md_init(void)15782b77854SSepherosa Ziehau hyperv_md_init(void)
15882b77854SSepherosa Ziehau {
15982b77854SSepherosa Ziehau 	hyperv_tc64_t tc64 = NULL;
16082b77854SSepherosa Ziehau 	uint64_t val, orig;
16182b77854SSepherosa Ziehau 
16282b77854SSepherosa Ziehau 	if ((hyperv_features &
16382b77854SSepherosa Ziehau 	     (CPUID_HV_MSR_TIME_REFCNT | CPUID_HV_MSR_REFERENCE_TSC)) !=
16482b77854SSepherosa Ziehau 	    (CPUID_HV_MSR_TIME_REFCNT | CPUID_HV_MSR_REFERENCE_TSC) ||
16582b77854SSepherosa Ziehau 	    (cpu_feature & CPUID_SSE2) == 0)	/* SSE2 for mfence/lfence */
16682b77854SSepherosa Ziehau 		return;
16782b77854SSepherosa Ziehau 
16882b77854SSepherosa Ziehau 	switch (cpu_vendor_id) {
16982b77854SSepherosa Ziehau 	case CPU_VENDOR_AMD:
17082b77854SSepherosa Ziehau 		hyperv_tsc_cputimer.count = hyperv_tsc_cputimer_count_mfence;
17182b77854SSepherosa Ziehau 		tc64 = hyperv_tsc_mfence;
17282b77854SSepherosa Ziehau 		break;
17382b77854SSepherosa Ziehau 
17482b77854SSepherosa Ziehau 	case CPU_VENDOR_INTEL:
17582b77854SSepherosa Ziehau 		hyperv_tsc_cputimer.count = hyperv_tsc_cputimer_count_lfence;
17682b77854SSepherosa Ziehau 		tc64 = hyperv_tsc_lfence;
17782b77854SSepherosa Ziehau 		break;
17882b77854SSepherosa Ziehau 
17982b77854SSepherosa Ziehau 	default:
18082b77854SSepherosa Ziehau 		/* Unsupport CPU vendors. */
18182b77854SSepherosa Ziehau 		return;
18282b77854SSepherosa Ziehau 	}
183*31517ca9SSepherosa Ziehau 	KASSERT(tc64 != NULL, ("tc64 is not set"));
184*31517ca9SSepherosa Ziehau 	hyperv_tsc_cpucounter.count = tc64;
18582b77854SSepherosa Ziehau 
18682b77854SSepherosa Ziehau 	hyperv_ref_tsc.tsc_ref = hyperv_dmamem_alloc(NULL, PAGE_SIZE, 0,
18782b77854SSepherosa Ziehau 	    sizeof(struct hyperv_reftsc), &hyperv_ref_tsc.tsc_ref_dma,
18882b77854SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_ZERO);
18982b77854SSepherosa Ziehau 	if (hyperv_ref_tsc.tsc_ref == NULL) {
19082b77854SSepherosa Ziehau 		kprintf("hyperv: reftsc page allocation failed\n");
19182b77854SSepherosa Ziehau 		return;
19282b77854SSepherosa Ziehau 	}
19382b77854SSepherosa Ziehau 
19482b77854SSepherosa Ziehau 	orig = rdmsr(MSR_HV_REFERENCE_TSC);
19582b77854SSepherosa Ziehau 	val = MSR_HV_REFTSC_ENABLE | (orig & MSR_HV_REFTSC_RSVD_MASK) |
19682b77854SSepherosa Ziehau 	    ((hyperv_ref_tsc.tsc_ref_dma.hv_paddr >> PAGE_SHIFT) <<
19782b77854SSepherosa Ziehau 	     MSR_HV_REFTSC_PGSHIFT);
19882b77854SSepherosa Ziehau 	wrmsr(MSR_HV_REFERENCE_TSC, val);
19982b77854SSepherosa Ziehau 
200*31517ca9SSepherosa Ziehau 	/* Register Hyper-V reference TSC cputimers. */
20182b77854SSepherosa Ziehau 	cputimer_register(&hyperv_tsc_cputimer);
20282b77854SSepherosa Ziehau 	cputimer_select(&hyperv_tsc_cputimer, 0);
203*31517ca9SSepherosa Ziehau 	cpucounter_register(&hyperv_tsc_cpucounter);
20482b77854SSepherosa Ziehau 	hyperv_tc64_saved = hyperv_tc64;
20582b77854SSepherosa Ziehau 	hyperv_tc64 = tc64;
20682b77854SSepherosa Ziehau }
20782b77854SSepherosa Ziehau 
20882b77854SSepherosa Ziehau void
hyperv_md_uninit(void)20982b77854SSepherosa Ziehau hyperv_md_uninit(void)
21082b77854SSepherosa Ziehau {
21182b77854SSepherosa Ziehau 	if (hyperv_ref_tsc.tsc_ref != NULL) {
21282b77854SSepherosa Ziehau 		uint64_t val;
21382b77854SSepherosa Ziehau 
21482b77854SSepherosa Ziehau 		/* Deregister Hyper-V reference TSC systimer. */
21582b77854SSepherosa Ziehau 		cputimer_deregister(&hyperv_tsc_cputimer);
21682b77854SSepherosa Ziehau 		/* Revert tc64 change. */
21782b77854SSepherosa Ziehau 		hyperv_tc64 = hyperv_tc64_saved;
21882b77854SSepherosa Ziehau 
21982b77854SSepherosa Ziehau 		val = rdmsr(MSR_HV_REFERENCE_TSC);
22082b77854SSepherosa Ziehau 		wrmsr(MSR_HV_REFERENCE_TSC, val & MSR_HV_REFTSC_RSVD_MASK);
22182b77854SSepherosa Ziehau 
22282b77854SSepherosa Ziehau 		hyperv_dmamem_free(&hyperv_ref_tsc.tsc_ref_dma,
22382b77854SSepherosa Ziehau 		    hyperv_ref_tsc.tsc_ref);
22482b77854SSepherosa Ziehau 		hyperv_ref_tsc.tsc_ref = NULL;
22582b77854SSepherosa Ziehau 	}
22682b77854SSepherosa Ziehau }
227