xref: /illumos-gate/usr/src/uts/sun4/sys/clock.h (revision 023e71de)
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
5b0fc0e77Sgovinda  * Common Development and Distribution License (the "License").
6b0fc0e77Sgovinda  * 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_CLOCK_H
277c478bd9Sstevel@tonic-gate #define	_SYS_CLOCK_H
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
307c478bd9Sstevel@tonic-gate extern "C" {
317c478bd9Sstevel@tonic-gate #endif
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/spl.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate #include <sys/machclock.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #ifndef _ASM
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #ifdef	_KERNEL
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate extern void	setcpudelay(void);
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate extern uint_t	nsec_scale;
447c478bd9Sstevel@tonic-gate extern uint_t	nsec_shift;
457c478bd9Sstevel@tonic-gate extern uint_t	nsec_per_sys_tick;
467c478bd9Sstevel@tonic-gate extern uint64_t	sys_tick_freq;
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate extern int	traptrace_use_stick;
497c478bd9Sstevel@tonic-gate extern uint64_t	system_clock_freq;
507c478bd9Sstevel@tonic-gate extern uint_t	sys_clock_mhz;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate extern void mon_clock_init(void);
537c478bd9Sstevel@tonic-gate extern void mon_clock_start(void);
547c478bd9Sstevel@tonic-gate extern void mon_clock_stop(void);
557c478bd9Sstevel@tonic-gate extern void mon_clock_share(void);
567c478bd9Sstevel@tonic-gate extern void mon_clock_unshare(void);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate extern hrtime_t hrtime_base;
597c478bd9Sstevel@tonic-gate extern void hres_tick(void);
607c478bd9Sstevel@tonic-gate extern void	clkstart(void);
617c478bd9Sstevel@tonic-gate extern void cbe_level14();
627c478bd9Sstevel@tonic-gate extern hrtime_t tick2ns(hrtime_t, uint_t);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate typedef struct {
65b0fc0e77Sgovinda 	uint64_t cbe_level1_inum;
66b0fc0e77Sgovinda 	uint64_t cbe_level10_inum;
677c478bd9Sstevel@tonic-gate } cbe_data_t;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #endif	/* _KERNEL */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate #endif	/* _ASM */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #define	CBE_LOW_PIL	1
757c478bd9Sstevel@tonic-gate #define	CBE_LOCK_PIL	LOCK_LEVEL
767c478bd9Sstevel@tonic-gate #define	CBE_HIGH_PIL	14
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	ADJ_SHIFT	4	/* used in get_hrestime and _level10 */
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * Locking strategy for high-resolution timing services
827c478bd9Sstevel@tonic-gate  *
837c478bd9Sstevel@tonic-gate  * We generally construct timestamps from two or more components:
847c478bd9Sstevel@tonic-gate  * a hardware time source and one or more software time sources.
857c478bd9Sstevel@tonic-gate  * These components cannot all be loaded simultaneously, so we need
867c478bd9Sstevel@tonic-gate  * some sort of locking strategy to generate consistent timestamps.
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * To minimize lock contention and cache thrashing we employ the
897c478bd9Sstevel@tonic-gate  * weakest possible synchronization model: writers (rare) serialize
907c478bd9Sstevel@tonic-gate  * on an acquisition-counting mutex, described below; readers (common)
917c478bd9Sstevel@tonic-gate  * execute in parallel with no synchronization at all -- they don't
927c478bd9Sstevel@tonic-gate  * exclude other readers, and they don't even exclude writers.  Instead,
937c478bd9Sstevel@tonic-gate  * readers just examine the writer lock's value before and after loading
947c478bd9Sstevel@tonic-gate  * all the components of a timestamp to detect writer intervention.
957c478bd9Sstevel@tonic-gate  * In the rare case when a writer does intervene, the reader will
967c478bd9Sstevel@tonic-gate  * detect it, discard the timestamp and try again.
977c478bd9Sstevel@tonic-gate  *
987c478bd9Sstevel@tonic-gate  * The writer lock, hres_lock, is a 32-bit integer consisting of an
997c478bd9Sstevel@tonic-gate  * 8-bit lock and a 24-bit acquisition count.  To acquire the lock we
1007c478bd9Sstevel@tonic-gate  * set the lock field with ldstub, which sets the low-order 8 bits to
1017c478bd9Sstevel@tonic-gate  * 0xff; to clear the lock, we increment it, which simultaneously clears
1027c478bd9Sstevel@tonic-gate  * the lock field (0xff --> 0x00) and increments the acquisition count
1037c478bd9Sstevel@tonic-gate  * (due to carry into bit 8).  Thus each acquisition transforms hres_lock
1047c478bd9Sstevel@tonic-gate  * from N:0 to N:ff, and each release transforms N:ff into (N+1):0.
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Readers can detect writer intervention by loading hres_lock before
1077c478bd9Sstevel@tonic-gate  * and after loading the time components they need; if either lock value
1087c478bd9Sstevel@tonic-gate  * contains 0xff in the low-order bits (lock held), or if the lock values
1097c478bd9Sstevel@tonic-gate  * are not equal (lock was acquired and released), a writer intervened
1107c478bd9Sstevel@tonic-gate  * and the reader must try again.  If the lock values are equal and the
1117c478bd9Sstevel@tonic-gate  * low-order 8 bits are clear, the timestamp must be valid.  We can check
1127c478bd9Sstevel@tonic-gate  * both of these conditions with a single compare instruction by checking
1137c478bd9Sstevel@tonic-gate  * whether old_hres_lock & ~1 == new_hres_lock, as illustrated by the
1147c478bd9Sstevel@tonic-gate  * following table of all possible lock states:
1157c478bd9Sstevel@tonic-gate  *
1167c478bd9Sstevel@tonic-gate  *	initial	& ~1	final		result of compare
1177c478bd9Sstevel@tonic-gate  *	------------	-----		-----------------
1187c478bd9Sstevel@tonic-gate  *	now:00		now:00		valid
1197c478bd9Sstevel@tonic-gate  *	now:00		now:ff		invalid
1207c478bd9Sstevel@tonic-gate  *	now:00		later:00	invalid
1217c478bd9Sstevel@tonic-gate  *	now:00		later:ff	invalid
1227c478bd9Sstevel@tonic-gate  *	now:fe		now:ff		invalid
1237c478bd9Sstevel@tonic-gate  *	now:fe		later:00	invalid
1247c478bd9Sstevel@tonic-gate  *	now:fe		later:ff	invalid
1257c478bd9Sstevel@tonic-gate  *
1267c478bd9Sstevel@tonic-gate  * Implementation considerations:
1277c478bd9Sstevel@tonic-gate  *
1287c478bd9Sstevel@tonic-gate  * (1) Load buffering.
1297c478bd9Sstevel@tonic-gate  *
1307c478bd9Sstevel@tonic-gate  * On a CPU that does load buffering we must ensure that the load of
1317c478bd9Sstevel@tonic-gate  * hres_lock completes before the load of any timestamp components.
1327c478bd9Sstevel@tonic-gate  * This is essential *even on a CPU that does in-order loads* because
1337c478bd9Sstevel@tonic-gate  * accessing the hardware time source may not involve a memory reference
1347c478bd9Sstevel@tonic-gate  * (e.g. rd %tick).  A convenient way to address this is to clear the
1357c478bd9Sstevel@tonic-gate  * lower bit (andn with 1) of the old lock value right away, since this
1367c478bd9Sstevel@tonic-gate  * generates a dependency on the load of hres_lock.  We have to do this
1377c478bd9Sstevel@tonic-gate  * anyway to perform the lock comparison described above.
1387c478bd9Sstevel@tonic-gate  *
1397c478bd9Sstevel@tonic-gate  * (2) Out-of-order loads.
1407c478bd9Sstevel@tonic-gate  *
1417c478bd9Sstevel@tonic-gate  * On a CPU that does out-of-order loads we must ensure that the loads
1427c478bd9Sstevel@tonic-gate  * of all timestamp components have completed before we load the final
1437c478bd9Sstevel@tonic-gate  * value of hres_lock.  This can be done either by generating load
1447c478bd9Sstevel@tonic-gate  * dependencies on the timestamp components or by membar #LoadLoad.
1457c478bd9Sstevel@tonic-gate  *
1467c478bd9Sstevel@tonic-gate  * (3) Interaction with the high level cyclic handler, hres_tick().
1477c478bd9Sstevel@tonic-gate  *
1487c478bd9Sstevel@tonic-gate  * One unusual property of hres_lock is that it's acquired in a high
1497c478bd9Sstevel@tonic-gate  * level cyclic handler, hres_tick().  Thus, hres_lock must be acquired at
1507c478bd9Sstevel@tonic-gate  * CBE_HIGH_PIL or higher to prevent single-CPU deadlock.
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  * (4) Cross-calls.
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  * If a cross-call happens while one CPU has hres_lock and another is
1557c478bd9Sstevel@tonic-gate  * trying to acquire it in the clock interrupt path, the system will
1567c478bd9Sstevel@tonic-gate  * deadlock: the first CPU will never release hres_lock since it's
1577c478bd9Sstevel@tonic-gate  * waiting to be released from the cross-call, and the cross-call can't
1587c478bd9Sstevel@tonic-gate  * complete because the second CPU is spinning on hres_lock with traps
1597c478bd9Sstevel@tonic-gate  * disabled.  Thus cross-calls must be blocked while holding hres_lock.
1607c478bd9Sstevel@tonic-gate  *
1617c478bd9Sstevel@tonic-gate  * Together, (3) and (4) imply that hres_lock should only be acquired
1627c478bd9Sstevel@tonic-gate  * at PIL >= max(XCALL_PIL, CBE_HIGH_PIL), or while traps are disabled.
1637c478bd9Sstevel@tonic-gate  */
1647c478bd9Sstevel@tonic-gate #define	HRES_LOCK_OFFSET 3
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate #define	CLOCK_LOCK(oldsplp)	\
1677c478bd9Sstevel@tonic-gate 	lock_set_spl((lock_t *)&hres_lock + HRES_LOCK_OFFSET, \
1687c478bd9Sstevel@tonic-gate 		ipltospl(CBE_HIGH_PIL), oldsplp)
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate #define	CLOCK_UNLOCK(spl)	\
1717c478bd9Sstevel@tonic-gate 	membar_ldst_stst();	\
1727c478bd9Sstevel@tonic-gate 	hres_lock++;		\
1737c478bd9Sstevel@tonic-gate 	splx(spl);		\
1747c478bd9Sstevel@tonic-gate 	LOCKSTAT_RECORD0(LS_CLOCK_UNLOCK_RELEASE,	\
1757c478bd9Sstevel@tonic-gate 		(lock_t *)&hres_lock + HRES_LOCK_OFFSET);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * NATIVE_TIME_TO_NSEC_SCALE is called with NSEC_SHIFT to convert hi-res
1797c478bd9Sstevel@tonic-gate  * timestamps into nanoseconds. On systems that have a %stick register,
1807c478bd9Sstevel@tonic-gate  * hi-res timestamps are in %stick units. On systems that do not have a
1817c478bd9Sstevel@tonic-gate  * %stick register, hi-res timestamps are in %tick units.
1827c478bd9Sstevel@tonic-gate  *
1837c478bd9Sstevel@tonic-gate  * NATIVE_TIME_TO_NSEC_SCALE is called with TICK_NSEC_SHIFT to convert from
1847c478bd9Sstevel@tonic-gate  * %tick units to nanoseconds on all implementations whether %stick is
1857c478bd9Sstevel@tonic-gate  * available or not.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * At least 62.5 MHz CPU %tick frequency
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate #define	TICK_NSEC_SHIFT	4
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate  * Convert hi-res native time (V9's %tick in our case) into nanoseconds.
1967c478bd9Sstevel@tonic-gate  *
1977c478bd9Sstevel@tonic-gate  * The challenge is to multiply a %tick value by (NANOSEC / sys_tick_freq)
1987c478bd9Sstevel@tonic-gate  * without using floating point and without overflowing 64-bit integers.
1997c478bd9Sstevel@tonic-gate  * We assume that all sun4u systems will have a 16 nsec or better clock
2007c478bd9Sstevel@tonic-gate  * (i.e. faster than 62.5 MHz), which means that (ticks << 4) has units
2017c478bd9Sstevel@tonic-gate  * greater than one nanosecond, so converting from (ticks << 4) to nsec
2027c478bd9Sstevel@tonic-gate  * requires multiplication by a rational number, R, between 0 and 1.
2037c478bd9Sstevel@tonic-gate  * To avoid floating-point we precompute (R * 2^32) during boot and
2047c478bd9Sstevel@tonic-gate  * stash this away in nsec_scale.  Thus we can compute (tick * R) as
2057c478bd9Sstevel@tonic-gate  * (tick * nsec_scale) >> 32, which is accurate to about 1 part per billion.
2067c478bd9Sstevel@tonic-gate  *
2077c478bd9Sstevel@tonic-gate  * To avoid 64-bit overflow when multiplying (tick << 4) by nsec_scale,
2087c478bd9Sstevel@tonic-gate  * we split (tick << 4) into its high and low 32-bit pieces, H and L,
2097c478bd9Sstevel@tonic-gate  * multiply each piece separately, and add up the relevant bits of the
2107c478bd9Sstevel@tonic-gate  * partial products.  Putting it all together we have:
2117c478bd9Sstevel@tonic-gate  *
2127c478bd9Sstevel@tonic-gate  * nsec = (tick << 4) * R
2137c478bd9Sstevel@tonic-gate  *	= ((tick << 4) * nsec_scale) >> 32
2147c478bd9Sstevel@tonic-gate  *	= ((H << 32) + L) * nsec_scale) >> 32
2157c478bd9Sstevel@tonic-gate  *	= (H * nsec_scale) + ((L * nsec_scale) >> 32)
2167c478bd9Sstevel@tonic-gate  *
2177c478bd9Sstevel@tonic-gate  * The last line is the computation we actually perform: it requires no
2187c478bd9Sstevel@tonic-gate  * floating point and all intermediate results fit in 64-bit registers.
2197c478bd9Sstevel@tonic-gate  *
2207c478bd9Sstevel@tonic-gate  * Note that we require that tick is less than (1 << (64 - NSEC_SHIFT));
2217c478bd9Sstevel@tonic-gate  * greater values will result in overflow and misbehavior (not that this
2227c478bd9Sstevel@tonic-gate  * is a serious problem; (1 << (64 - NSEC_SHIFT)) nanoseconds is over
2237c478bd9Sstevel@tonic-gate  * thirty-six years).  Nonetheless, clients may wish to be aware of this
2247c478bd9Sstevel@tonic-gate  * limitation; NATIVE_TIME_MAX() returns this maximum native time.
2257c478bd9Sstevel@tonic-gate  *
2267c478bd9Sstevel@tonic-gate  * We provide two versions of this macro: a "full-service" version that
2277c478bd9Sstevel@tonic-gate  * just converts ticks to nanoseconds and a higher-performance version that
2287c478bd9Sstevel@tonic-gate  * expects the scaling factor nsec_scale as its second argument (so that
2297c478bd9Sstevel@tonic-gate  * callers can distance the load of nsec_scale from its use).  Note that
2307c478bd9Sstevel@tonic-gate  * we take a fast path if we determine the ticks to be less than 32 bits
2317c478bd9Sstevel@tonic-gate  * (as it often is for the delta between %tick values for successive
2327c478bd9Sstevel@tonic-gate  * firings of the hres_tick() cyclic).
2337c478bd9Sstevel@tonic-gate  *
2347c478bd9Sstevel@tonic-gate  * Note that in the 32-bit path we don't even bother clearing NPT.
2357c478bd9Sstevel@tonic-gate  * We get away with this by making hardclk.c ensure than nsec_scale
2367c478bd9Sstevel@tonic-gate  * is even, so we can take advantage of the associativity of modular
2377c478bd9Sstevel@tonic-gate  * arithmetic: multiplying %tick by any even number, say 2*n, is
2387c478bd9Sstevel@tonic-gate  * equivalent to multiplying %tick by 2, then by n.  Multiplication
2397c478bd9Sstevel@tonic-gate  * by 2 is equivalent to shifting left by one, which clears NPT.
2407c478bd9Sstevel@tonic-gate  *
2417c478bd9Sstevel@tonic-gate  * Finally, note that the macros use the labels "6:" and "7:"; these
2427c478bd9Sstevel@tonic-gate  * labels must not be used across an invocation of either macro.
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate #define	NATIVE_TIME_TO_NSEC_SCALE(out, scr1, scr2, shift)		\
2457c478bd9Sstevel@tonic-gate 	srlx	out, 32, scr2;		/* check high 32 bits */	\
2467c478bd9Sstevel@tonic-gate /* CSTYLED */ 								\
2477c478bd9Sstevel@tonic-gate 	brz,a,pt scr2, 6f;		/* if clear, 32-bit fast path */\
2487c478bd9Sstevel@tonic-gate 	mulx	out, scr1, out;		/* delay: 32-bit fast path */	\
2497c478bd9Sstevel@tonic-gate 	sllx	out, shift, out;	/* clear NPT and pre-scale */	\
2507c478bd9Sstevel@tonic-gate 	srlx	out, 32, scr2;		/* scr2 = hi32(tick<<4) = H */	\
2517c478bd9Sstevel@tonic-gate 	mulx	scr2, scr1, scr2;	/* scr2 = (H*F) */		\
2527c478bd9Sstevel@tonic-gate 	srl	out, 0, out;		/* out = lo32(tick<<4) = L */	\
2537c478bd9Sstevel@tonic-gate 	mulx	out, scr1, scr1;	/* scr1 = (L*F) */		\
2547c478bd9Sstevel@tonic-gate 	srlx	scr1, 32, scr1;		/* scr1 = (L*F) >> 32 */	\
2557c478bd9Sstevel@tonic-gate 	ba	7f;			/* branch over 32-bit path */	\
2567c478bd9Sstevel@tonic-gate 	add	scr1, scr2, out;	/* out = (H*F) + ((L*F) >> 32) */\
2577c478bd9Sstevel@tonic-gate 6:									\
2587c478bd9Sstevel@tonic-gate 	srlx	out, 32 - shift, out;					\
2597c478bd9Sstevel@tonic-gate 7:
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #define	NATIVE_TIME_TO_NSEC(out, scr1, scr2)				\
2627c478bd9Sstevel@tonic-gate 	sethi	%hi(nsec_scale), scr1;	/* load scaling factor */	\
2637c478bd9Sstevel@tonic-gate 	ld	[scr1 + %lo(nsec_scale)], scr1;				\
2647c478bd9Sstevel@tonic-gate 	NATIVE_TIME_TO_NSEC_SCALE(out, scr1, scr2, NSEC_SHIFT);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate #define	NATIVE_TIME_MAX(out)						\
2677c478bd9Sstevel@tonic-gate 	mov	-1, out;						\
2687c478bd9Sstevel@tonic-gate 	srlx	out, NSEC_SHIFT, out
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate  * NSEC_SHIFT and VTRACE_SHIFT constants are defined in
2727c478bd9Sstevel@tonic-gate  * <sys/machclock.h> file.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate #endif
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate #endif	/* !_SYS_CLOCK_H */
280