xref: /titanic_52/usr/src/uts/i86xpv/os/xpv_timestamp.c (revision 263f549e5da8b32c4922f586afb365b8ae388a6c)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev 
22843e1988Sjohnlev /*
23349b53ddSStuart Maybee  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24843e1988Sjohnlev  * Use is subject to license terms.
25*263f549eSPatrick Mooney  * Copyright 2016 Joyent, Inc.
26843e1988Sjohnlev  */
27843e1988Sjohnlev 
28843e1988Sjohnlev #include <sys/types.h>
29843e1988Sjohnlev #include <sys/clock.h>
30843e1988Sjohnlev #include <sys/panic.h>
31843e1988Sjohnlev #include <sys/atomic.h>
32843e1988Sjohnlev #include <sys/hypervisor.h>
33843e1988Sjohnlev 
34843e1988Sjohnlev #include <sys/archsystm.h>
35843e1988Sjohnlev 
36843e1988Sjohnlev /*
37843e1988Sjohnlev  * On the hypervisor, we have a virtualized system time based upon the
38843e1988Sjohnlev  * information provided for each VCPU, which is updated every time it is
39843e1988Sjohnlev  * scheduled onto a real CPU.  Thus, none of the traditional code in
40843e1988Sjohnlev  * i86pc/os/timestamp.c applies, our gethrtime() implementation is run through
41843e1988Sjohnlev  * the PSM, and there is no scaling step to apply.
42843e1988Sjohnlev  *
43843e1988Sjohnlev  * However, the platform does not guarantee monotonicity; thus we have to fake
44843e1988Sjohnlev  * this up, which is a deeply unpleasant thing to have to do.
45843e1988Sjohnlev  *
46843e1988Sjohnlev  * Note that the virtualized interface still relies on the current TSC to
47843e1988Sjohnlev  * calculate the time in nanoseconds since the VCPU was scheduled, and is thus
48843e1988Sjohnlev  * subject to all the problems with that.  For the most part, the hypervisor is
49843e1988Sjohnlev  * supposed to deal with them.
50843e1988Sjohnlev  *
51843e1988Sjohnlev  * Another wrinkle involves suspend/resume/migration.  If we come back and time
52843e1988Sjohnlev  * is apparently less, we may have resumed on a different machine or on the
53843e1988Sjohnlev  * same machine after a reboot.  In this case we need to maintain an addend to
54843e1988Sjohnlev  * ensure time continues reasonably.  Otherwise we could end up taking a very
55843e1988Sjohnlev  * long time to expire cyclics in the heap.  Thus we have two functions:
56843e1988Sjohnlev  *
57843e1988Sjohnlev  * xpv_getsystime()
58843e1988Sjohnlev  *
59843e1988Sjohnlev  *	The unadulterated system time from the hypervisor.  This is only to be
60843e1988Sjohnlev  *	used when programming the hypervisor (setting a timer or calculating
61843e1988Sjohnlev  *	the TOD).
62843e1988Sjohnlev  *
63843e1988Sjohnlev  * xpv_gethrtime()
64843e1988Sjohnlev  *
65843e1988Sjohnlev  *	This is the monotonic hrtime counter to be used by everything else such
66843e1988Sjohnlev  *	as the cyclic subsystem.  We should never pass an hrtime directly into
67843e1988Sjohnlev  *	a hypervisor interface, as hrtime_addend may well be non-zero.
68843e1988Sjohnlev  */
69843e1988Sjohnlev 
70349b53ddSStuart Maybee int hrtime_fake_mt = 1;
71843e1988Sjohnlev static volatile hrtime_t hrtime_last;
72843e1988Sjohnlev static hrtime_t hrtime_suspend_time;
73843e1988Sjohnlev static hrtime_t hrtime_addend;
74843e1988Sjohnlev 
75*263f549eSPatrick Mooney volatile uint32_t hres_lock;
76*263f549eSPatrick Mooney hrtime_t hres_last_tick;
77*263f549eSPatrick Mooney int64_t hrestime_adj;
78*263f549eSPatrick Mooney volatile timestruc_t hrestime;
79*263f549eSPatrick Mooney 
80843e1988Sjohnlev /*
81843e1988Sjohnlev  * These functions are used in DTrace probe context, and must be removed from
82843e1988Sjohnlev  * fbt consideration.  Currently fbt ignores all weak symbols, so this will
83843e1988Sjohnlev  * achieve that.
84843e1988Sjohnlev  */
85843e1988Sjohnlev #pragma weak xpv_gethrtime = dtrace_xpv_gethrtime
86843e1988Sjohnlev #pragma weak xpv_getsystime = dtrace_xpv_getsystime
87843e1988Sjohnlev #pragma weak dtrace_gethrtime = dtrace_xpv_gethrtime
88843e1988Sjohnlev #pragma weak tsc_read = dtrace_xpv_gethrtime
89843e1988Sjohnlev 
90843e1988Sjohnlev hrtime_t
91843e1988Sjohnlev dtrace_xpv_getsystime(void)
92843e1988Sjohnlev {
93843e1988Sjohnlev 	vcpu_time_info_t *src;
94843e1988Sjohnlev 	vcpu_time_info_t __vti, *dst = &__vti;
95843e1988Sjohnlev 	uint64_t tsc_delta;
96843e1988Sjohnlev 	uint64_t tsc;
97843e1988Sjohnlev 	hrtime_t result;
983006ae82SFrank Van Der Linden 	uint32_t stamp;
99843e1988Sjohnlev 
100843e1988Sjohnlev 	src = &CPU->cpu_m.mcpu_vcpu_info->time;
101843e1988Sjohnlev 
102843e1988Sjohnlev 	/*
103843e1988Sjohnlev 	 * Loop until version has not been changed during our update, and a Xen
104843e1988Sjohnlev 	 * update is not under way (lowest bit is set).
105843e1988Sjohnlev 	 */
106843e1988Sjohnlev 	do {
107843e1988Sjohnlev 		dst->version = src->version;
1083006ae82SFrank Van Der Linden 		stamp = CPU->cpu_m.mcpu_istamp;
109843e1988Sjohnlev 
110843e1988Sjohnlev 		membar_consumer();
111843e1988Sjohnlev 
112843e1988Sjohnlev 		dst->tsc_timestamp = src->tsc_timestamp;
113843e1988Sjohnlev 		dst->system_time = src->system_time;
114843e1988Sjohnlev 		dst->tsc_to_system_mul = src->tsc_to_system_mul;
115843e1988Sjohnlev 		dst->tsc_shift = src->tsc_shift;
116843e1988Sjohnlev 
117843e1988Sjohnlev 		/*
118843e1988Sjohnlev 		 * Note that this use of the -actual- TSC register
119843e1988Sjohnlev 		 * should probably be the SOLE one in the system on this
120843e1988Sjohnlev 		 * paravirtualized platform.
121843e1988Sjohnlev 		 */
122843e1988Sjohnlev 		tsc = __rdtsc_insn();
123843e1988Sjohnlev 		tsc_delta = tsc - dst->tsc_timestamp;
124843e1988Sjohnlev 
125843e1988Sjohnlev 		membar_consumer();
126843e1988Sjohnlev 
1273006ae82SFrank Van Der Linden 	} while (((src->version & 1) | (dst->version ^ src->version)) ||
1283006ae82SFrank Van Der Linden 	    CPU->cpu_m.mcpu_istamp != stamp);
129843e1988Sjohnlev 
130843e1988Sjohnlev 	if (dst->tsc_shift >= 0)
131843e1988Sjohnlev 		tsc_delta <<= dst->tsc_shift;
132843e1988Sjohnlev 	else if (dst->tsc_shift < 0)
133843e1988Sjohnlev 		tsc_delta >>= -dst->tsc_shift;
134843e1988Sjohnlev 
135843e1988Sjohnlev 	result = dst->system_time +
136843e1988Sjohnlev 	    ((uint64_t)(tsc_delta * (uint64_t)dst->tsc_to_system_mul) >> 32);
137843e1988Sjohnlev 
138843e1988Sjohnlev 	return (result);
139843e1988Sjohnlev }
140843e1988Sjohnlev 
141843e1988Sjohnlev hrtime_t
142843e1988Sjohnlev dtrace_xpv_gethrtime(void)
143843e1988Sjohnlev {
144843e1988Sjohnlev 	hrtime_t result = xpv_getsystime() + hrtime_addend;
145843e1988Sjohnlev 
146843e1988Sjohnlev 	if (hrtime_fake_mt) {
147843e1988Sjohnlev 		hrtime_t last;
148843e1988Sjohnlev 		do {
149843e1988Sjohnlev 			last = hrtime_last;
150843e1988Sjohnlev 			if (result < last)
151843e1988Sjohnlev 				result = last + 1;
152843e1988Sjohnlev 		} while (atomic_cas_64((volatile uint64_t *)&hrtime_last,
153843e1988Sjohnlev 		    last, result) != last);
154843e1988Sjohnlev 	}
155843e1988Sjohnlev 
156843e1988Sjohnlev 	return (result);
157843e1988Sjohnlev }
158843e1988Sjohnlev 
159843e1988Sjohnlev void
160843e1988Sjohnlev xpv_time_suspend(void)
161843e1988Sjohnlev {
162843e1988Sjohnlev 	hrtime_suspend_time = xpv_getsystime();
163843e1988Sjohnlev }
164843e1988Sjohnlev 
165843e1988Sjohnlev void
166843e1988Sjohnlev xpv_time_resume(void)
167843e1988Sjohnlev {
168843e1988Sjohnlev 	hrtime_t delta = xpv_getsystime() - hrtime_suspend_time;
169843e1988Sjohnlev 
170843e1988Sjohnlev 	if (delta < 0)
171843e1988Sjohnlev 		hrtime_addend += -delta;
172843e1988Sjohnlev }
173