xref: /illumos-gate/usr/src/uts/sun4v/sys/machclock.h (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #ifndef _SYS_MACHCLOCK_H
27 #define	_SYS_MACHCLOCK_H
28 
29 #include <sys/intreg.h>
30 
31 #ifdef	__cplusplus
32 extern "C" {
33 #endif
34 
35 /*
36  * Tick/Stick Register Access
37  *
38  * The following assembly language macros are defined for reading
39  * the %tick and %stick registers as well as reading and writing
40  * the stick compare register. With the exception of trapstat, reads
41  * and writes of these registers all take into account an offset
42  * value which is added to the hardware counter. By default, this
43  * offset is zero. The offsets can only be modified when CPUs are
44  * paused and are only intended to be modified during an OS suspend
45  * operation.
46  *
47  * Since the read of the %tick or %stick is not an atomic operation,
48  * it is possible for a suspend operation to occur between the read
49  * of the hardware register and its offset variable. The default
50  * macros here take this into account by comparing the value of the
51  * offset variable before and after reading the hardware register.
52  * Callers that need to read the %tick register and can guarantee
53  * they will not be preempted can use the RD_TICK_NO_SUSPEND_CHECK
54  * which does not check for native_tick_offset changing.
55  */
56 #define	RD_STICK(out, scr1, scr2, label)			\
57 .rd_stick.label:						\
58 	sethi	%hi(native_stick_offset), scr1;			\
59 	ldx	[scr1 + %lo(native_stick_offset)], scr2;	\
60 	rd	STICK, out;					\
61 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
62 	sub	scr1, scr2, scr2;				\
63 /* CSTYLED */							\
64 	brnz,pn	scr2, .rd_stick.label;				\
65 	sllx	out, 1, out;					\
66 	srlx	out, 1, out;					\
67 	add	out, scr1, out
68 
69 #define	RD_TICK(out, scr1, scr2, label)				\
70 .rd_tick.label:							\
71 	sethi	%hi(native_tick_offset), scr1;			\
72 	ldx	[scr1 + %lo(native_tick_offset)], scr2;		\
73 	rd	%tick, out;					\
74 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
75 	sub	scr1, scr2, scr2;				\
76 /* CSTYLED */							\
77 	brnz,pn	scr2, .rd_tick.label;				\
78 	sllx	out, 1, out;					\
79 	srlx	out, 1, out;					\
80 	add	out, scr1, out
81 
82 #define	RD_TICK_NO_SUSPEND_CHECK(out, scr1)			\
83 	sethi	%hi(native_tick_offset), scr1;			\
84 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
85 	rd	%tick, out;					\
86 	sllx	out, 1, out;					\
87 	srlx	out, 1, out;					\
88 	add	out, scr1, out
89 
90 /*
91  * Read the %stick register without taking the native_stick_offset
92  * into account.
93  */
94 #define	RD_STICK_PHYSICAL(out)					\
95 	rd	%stick, out
96 
97 /*
98  * Read the %tick register without taking the native_tick_offset
99  * into account. Required to be a single instruction, usable in a
100  * delay slot.
101  */
102 #define	RD_TICK_PHYSICAL(out)					\
103 	rd	%tick, out
104 
105 /*
106  * For traptrace, which requires either the %tick or %stick
107  * counter depending on the value of a global variable.
108  * If the kernel variable passed in as 'use_stick' is non-zero,
109  * read the %stick counter into the 'out' register, otherwise,
110  * read the %tick counter. Note the label-less branches.
111  * We do not check for the tick or stick offset variables changing
112  * during the course of the macro's execution and as a result
113  * if a suspend operation occurs between the time the offset
114  * variable is read and the hardware register is read, we will
115  * use an inaccurate traptrace timestamp.
116  */
117 #define	RD_TICKSTICK_FLAG(out, scr1, use_stick)			\
118 	sethi	%hi(use_stick), scr1;				\
119 	lduw	[scr1 + %lo(use_stick)], scr1;			\
120 /* CSTYLED */							\
121 	brz,a	scr1, .+24;					\
122 	rd	%tick, out;					\
123 	sethi	%hi(native_stick_offset), scr1;			\
124 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
125 	ba	.+16;						\
126 	rd	STICK, out;					\
127 	sethi	%hi(native_tick_offset), scr1;			\
128 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
129 	sllx	out, 1, out;					\
130 	srlx	out, 1, out;					\
131 	add	out, scr1, out;
132 
133 #define	RD_TICKCMPR(out, scr1, scr2, label)			\
134 .rd_stickcmpr.label: 						\
135 	sethi	%hi(native_stick_offset), scr1;			\
136 	ldx	[scr1 + %lo(native_stick_offset)], scr2;	\
137 	rd	STICK_COMPARE, out;				\
138 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
139 	sub	scr1, scr2, scr2;				\
140 /* CSTYLED */							\
141 	brnz,pn	scr2, .rd_stickcmpr.label;			\
142 	add	out, scr1, out
143 
144 #define	WR_TICKCMPR(in, scr1, scr2, label)			\
145 	sethi	%hi(native_stick_offset), scr1;			\
146 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
147 	sub	in, scr1, scr1;					\
148 	wr	scr1, STICK_COMPARE
149 
150 #define	GET_NATIVE_TIME(out, scr1, scr2, label)			\
151 /* CSTYLED */							\
152 	RD_STICK(out,scr1,scr2,label)
153 
154 /*
155  * Sun4v processors come up with NPT cleared and there is no need to
156  * clear it again. Also, clearing of the NPT cannot be done atomically
157  * on a CMT processor.
158  */
159 #define	CLEARTICKNPT
160 
161 #if defined(CPU_MODULE)
162 
163 /*
164  * Constants used to convert hi-res timestamps into nanoseconds
165  * (see <sys/clock.h> file for more information)
166  */
167 
168 /*
169  * At least 62.5 MHz, for faster %tick-based systems.
170  */
171 #define	NSEC_SHIFT	4
172 
173 /*
174  * NOTE: the macros below assume that the various time-related variables
175  * (hrestime, hrestime_adj, hres_last_tick, timedelta, nsec_scale, etc)
176  * are all stored together on a 64-byte boundary.  The primary motivation
177  * is cache performance, but we also take advantage of a convenient side
178  * effect: these variables all have the same high 22 address bits, so only
179  * one sethi is needed to access them all.
180  */
181 
182 /*
183  * GET_HRESTIME() returns the value of hrestime, hrestime_adj and the
184  * number of nanoseconds since the last clock tick ('nslt').  It also
185  * sets 'nano' to the value NANOSEC (one billion).
186  *
187  * This macro assumes that all registers are globals or outs so they can
188  * safely contain 64-bit data, and that it's safe to use the label "5:".
189  * Further, this macro calls the NATIVE_TIME_TO_NSEC_SCALE which in turn
190  * uses the labels "6:" and "7:"; labels "5:", "6:" and "7:" must not
191  * be used across invocations of this macro.
192  */
193 #define	GET_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano, scr, hrlock, \
194     gnt1, gnt2, label) \
195 5:	sethi	%hi(hres_lock), scr;					\
196 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
197 	lduw	[scr + %lo(nsec_scale)], nano;	/* tick-to-ns factor */	\
198 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
199 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
200 	ldn	[scr + %lo(hrestime)], hrestsec; /* load hrestime.sec */\
201 	add	scr, %lo(hrestime), hrestnsec;				\
202 	ldn	[hrestnsec + CLONGSIZE], hrestnsec;			\
203 /* CSTYLED */ 								\
204 	GET_NATIVE_TIME(adj,gnt1,gnt2,label); /* get current %stick */	\
205 	subcc	adj, nslt, nslt; /* nslt = ticks since last clockint */	\
206 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
207 	ldx	[scr + %lo(hrestime_adj)], adj; /* load hrestime_adj */	\
208 	/* membar #LoadLoad; (see comment (2) above) */			\
209 	lduw	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
210 	NATIVE_TIME_TO_NSEC_SCALE(nslt, nano, gnt1, NSEC_SHIFT);	\
211 	sethi	%hi(NANOSEC), nano;					\
212 	xor	hrlock, scr, scr;					\
213 /* CSTYLED */ 								\
214 	brnz,pn	scr, 5b;						\
215 	or	nano, %lo(NANOSEC), nano;
216 
217 /*
218  * Similar to above, but returns current gethrtime() value in 'base'.
219  */
220 #define	GET_HRTIME(base, now, nslt, scale, scr, hrlock, gnt1, gnt2, label) \
221 5:	sethi	%hi(hres_lock), scr;					\
222 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
223 	lduw	[scr + %lo(nsec_scale)], scale;	/* tick-to-ns factor */	\
224 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
225 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
226 	ldx	[scr + %lo(hrtime_base)], base;	/* load hrtime_base */	\
227 /* CSTYLED */ 								\
228 	GET_NATIVE_TIME(now,gnt1,gnt2,label); /* get current %stick */	\
229 	subcc	now, nslt, nslt; /* nslt = ticks since last clockint */	\
230 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
231 	/* membar #LoadLoad; (see comment (2) above) */			\
232 	ld	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
233 	NATIVE_TIME_TO_NSEC_SCALE(nslt, scale, gnt1, NSEC_SHIFT);	\
234 	xor	hrlock, scr, scr;					\
235 /* CSTYLED */ 								\
236 	brnz,pn	scr, 5b;						\
237 	add	base, nslt, base;
238 
239 #endif /* CPU_MODULE */
240 
241 #ifdef	__cplusplus
242 }
243 #endif
244 
245 #endif	/* !_SYS_MACHCLOCK_H */
246