xref: /illumos-gate/usr/src/uts/sun4u/sys/machclock.h (revision afab0816ecb604f0099a09ad8ee398f0d7b77b1c)
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 #ifdef	__cplusplus
29 extern "C" {
30 #endif
31 
32 #ifdef _ASM
33 /*
34  * Macro to clear the NPT (non-privileged trap) bit in the %tick/%stick
35  * register.  Uses %g1-%g4.
36  */
37 #define	CLEARTICKNPT				\
38 	sethi	%hi(cpu_clearticknpt), %g1;	\
39 	jmp	%g1 + %lo(cpu_clearticknpt);	\
40 	rd	%pc, %g4
41 
42 #define	RD_TICK_NO_SUSPEND_CHECK(out, scr1)	\
43 	rdpr	%tick, out;			\
44 	sllx	out, 1, out;			\
45 	srlx	out, 1, out;
46 
47 #define	RD_TICK(out, scr1, scr2, label)		\
48 	RD_TICK_NO_SUSPEND_CHECK(out, scr1);
49 
50 /*
51  * These macros on sun4u read the %tick register, due to :
52  * - %stick does not have enough precision, it's very low frequency
53  * - %stick accesses are very slow on UltraSPARC IIe
54  * Instead, consumers read %tick and scale it by the current stick/tick ratio.
55  * This only works because all cpus in a system change clock ratios
56  * synchronously and the changes are all initiated by the kernel.
57  */
58 #define	RD_CLOCK_TICK(out, scr1, scr2, label)	\
59 /* CSTYLED */					\
60 	RD_TICK(out,scr1,scr2,label)
61 
62 #define	RD_CLOCK_TICK_NO_SUSPEND_CHECK(out, scr1)	\
63 /* CSTYLED */						\
64 	RD_TICK_NO_SUSPEND_CHECK(out,scr1)
65 
66 #endif /* _ASM */
67 
68 #if defined(CPU_MODULE)
69 
70 /*
71  * Constants used to convert hi-res timestamps into nanoseconds
72  * (see <sys/clock.h> file for more information)
73  */
74 
75 #if defined(CHEETAH) || defined(HUMMINGBIRD) || defined(OLYMPUS_C)
76 
77 /*
78  * At least 3.9MHz, for slower %stick-based systems.
79  */
80 #define	NSEC_SHIFT	8
81 
82 #elif defined(SPITFIRE)
83 
84 /*
85  * At least 62.5 MHz, for faster %tick-based systems.
86  */
87 #define	NSEC_SHIFT	4
88 #define	VTRACE_SHIFT	4
89 
90 #else
91 #error "Compiling for CPU_MODULE but no CPU specified"
92 #endif
93 
94 /*
95  * NOTE: the macros below assume that the various time-related variables
96  * (hrestime, hrestime_adj, hres_last_tick, timedelta, nsec_scale, etc)
97  * are all stored together on a 64-byte boundary.  The primary motivation
98  * is cache performance, but we also take advantage of a convenient side
99  * effect: these variables all have the same high 22 address bits, so only
100  * one sethi is needed to access them all.
101  */
102 
103 /*
104  * GET_HRESTIME() returns the value of hrestime, hrestime_adj and the
105  * number of nanoseconds since the last clock tick ('nslt').  It also
106  * sets 'nano' to the value NANOSEC (one billion).
107  *
108  * This macro assumes that all registers are globals or outs so they can
109  * safely contain 64-bit data, and that it's safe to use the label "5:".
110  * Further, this macro calls the NATIVE_TIME_TO_NSEC_SCALE which in turn
111  * uses the labels "6:" and "7:"; labels "5:", "6:" and "7:" must not
112  * be used across invocations of this macro.
113  */
114 #define	GET_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano, scr, hrlock, \
115     gnt1, gnt2) \
116 5:	sethi	%hi(hres_lock), scr;					\
117 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
118 	lduw	[scr + %lo(nsec_scale)], nano;	/* tick-to-ns factor */	\
119 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
120 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
121 	ldn	[scr + %lo(hrestime)], hrestsec; /* load hrestime.sec */\
122 	add	scr, %lo(hrestime), hrestnsec;				\
123 	ldn	[hrestnsec + CLONGSIZE], hrestnsec;			\
124 	GET_NATIVE_TIME(adj, gnt1, gnt2);	/* get current %tick */	\
125 	subcc	adj, nslt, nslt; /* nslt = ticks since last clockint */	\
126 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
127 	ldx	[scr + %lo(hrestime_adj)], adj; /* load hrestime_adj */	\
128 	/* membar #LoadLoad; (see comment (2) above) */			\
129 	lduw	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
130 	NATIVE_TIME_TO_NSEC_SCALE(nslt, nano, gnt1, NSEC_SHIFT);	\
131 	sethi	%hi(NANOSEC), nano;					\
132 	xor	hrlock, scr, scr;					\
133 /* CSTYLED */ 								\
134 	brnz,pn	scr, 5b;						\
135 	or	nano, %lo(NANOSEC), nano;
136 
137 /*
138  * Similar to above, but returns current gethrtime() value in 'base'.
139  */
140 #define	GET_HRTIME(base, now, nslt, scale, scr, hrlock, gnt1, gnt2)	\
141 5:	sethi	%hi(hres_lock), scr;					\
142 	lduw	[scr + %lo(hres_lock)], hrlock;	/* load clock lock */	\
143 	lduw	[scr + %lo(nsec_scale)], scale;	/* tick-to-ns factor */	\
144 	andn	hrlock, 1, hrlock;  	/* see comments above! */	\
145 	ldx	[scr + %lo(hres_last_tick)], nslt;			\
146 	ldx	[scr + %lo(hrtime_base)], base;	/* load hrtime_base */	\
147 	GET_NATIVE_TIME(now, gnt1, gnt2);	/* get current %tick */	\
148 	subcc	now, nslt, nslt; /* nslt = ticks since last clockint */	\
149 	movneg	%xcc, %g0, nslt; /* ignore neg delta from tick skew */	\
150 	/* membar #LoadLoad; (see comment (2) above) */			\
151 	ld	[scr + %lo(hres_lock)], scr; /* load clock lock */	\
152 	NATIVE_TIME_TO_NSEC_SCALE(nslt, scale, gnt1, NSEC_SHIFT);	\
153 	xor	hrlock, scr, scr;					\
154 /* CSTYLED */ 								\
155 	brnz,pn	scr, 5b;						\
156 	add	base, nslt, base;
157 
158 #endif /* CPU_MODULE */
159 
160 #ifndef _ASM
161 
162 #ifdef	_KERNEL
163 
164 /*
165  * Hardware watchdog variables and knobs
166  */
167 
168 #define	CLK_WATCHDOG_DEFAULT	10	/* 10 seconds */
169 
170 extern int	watchdog_enable;
171 extern int	watchdog_available;
172 extern int	watchdog_activated;
173 extern uint_t	watchdog_timeout_seconds;
174 
175 /*
176  * tod module name and operations
177  */
178 struct tod_ops {
179 	timestruc_t	(*tod_get)(void);
180 	void		(*tod_set)(timestruc_t);
181 	uint_t		(*tod_set_watchdog_timer)(uint_t);
182 	uint_t		(*tod_clear_watchdog_timer)(void);
183 	void		(*tod_set_power_alarm)(timestruc_t);
184 	void		(*tod_clear_power_alarm)(void);
185 	uint64_t	(*tod_get_cpufrequency)(void);
186 };
187 
188 extern struct tod_ops	tod_ops;
189 extern char		*tod_module_name;
190 
191 extern uint64_t gettick_counter(void);
192 #define	CLOCK_TICK_COUNTER() gettick_counter()
193 
194 /*
195  * These defines allow common code to use TOD functions independant
196  * of hardware platform.
197  */
198 #define	TODOP_GET(top)		((top).tod_get())
199 #define	TODOP_SET(top, ts)	((top).tod_set(ts))
200 #define	TODOP_SETWD(top, nsec)	((top).tod_set_watchdog_timer(nsec))
201 #define	TODOP_CLRWD(top)	((top).tod_clear_watchdog_timer())
202 #define	TODOP_SETWAKE(top, ts)	((top).tod_set_power_alarm(ts))
203 #define	TODOP_CLRWAKE(top)	((top).tod_clear_power_alarm())
204 
205 #endif	/* _KERNEL */
206 
207 #endif	/* _ASM */
208 
209 #ifdef	__cplusplus
210 }
211 #endif
212 
213 #endif	/* !_SYS_MACHCLOCK_H */
214