xref: /illumos-gate/usr/src/uts/sun4v/sys/machclock.h (revision bd28a477)
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
5023e71deSHaik Aftandilian  * Common Development and Distribution License (the "License").
6023e71deSHaik 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*bd28a477SPrashanth Sreenivasa  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #ifndef _SYS_MACHCLOCK_H
267c478bd9Sstevel@tonic-gate #define	_SYS_MACHCLOCK_H
277c478bd9Sstevel@tonic-gate 
28023e71deSHaik Aftandilian #include <sys/intreg.h>
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
317c478bd9Sstevel@tonic-gate extern "C" {
327c478bd9Sstevel@tonic-gate #endif
337c478bd9Sstevel@tonic-gate 
34023e71deSHaik Aftandilian /*
35023e71deSHaik Aftandilian  * Tick/Stick Register Access
36023e71deSHaik Aftandilian  *
37023e71deSHaik Aftandilian  * The following assembly language macros are defined for reading
38023e71deSHaik Aftandilian  * the %tick and %stick registers as well as reading and writing
39023e71deSHaik Aftandilian  * the stick compare register. With the exception of trapstat, reads
40023e71deSHaik Aftandilian  * and writes of these registers all take into account an offset
41023e71deSHaik Aftandilian  * value which is added to the hardware counter. By default, this
42023e71deSHaik Aftandilian  * offset is zero. The offsets can only be modified when CPUs are
43023e71deSHaik Aftandilian  * paused and are only intended to be modified during an OS suspend
44023e71deSHaik Aftandilian  * operation.
45023e71deSHaik Aftandilian  *
46023e71deSHaik Aftandilian  * Since the read of the %tick or %stick is not an atomic operation,
47023e71deSHaik Aftandilian  * it is possible for a suspend operation to occur between the read
48023e71deSHaik Aftandilian  * of the hardware register and its offset variable. The default
49023e71deSHaik Aftandilian  * macros here take this into account by comparing the value of the
50023e71deSHaik Aftandilian  * offset variable before and after reading the hardware register.
51023e71deSHaik Aftandilian  * Callers that need to read the %tick register and can guarantee
52023e71deSHaik Aftandilian  * they will not be preempted can use the RD_TICK_NO_SUSPEND_CHECK
53023e71deSHaik Aftandilian  * which does not check for native_tick_offset changing.
54023e71deSHaik Aftandilian  */
55023e71deSHaik Aftandilian #define	RD_STICK(out, scr1, scr2, label)			\
56023e71deSHaik Aftandilian .rd_stick.label:						\
57023e71deSHaik Aftandilian 	sethi	%hi(native_stick_offset), scr1;			\
58023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_stick_offset)], scr2;	\
59023e71deSHaik Aftandilian 	rd	STICK, out;					\
60023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
61023e71deSHaik Aftandilian 	sub	scr1, scr2, scr2;				\
62023e71deSHaik Aftandilian /* CSTYLED */							\
63023e71deSHaik Aftandilian 	brnz,pn	scr2, .rd_stick.label;				\
64023e71deSHaik Aftandilian 	sllx	out, 1, out;					\
65023e71deSHaik Aftandilian 	srlx	out, 1, out;					\
66023e71deSHaik Aftandilian 	add	out, scr1, out
67023e71deSHaik Aftandilian 
68*bd28a477SPrashanth Sreenivasa /*
69*bd28a477SPrashanth Sreenivasa  * These macros on sun4v read the %stick register, because :
70*bd28a477SPrashanth Sreenivasa  *
71*bd28a477SPrashanth Sreenivasa  * For sun4v platforms %tick can change dynamically *without* kernel
72*bd28a477SPrashanth Sreenivasa  * knowledge, due to SP side power & thermal management cases,
73*bd28a477SPrashanth Sreenivasa  * which is triggered externally by SP and handled by Hypervisor.
74*bd28a477SPrashanth Sreenivasa  *
75*bd28a477SPrashanth Sreenivasa  * The frequency of %tick cannot be relied upon by kernel code,
76*bd28a477SPrashanth Sreenivasa  * since it changes dynamically without the kernel being aware.
77*bd28a477SPrashanth Sreenivasa  * So, always use the constant-frequency %stick on sun4v.
78*bd28a477SPrashanth Sreenivasa  */
79*bd28a477SPrashanth Sreenivasa #define	RD_CLOCK_TICK(out, scr1, scr2, label)			\
80*bd28a477SPrashanth Sreenivasa /* CSTYLED */							\
81*bd28a477SPrashanth Sreenivasa 	RD_STICK(out,scr1,scr2,label)
82*bd28a477SPrashanth Sreenivasa 
83*bd28a477SPrashanth Sreenivasa #define	RD_STICK_NO_SUSPEND_CHECK(out, scr1)			\
84*bd28a477SPrashanth Sreenivasa 	sethi	%hi(native_stick_offset), scr1;			\
85*bd28a477SPrashanth Sreenivasa 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
86*bd28a477SPrashanth Sreenivasa 	rd	STICK, out;					\
87*bd28a477SPrashanth Sreenivasa 	sllx	out, 1, out;					\
88*bd28a477SPrashanth Sreenivasa 	srlx	out, 1, out;					\
89*bd28a477SPrashanth Sreenivasa 	add	out, scr1, out
90*bd28a477SPrashanth Sreenivasa 
91*bd28a477SPrashanth Sreenivasa #define	RD_CLOCK_TICK_NO_SUSPEND_CHECK(out, scr1)		\
92*bd28a477SPrashanth Sreenivasa /* CSTYLED */							\
93*bd28a477SPrashanth Sreenivasa 	RD_STICK_NO_SUSPEND_CHECK(out,scr1)
94*bd28a477SPrashanth Sreenivasa 
95*bd28a477SPrashanth Sreenivasa #ifndef	_ASM
96*bd28a477SPrashanth Sreenivasa #ifdef	_KERNEL
97*bd28a477SPrashanth Sreenivasa extern u_longlong_t gettick(void);
98*bd28a477SPrashanth Sreenivasa #define	CLOCK_TICK_COUNTER()	gettick()	/* returns %stick */
99*bd28a477SPrashanth Sreenivasa #endif	/* _KERNEL */
100*bd28a477SPrashanth Sreenivasa #endif	/* _ASM */
101*bd28a477SPrashanth Sreenivasa 
102*bd28a477SPrashanth Sreenivasa 
103023e71deSHaik Aftandilian #define	RD_TICK(out, scr1, scr2, label)				\
104023e71deSHaik Aftandilian .rd_tick.label:							\
105023e71deSHaik Aftandilian 	sethi	%hi(native_tick_offset), scr1;			\
106023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_tick_offset)], scr2;		\
107023e71deSHaik Aftandilian 	rd	%tick, out;					\
108023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
109023e71deSHaik Aftandilian 	sub	scr1, scr2, scr2;				\
110023e71deSHaik Aftandilian /* CSTYLED */							\
111023e71deSHaik Aftandilian 	brnz,pn	scr2, .rd_tick.label;				\
112023e71deSHaik Aftandilian 	sllx	out, 1, out;					\
113023e71deSHaik Aftandilian 	srlx	out, 1, out;					\
114023e71deSHaik Aftandilian 	add	out, scr1, out
115023e71deSHaik Aftandilian 
116023e71deSHaik Aftandilian #define	RD_TICK_NO_SUSPEND_CHECK(out, scr1)			\
117023e71deSHaik Aftandilian 	sethi	%hi(native_tick_offset), scr1;			\
118023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
119023e71deSHaik Aftandilian 	rd	%tick, out;					\
120023e71deSHaik Aftandilian 	sllx	out, 1, out;					\
121023e71deSHaik Aftandilian 	srlx	out, 1, out;					\
122023e71deSHaik Aftandilian 	add	out, scr1, out
123023e71deSHaik Aftandilian 
124023e71deSHaik Aftandilian /*
125023e71deSHaik Aftandilian  * Read the %stick register without taking the native_stick_offset
126023e71deSHaik Aftandilian  * into account.
127023e71deSHaik Aftandilian  */
128023e71deSHaik Aftandilian #define	RD_STICK_PHYSICAL(out)					\
129023e71deSHaik Aftandilian 	rd	%stick, out
130023e71deSHaik Aftandilian 
131023e71deSHaik Aftandilian /*
132023e71deSHaik Aftandilian  * Read the %tick register without taking the native_tick_offset
133023e71deSHaik Aftandilian  * into account. Required to be a single instruction, usable in a
134023e71deSHaik Aftandilian  * delay slot.
135023e71deSHaik Aftandilian  */
136023e71deSHaik Aftandilian #define	RD_TICK_PHYSICAL(out)					\
137023e71deSHaik Aftandilian 	rd	%tick, out
138023e71deSHaik Aftandilian 
139023e71deSHaik Aftandilian /*
140023e71deSHaik Aftandilian  * For traptrace, which requires either the %tick or %stick
141023e71deSHaik Aftandilian  * counter depending on the value of a global variable.
142023e71deSHaik Aftandilian  * If the kernel variable passed in as 'use_stick' is non-zero,
143023e71deSHaik Aftandilian  * read the %stick counter into the 'out' register, otherwise,
144023e71deSHaik Aftandilian  * read the %tick counter. Note the label-less branches.
145023e71deSHaik Aftandilian  * We do not check for the tick or stick offset variables changing
146023e71deSHaik Aftandilian  * during the course of the macro's execution and as a result
147023e71deSHaik Aftandilian  * if a suspend operation occurs between the time the offset
148023e71deSHaik Aftandilian  * variable is read and the hardware register is read, we will
149023e71deSHaik Aftandilian  * use an inaccurate traptrace timestamp.
150023e71deSHaik Aftandilian  */
151023e71deSHaik Aftandilian #define	RD_TICKSTICK_FLAG(out, scr1, use_stick)			\
152023e71deSHaik Aftandilian 	sethi	%hi(use_stick), scr1;				\
153023e71deSHaik Aftandilian 	lduw	[scr1 + %lo(use_stick)], scr1;			\
154023e71deSHaik Aftandilian /* CSTYLED */							\
155023e71deSHaik Aftandilian 	brz,a	scr1, .+24;					\
156023e71deSHaik Aftandilian 	rd	%tick, out;					\
157023e71deSHaik Aftandilian 	sethi	%hi(native_stick_offset), scr1;			\
158023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
159023e71deSHaik Aftandilian 	ba	.+16;						\
160023e71deSHaik Aftandilian 	rd	STICK, out;					\
161023e71deSHaik Aftandilian 	sethi	%hi(native_tick_offset), scr1;			\
162023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_tick_offset)], scr1;		\
163023e71deSHaik Aftandilian 	sllx	out, 1, out;					\
164023e71deSHaik Aftandilian 	srlx	out, 1, out;					\
165023e71deSHaik Aftandilian 	add	out, scr1, out;
166023e71deSHaik Aftandilian 
167023e71deSHaik Aftandilian #define	RD_TICKCMPR(out, scr1, scr2, label)			\
168023e71deSHaik Aftandilian .rd_stickcmpr.label: 						\
169023e71deSHaik Aftandilian 	sethi	%hi(native_stick_offset), scr1;			\
170023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_stick_offset)], scr2;	\
171023e71deSHaik Aftandilian 	rd	STICK_COMPARE, out;				\
172023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
173023e71deSHaik Aftandilian 	sub	scr1, scr2, scr2;				\
174023e71deSHaik Aftandilian /* CSTYLED */							\
175023e71deSHaik Aftandilian 	brnz,pn	scr2, .rd_stickcmpr.label;			\
176023e71deSHaik Aftandilian 	add	out, scr1, out
177023e71deSHaik Aftandilian 
178023e71deSHaik Aftandilian #define	WR_TICKCMPR(in, scr1, scr2, label)			\
179023e71deSHaik Aftandilian 	sethi	%hi(native_stick_offset), scr1;			\
180023e71deSHaik Aftandilian 	ldx	[scr1 + %lo(native_stick_offset)], scr1;	\
181023e71deSHaik Aftandilian 	sub	in, scr1, scr1;					\
182023e71deSHaik Aftandilian 	wr	scr1, STICK_COMPARE
183023e71deSHaik Aftandilian 
184023e71deSHaik Aftandilian #define	GET_NATIVE_TIME(out, scr1, scr2, label)			\
185023e71deSHaik Aftandilian /* CSTYLED */							\
186023e71deSHaik Aftandilian 	RD_STICK(out,scr1,scr2,label)
187023e71deSHaik Aftandilian 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * Sun4v processors come up with NPT cleared and there is no need to
1907c478bd9Sstevel@tonic-gate  * clear it again. Also, clearing of the NPT cannot be done atomically
1917c478bd9Sstevel@tonic-gate  * on a CMT processor.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate #define	CLEARTICKNPT
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate #if defined(CPU_MODULE)
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * Constants used to convert hi-res timestamps into nanoseconds
1997c478bd9Sstevel@tonic-gate  * (see <sys/clock.h> file for more information)
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * At least 62.5 MHz, for faster %tick-based systems.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate #define	NSEC_SHIFT	4
206023e71deSHaik Aftandilian 
207023e71deSHaik Aftandilian /*
208023e71deSHaik Aftandilian  * NOTE: the macros below assume that the various time-related variables
209023e71deSHaik Aftandilian  * (hrestime, hrestime_adj, hres_last_tick, timedelta, nsec_scale, etc)
210023e71deSHaik Aftandilian  * are all stored together on a 64-byte boundary.  The primary motivation
211023e71deSHaik Aftandilian  * is cache performance, but we also take advantage of a convenient side
212023e71deSHaik Aftandilian  * effect: these variables all have the same high 22 address bits, so only
213023e71deSHaik Aftandilian  * one sethi is needed to access them all.
214023e71deSHaik Aftandilian  */
215023e71deSHaik Aftandilian 
216023e71deSHaik Aftandilian /*
217023e71deSHaik Aftandilian  * GET_HRESTIME() returns the value of hrestime, hrestime_adj and the
218023e71deSHaik Aftandilian  * number of nanoseconds since the last clock tick ('nslt').  It also
219023e71deSHaik Aftandilian  * sets 'nano' to the value NANOSEC (one billion).
220023e71deSHaik Aftandilian  *
221023e71deSHaik Aftandilian  * This macro assumes that all registers are globals or outs so they can
222023e71deSHaik Aftandilian  * safely contain 64-bit data, and that it's safe to use the label "5:".
223023e71deSHaik Aftandilian  * Further, this macro calls the NATIVE_TIME_TO_NSEC_SCALE which in turn
224023e71deSHaik Aftandilian  * uses the labels "6:" and "7:"; labels "5:", "6:" and "7:" must not
225023e71deSHaik Aftandilian  * be used across invocations of this macro.
226023e71deSHaik Aftandilian  */
227023e71deSHaik Aftandilian #define	GET_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano, scr, hrlock, \
228023e71deSHaik Aftandilian     gnt1, gnt2, label) \
229023e71deSHaik Aftandilian 5:	sethi	%hi(hres_lock), scr;					\
230023e71deSHaik Aftandilian 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
231023e71deSHaik Aftandilian 	lduw	[scr + %lo(nsec_scale)], nano;	/* tick-to-ns factor */	\
232023e71deSHaik Aftandilian 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
233023e71deSHaik Aftandilian 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
234023e71deSHaik Aftandilian 	ldn	[scr + %lo(hrestime)], hrestsec; /* load hrestime.sec */\
235023e71deSHaik Aftandilian 	add	scr, %lo(hrestime), hrestnsec;				\
236023e71deSHaik Aftandilian 	ldn	[hrestnsec + CLONGSIZE], hrestnsec;			\
237023e71deSHaik Aftandilian /* CSTYLED */ 								\
238023e71deSHaik Aftandilian 	GET_NATIVE_TIME(adj,gnt1,gnt2,label); /* get current %stick */	\
239023e71deSHaik Aftandilian 	subcc	adj, nslt, nslt; /* nslt = ticks since last clockint */	\
240023e71deSHaik Aftandilian 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
241023e71deSHaik Aftandilian 	ldx	[scr + %lo(hrestime_adj)], adj; /* load hrestime_adj */	\
242023e71deSHaik Aftandilian 	/* membar #LoadLoad; (see comment (2) above) */			\
243023e71deSHaik Aftandilian 	lduw	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
244023e71deSHaik Aftandilian 	NATIVE_TIME_TO_NSEC_SCALE(nslt, nano, gnt1, NSEC_SHIFT);	\
245023e71deSHaik Aftandilian 	sethi	%hi(NANOSEC), nano;					\
246023e71deSHaik Aftandilian 	xor	hrlock, scr, scr;					\
247023e71deSHaik Aftandilian /* CSTYLED */ 								\
248023e71deSHaik Aftandilian 	brnz,pn	scr, 5b;						\
249023e71deSHaik Aftandilian 	or	nano, %lo(NANOSEC), nano;
250023e71deSHaik Aftandilian 
251023e71deSHaik Aftandilian /*
252023e71deSHaik Aftandilian  * Similar to above, but returns current gethrtime() value in 'base'.
253023e71deSHaik Aftandilian  */
254023e71deSHaik Aftandilian #define	GET_HRTIME(base, now, nslt, scale, scr, hrlock, gnt1, gnt2, label) \
255023e71deSHaik Aftandilian 5:	sethi	%hi(hres_lock), scr;					\
256023e71deSHaik Aftandilian 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
257023e71deSHaik Aftandilian 	lduw	[scr + %lo(nsec_scale)], scale;	/* tick-to-ns factor */	\
258023e71deSHaik Aftandilian 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
259023e71deSHaik Aftandilian 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
260023e71deSHaik Aftandilian 	ldx	[scr + %lo(hrtime_base)], base;	/* load hrtime_base */	\
261023e71deSHaik Aftandilian /* CSTYLED */ 								\
262023e71deSHaik Aftandilian 	GET_NATIVE_TIME(now,gnt1,gnt2,label); /* get current %stick */	\
263023e71deSHaik Aftandilian 	subcc	now, nslt, nslt; /* nslt = ticks since last clockint */	\
264023e71deSHaik Aftandilian 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
265023e71deSHaik Aftandilian 	/* membar #LoadLoad; (see comment (2) above) */			\
266023e71deSHaik Aftandilian 	ld	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
267023e71deSHaik Aftandilian 	NATIVE_TIME_TO_NSEC_SCALE(nslt, scale, gnt1, NSEC_SHIFT);	\
268023e71deSHaik Aftandilian 	xor	hrlock, scr, scr;					\
269023e71deSHaik Aftandilian /* CSTYLED */ 								\
270023e71deSHaik Aftandilian 	brnz,pn	scr, 5b;						\
271023e71deSHaik Aftandilian 	add	base, nslt, base;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #endif /* CPU_MODULE */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate #endif
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate #endif	/* !_SYS_MACHCLOCK_H */
280