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