xref: /illumos-gate/usr/src/uts/sun4v/sys/machclock.h (revision bd28a477)
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #ifndef _SYS_MACHCLOCK_H
26 #define	_SYS_MACHCLOCK_H
27 
28 #include <sys/intreg.h>
29 
30 #ifdef	__cplusplus
31 extern "C" {
32 #endif
33 
34 /*
35  * Tick/Stick Register Access
36  *
37  * The following assembly language macros are defined for reading
38  * the %tick and %stick registers as well as reading and writing
39  * the stick compare register. With the exception of trapstat, reads
40  * and writes of these registers all take into account an offset
41  * value which is added to the hardware counter. By default, this
42  * offset is zero. The offsets can only be modified when CPUs are
43  * paused and are only intended to be modified during an OS suspend
44  * operation.
45  *
46  * Since the read of the %tick or %stick is not an atomic operation,
47  * it is possible for a suspend operation to occur between the read
48  * of the hardware register and its offset variable. The default
49  * macros here take this into account by comparing the value of the
50  * offset variable before and after reading the hardware register.
51  * Callers that need to read the %tick register and can guarantee
52  * they will not be preempted can use the RD_TICK_NO_SUSPEND_CHECK
53  * which does not check for native_tick_offset changing.
54  */
55 #define	RD_STICK(out, scr1, scr2, label)			\
56 .rd_stick.label:						\
57 	sethi	%hi(native_stick_offset), scr1;			\
58 	ldx	[scr1 + %lo(native_stick_offset)], scr2;	\
59 	rd	STICK, out;					\
60 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
61 	sub	scr1, scr2, scr2;				\
62 /* CSTYLED */							\
63 	brnz,pn	scr2, .rd_stick.label;				\
64 	sllx	out, 1, out;					\
65 	srlx	out, 1, out;					\
66 	add	out, scr1, out
67 
68 /*
69  * These macros on sun4v read the %stick register, because :
70  *
71  * For sun4v platforms %tick can change dynamically *without* kernel
72  * knowledge, due to SP side power & thermal management cases,
73  * which is triggered externally by SP and handled by Hypervisor.
74  *
75  * The frequency of %tick cannot be relied upon by kernel code,
76  * since it changes dynamically without the kernel being aware.
77  * So, always use the constant-frequency %stick on sun4v.
78  */
79 #define	RD_CLOCK_TICK(out, scr1, scr2, label)			\
80 /* CSTYLED */							\
81 	RD_STICK(out,scr1,scr2,label)
82 
83 #define	RD_STICK_NO_SUSPEND_CHECK(out, scr1)			\
84 	sethi	%hi(native_stick_offset), scr1;			\
85 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
86 	rd	STICK, out;					\
87 	sllx	out, 1, out;					\
88 	srlx	out, 1, out;					\
89 	add	out, scr1, out
90 
91 #define	RD_CLOCK_TICK_NO_SUSPEND_CHECK(out, scr1)		\
92 /* CSTYLED */							\
93 	RD_STICK_NO_SUSPEND_CHECK(out,scr1)
94 
95 #ifndef	_ASM
96 #ifdef	_KERNEL
97 extern u_longlong_t gettick(void);
98 #define	CLOCK_TICK_COUNTER()	gettick()	/* returns %stick */
99 #endif	/* _KERNEL */
100 #endif	/* _ASM */
101 
102 
103 #define	RD_TICK(out, scr1, scr2, label)				\
104 .rd_tick.label:							\
105 	sethi	%hi(native_tick_offset), scr1;			\
106 	ldx	[scr1 + %lo(native_tick_offset)], scr2;		\
107 	rd	%tick, out;					\
108 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
109 	sub	scr1, scr2, scr2;				\
110 /* CSTYLED */							\
111 	brnz,pn	scr2, .rd_tick.label;				\
112 	sllx	out, 1, out;					\
113 	srlx	out, 1, out;					\
114 	add	out, scr1, out
115 
116 #define	RD_TICK_NO_SUSPEND_CHECK(out, scr1)			\
117 	sethi	%hi(native_tick_offset), scr1;			\
118 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
119 	rd	%tick, out;					\
120 	sllx	out, 1, out;					\
121 	srlx	out, 1, out;					\
122 	add	out, scr1, out
123 
124 /*
125  * Read the %stick register without taking the native_stick_offset
126  * into account.
127  */
128 #define	RD_STICK_PHYSICAL(out)					\
129 	rd	%stick, out
130 
131 /*
132  * Read the %tick register without taking the native_tick_offset
133  * into account. Required to be a single instruction, usable in a
134  * delay slot.
135  */
136 #define	RD_TICK_PHYSICAL(out)					\
137 	rd	%tick, out
138 
139 /*
140  * For traptrace, which requires either the %tick or %stick
141  * counter depending on the value of a global variable.
142  * If the kernel variable passed in as 'use_stick' is non-zero,
143  * read the %stick counter into the 'out' register, otherwise,
144  * read the %tick counter. Note the label-less branches.
145  * We do not check for the tick or stick offset variables changing
146  * during the course of the macro's execution and as a result
147  * if a suspend operation occurs between the time the offset
148  * variable is read and the hardware register is read, we will
149  * use an inaccurate traptrace timestamp.
150  */
151 #define	RD_TICKSTICK_FLAG(out, scr1, use_stick)			\
152 	sethi	%hi(use_stick), scr1;				\
153 	lduw	[scr1 + %lo(use_stick)], scr1;			\
154 /* CSTYLED */							\
155 	brz,a	scr1, .+24;					\
156 	rd	%tick, out;					\
157 	sethi	%hi(native_stick_offset), scr1;			\
158 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
159 	ba	.+16;						\
160 	rd	STICK, out;					\
161 	sethi	%hi(native_tick_offset), scr1;			\
162 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
163 	sllx	out, 1, out;					\
164 	srlx	out, 1, out;					\
165 	add	out, scr1, out;
166 
167 #define	RD_TICKCMPR(out, scr1, scr2, label)			\
168 .rd_stickcmpr.label: 						\
169 	sethi	%hi(native_stick_offset), scr1;			\
170 	ldx	[scr1 + %lo(native_stick_offset)], scr2;	\
171 	rd	STICK_COMPARE, out;				\
172 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
173 	sub	scr1, scr2, scr2;				\
174 /* CSTYLED */							\
175 	brnz,pn	scr2, .rd_stickcmpr.label;			\
176 	add	out, scr1, out
177 
178 #define	WR_TICKCMPR(in, scr1, scr2, label)			\
179 	sethi	%hi(native_stick_offset), scr1;			\
180 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
181 	sub	in, scr1, scr1;					\
182 	wr	scr1, STICK_COMPARE
183 
184 #define	GET_NATIVE_TIME(out, scr1, scr2, label)			\
185 /* CSTYLED */							\
186 	RD_STICK(out,scr1,scr2,label)
187 
188 /*
189  * Sun4v processors come up with NPT cleared and there is no need to
190  * clear it again. Also, clearing of the NPT cannot be done atomically
191  * on a CMT processor.
192  */
193 #define	CLEARTICKNPT
194 
195 #if defined(CPU_MODULE)
196 
197 /*
198  * Constants used to convert hi-res timestamps into nanoseconds
199  * (see <sys/clock.h> file for more information)
200  */
201 
202 /*
203  * At least 62.5 MHz, for faster %tick-based systems.
204  */
205 #define	NSEC_SHIFT	4
206 
207 /*
208  * NOTE: the macros below assume that the various time-related variables
209  * (hrestime, hrestime_adj, hres_last_tick, timedelta, nsec_scale, etc)
210  * are all stored together on a 64-byte boundary.  The primary motivation
211  * is cache performance, but we also take advantage of a convenient side
212  * effect: these variables all have the same high 22 address bits, so only
213  * one sethi is needed to access them all.
214  */
215 
216 /*
217  * GET_HRESTIME() returns the value of hrestime, hrestime_adj and the
218  * number of nanoseconds since the last clock tick ('nslt').  It also
219  * sets 'nano' to the value NANOSEC (one billion).
220  *
221  * This macro assumes that all registers are globals or outs so they can
222  * safely contain 64-bit data, and that it's safe to use the label "5:".
223  * Further, this macro calls the NATIVE_TIME_TO_NSEC_SCALE which in turn
224  * uses the labels "6:" and "7:"; labels "5:", "6:" and "7:" must not
225  * be used across invocations of this macro.
226  */
227 #define	GET_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano, scr, hrlock, \
228     gnt1, gnt2, label) \
229 5:	sethi	%hi(hres_lock), scr;					\
230 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
231 	lduw	[scr + %lo(nsec_scale)], nano;	/* tick-to-ns factor */	\
232 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
233 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
234 	ldn	[scr + %lo(hrestime)], hrestsec; /* load hrestime.sec */\
235 	add	scr, %lo(hrestime), hrestnsec;				\
236 	ldn	[hrestnsec + CLONGSIZE], hrestnsec;			\
237 /* CSTYLED */ 								\
238 	GET_NATIVE_TIME(adj,gnt1,gnt2,label); /* get current %stick */	\
239 	subcc	adj, nslt, nslt; /* nslt = ticks since last clockint */	\
240 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
241 	ldx	[scr + %lo(hrestime_adj)], adj; /* load hrestime_adj */	\
242 	/* membar #LoadLoad; (see comment (2) above) */			\
243 	lduw	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
244 	NATIVE_TIME_TO_NSEC_SCALE(nslt, nano, gnt1, NSEC_SHIFT);	\
245 	sethi	%hi(NANOSEC), nano;					\
246 	xor	hrlock, scr, scr;					\
247 /* CSTYLED */ 								\
248 	brnz,pn	scr, 5b;						\
249 	or	nano, %lo(NANOSEC), nano;
250 
251 /*
252  * Similar to above, but returns current gethrtime() value in 'base'.
253  */
254 #define	GET_HRTIME(base, now, nslt, scale, scr, hrlock, gnt1, gnt2, label) \
255 5:	sethi	%hi(hres_lock), scr;					\
256 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
257 	lduw	[scr + %lo(nsec_scale)], scale;	/* tick-to-ns factor */	\
258 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
259 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
260 	ldx	[scr + %lo(hrtime_base)], base;	/* load hrtime_base */	\
261 /* CSTYLED */ 								\
262 	GET_NATIVE_TIME(now,gnt1,gnt2,label); /* get current %stick */	\
263 	subcc	now, nslt, nslt; /* nslt = ticks since last clockint */	\
264 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
265 	/* membar #LoadLoad; (see comment (2) above) */			\
266 	ld	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
267 	NATIVE_TIME_TO_NSEC_SCALE(nslt, scale, gnt1, NSEC_SHIFT);	\
268 	xor	hrlock, scr, scr;					\
269 /* CSTYLED */ 								\
270 	brnz,pn	scr, 5b;						\
271 	add	base, nslt, base;
272 
273 #endif /* CPU_MODULE */
274 
275 #ifdef	__cplusplus
276 }
277 #endif
278 
279 #endif	/* !_SYS_MACHCLOCK_H */
280