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*b0fc0e77Sgovinda * Common Development and Distribution License (the "License"). 6*b0fc0e77Sgovinda * 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*b0fc0e77Sgovinda * Copyright 2006 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 #pragma ident "%Z%%M% %I% %E% SMI" 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #ifdef __cplusplus 327c478bd9Sstevel@tonic-gate extern "C" { 337c478bd9Sstevel@tonic-gate #endif 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <sys/spl.h> 367c478bd9Sstevel@tonic-gate #include <sys/time.h> 377c478bd9Sstevel@tonic-gate #include <sys/machclock.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #ifndef _ASM 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #ifdef _KERNEL 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate extern void setcpudelay(void); 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate extern uint_t nsec_scale; 467c478bd9Sstevel@tonic-gate extern uint_t nsec_shift; 477c478bd9Sstevel@tonic-gate extern uint_t nsec_per_sys_tick; 487c478bd9Sstevel@tonic-gate extern uint64_t sys_tick_freq; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate extern int traptrace_use_stick; 517c478bd9Sstevel@tonic-gate extern uint64_t system_clock_freq; 527c478bd9Sstevel@tonic-gate extern uint_t sys_clock_mhz; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate extern void mon_clock_init(void); 557c478bd9Sstevel@tonic-gate extern void mon_clock_start(void); 567c478bd9Sstevel@tonic-gate extern void mon_clock_stop(void); 577c478bd9Sstevel@tonic-gate extern void mon_clock_share(void); 587c478bd9Sstevel@tonic-gate extern void mon_clock_unshare(void); 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate extern hrtime_t hrtime_base; 617c478bd9Sstevel@tonic-gate extern void hres_tick(void); 627c478bd9Sstevel@tonic-gate extern void clkstart(void); 637c478bd9Sstevel@tonic-gate extern void cbe_level14(); 647c478bd9Sstevel@tonic-gate extern hrtime_t tick2ns(hrtime_t, uint_t); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate typedef struct { 67*b0fc0e77Sgovinda uint64_t cbe_level1_inum; 68*b0fc0e77Sgovinda uint64_t cbe_level10_inum; 697c478bd9Sstevel@tonic-gate } cbe_data_t; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #endif /* _ASM */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #define CBE_LOW_PIL 1 777c478bd9Sstevel@tonic-gate #define CBE_LOCK_PIL LOCK_LEVEL 787c478bd9Sstevel@tonic-gate #define CBE_HIGH_PIL 14 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate #define ADJ_SHIFT 4 /* used in get_hrestime and _level10 */ 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * Locking strategy for high-resolution timing services 847c478bd9Sstevel@tonic-gate * 857c478bd9Sstevel@tonic-gate * We generally construct timestamps from two or more components: 867c478bd9Sstevel@tonic-gate * a hardware time source and one or more software time sources. 877c478bd9Sstevel@tonic-gate * These components cannot all be loaded simultaneously, so we need 887c478bd9Sstevel@tonic-gate * some sort of locking strategy to generate consistent timestamps. 897c478bd9Sstevel@tonic-gate * 907c478bd9Sstevel@tonic-gate * To minimize lock contention and cache thrashing we employ the 917c478bd9Sstevel@tonic-gate * weakest possible synchronization model: writers (rare) serialize 927c478bd9Sstevel@tonic-gate * on an acquisition-counting mutex, described below; readers (common) 937c478bd9Sstevel@tonic-gate * execute in parallel with no synchronization at all -- they don't 947c478bd9Sstevel@tonic-gate * exclude other readers, and they don't even exclude writers. Instead, 957c478bd9Sstevel@tonic-gate * readers just examine the writer lock's value before and after loading 967c478bd9Sstevel@tonic-gate * all the components of a timestamp to detect writer intervention. 977c478bd9Sstevel@tonic-gate * In the rare case when a writer does intervene, the reader will 987c478bd9Sstevel@tonic-gate * detect it, discard the timestamp and try again. 997c478bd9Sstevel@tonic-gate * 1007c478bd9Sstevel@tonic-gate * The writer lock, hres_lock, is a 32-bit integer consisting of an 1017c478bd9Sstevel@tonic-gate * 8-bit lock and a 24-bit acquisition count. To acquire the lock we 1027c478bd9Sstevel@tonic-gate * set the lock field with ldstub, which sets the low-order 8 bits to 1037c478bd9Sstevel@tonic-gate * 0xff; to clear the lock, we increment it, which simultaneously clears 1047c478bd9Sstevel@tonic-gate * the lock field (0xff --> 0x00) and increments the acquisition count 1057c478bd9Sstevel@tonic-gate * (due to carry into bit 8). Thus each acquisition transforms hres_lock 1067c478bd9Sstevel@tonic-gate * from N:0 to N:ff, and each release transforms N:ff into (N+1):0. 1077c478bd9Sstevel@tonic-gate * 1087c478bd9Sstevel@tonic-gate * Readers can detect writer intervention by loading hres_lock before 1097c478bd9Sstevel@tonic-gate * and after loading the time components they need; if either lock value 1107c478bd9Sstevel@tonic-gate * contains 0xff in the low-order bits (lock held), or if the lock values 1117c478bd9Sstevel@tonic-gate * are not equal (lock was acquired and released), a writer intervened 1127c478bd9Sstevel@tonic-gate * and the reader must try again. If the lock values are equal and the 1137c478bd9Sstevel@tonic-gate * low-order 8 bits are clear, the timestamp must be valid. We can check 1147c478bd9Sstevel@tonic-gate * both of these conditions with a single compare instruction by checking 1157c478bd9Sstevel@tonic-gate * whether old_hres_lock & ~1 == new_hres_lock, as illustrated by the 1167c478bd9Sstevel@tonic-gate * following table of all possible lock states: 1177c478bd9Sstevel@tonic-gate * 1187c478bd9Sstevel@tonic-gate * initial & ~1 final result of compare 1197c478bd9Sstevel@tonic-gate * ------------ ----- ----------------- 1207c478bd9Sstevel@tonic-gate * now:00 now:00 valid 1217c478bd9Sstevel@tonic-gate * now:00 now:ff invalid 1227c478bd9Sstevel@tonic-gate * now:00 later:00 invalid 1237c478bd9Sstevel@tonic-gate * now:00 later:ff invalid 1247c478bd9Sstevel@tonic-gate * now:fe now:ff invalid 1257c478bd9Sstevel@tonic-gate * now:fe later:00 invalid 1267c478bd9Sstevel@tonic-gate * now:fe later:ff invalid 1277c478bd9Sstevel@tonic-gate * 1287c478bd9Sstevel@tonic-gate * Implementation considerations: 1297c478bd9Sstevel@tonic-gate * 1307c478bd9Sstevel@tonic-gate * (1) Load buffering. 1317c478bd9Sstevel@tonic-gate * 1327c478bd9Sstevel@tonic-gate * On a CPU that does load buffering we must ensure that the load of 1337c478bd9Sstevel@tonic-gate * hres_lock completes before the load of any timestamp components. 1347c478bd9Sstevel@tonic-gate * This is essential *even on a CPU that does in-order loads* because 1357c478bd9Sstevel@tonic-gate * accessing the hardware time source may not involve a memory reference 1367c478bd9Sstevel@tonic-gate * (e.g. rd %tick). A convenient way to address this is to clear the 1377c478bd9Sstevel@tonic-gate * lower bit (andn with 1) of the old lock value right away, since this 1387c478bd9Sstevel@tonic-gate * generates a dependency on the load of hres_lock. We have to do this 1397c478bd9Sstevel@tonic-gate * anyway to perform the lock comparison described above. 1407c478bd9Sstevel@tonic-gate * 1417c478bd9Sstevel@tonic-gate * (2) Out-of-order loads. 1427c478bd9Sstevel@tonic-gate * 1437c478bd9Sstevel@tonic-gate * On a CPU that does out-of-order loads we must ensure that the loads 1447c478bd9Sstevel@tonic-gate * of all timestamp components have completed before we load the final 1457c478bd9Sstevel@tonic-gate * value of hres_lock. This can be done either by generating load 1467c478bd9Sstevel@tonic-gate * dependencies on the timestamp components or by membar #LoadLoad. 1477c478bd9Sstevel@tonic-gate * 1487c478bd9Sstevel@tonic-gate * (3) Interaction with the high level cyclic handler, hres_tick(). 1497c478bd9Sstevel@tonic-gate * 1507c478bd9Sstevel@tonic-gate * One unusual property of hres_lock is that it's acquired in a high 1517c478bd9Sstevel@tonic-gate * level cyclic handler, hres_tick(). Thus, hres_lock must be acquired at 1527c478bd9Sstevel@tonic-gate * CBE_HIGH_PIL or higher to prevent single-CPU deadlock. 1537c478bd9Sstevel@tonic-gate * 1547c478bd9Sstevel@tonic-gate * (4) Cross-calls. 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * If a cross-call happens while one CPU has hres_lock and another is 1577c478bd9Sstevel@tonic-gate * trying to acquire it in the clock interrupt path, the system will 1587c478bd9Sstevel@tonic-gate * deadlock: the first CPU will never release hres_lock since it's 1597c478bd9Sstevel@tonic-gate * waiting to be released from the cross-call, and the cross-call can't 1607c478bd9Sstevel@tonic-gate * complete because the second CPU is spinning on hres_lock with traps 1617c478bd9Sstevel@tonic-gate * disabled. Thus cross-calls must be blocked while holding hres_lock. 1627c478bd9Sstevel@tonic-gate * 1637c478bd9Sstevel@tonic-gate * Together, (3) and (4) imply that hres_lock should only be acquired 1647c478bd9Sstevel@tonic-gate * at PIL >= max(XCALL_PIL, CBE_HIGH_PIL), or while traps are disabled. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate #define HRES_LOCK_OFFSET 3 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate #define CLOCK_LOCK(oldsplp) \ 1697c478bd9Sstevel@tonic-gate lock_set_spl((lock_t *)&hres_lock + HRES_LOCK_OFFSET, \ 1707c478bd9Sstevel@tonic-gate ipltospl(CBE_HIGH_PIL), oldsplp) 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate #define CLOCK_UNLOCK(spl) \ 1737c478bd9Sstevel@tonic-gate membar_ldst_stst(); \ 1747c478bd9Sstevel@tonic-gate hres_lock++; \ 1757c478bd9Sstevel@tonic-gate splx(spl); \ 1767c478bd9Sstevel@tonic-gate LOCKSTAT_RECORD0(LS_CLOCK_UNLOCK_RELEASE, \ 1777c478bd9Sstevel@tonic-gate (lock_t *)&hres_lock + HRES_LOCK_OFFSET); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * NATIVE_TIME_TO_NSEC_SCALE is called with NSEC_SHIFT to convert hi-res 1817c478bd9Sstevel@tonic-gate * timestamps into nanoseconds. On systems that have a %stick register, 1827c478bd9Sstevel@tonic-gate * hi-res timestamps are in %stick units. On systems that do not have a 1837c478bd9Sstevel@tonic-gate * %stick register, hi-res timestamps are in %tick units. 1847c478bd9Sstevel@tonic-gate * 1857c478bd9Sstevel@tonic-gate * NATIVE_TIME_TO_NSEC_SCALE is called with TICK_NSEC_SHIFT to convert from 1867c478bd9Sstevel@tonic-gate * %tick units to nanoseconds on all implementations whether %stick is 1877c478bd9Sstevel@tonic-gate * available or not. 1887c478bd9Sstevel@tonic-gate */ 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate /* 1917c478bd9Sstevel@tonic-gate * At least 62.5 MHz CPU %tick frequency 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate #define TICK_NSEC_SHIFT 4 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Convert hi-res native time (V9's %tick in our case) into nanoseconds. 1987c478bd9Sstevel@tonic-gate * 1997c478bd9Sstevel@tonic-gate * The challenge is to multiply a %tick value by (NANOSEC / sys_tick_freq) 2007c478bd9Sstevel@tonic-gate * without using floating point and without overflowing 64-bit integers. 2017c478bd9Sstevel@tonic-gate * We assume that all sun4u systems will have a 16 nsec or better clock 2027c478bd9Sstevel@tonic-gate * (i.e. faster than 62.5 MHz), which means that (ticks << 4) has units 2037c478bd9Sstevel@tonic-gate * greater than one nanosecond, so converting from (ticks << 4) to nsec 2047c478bd9Sstevel@tonic-gate * requires multiplication by a rational number, R, between 0 and 1. 2057c478bd9Sstevel@tonic-gate * To avoid floating-point we precompute (R * 2^32) during boot and 2067c478bd9Sstevel@tonic-gate * stash this away in nsec_scale. Thus we can compute (tick * R) as 2077c478bd9Sstevel@tonic-gate * (tick * nsec_scale) >> 32, which is accurate to about 1 part per billion. 2087c478bd9Sstevel@tonic-gate * 2097c478bd9Sstevel@tonic-gate * To avoid 64-bit overflow when multiplying (tick << 4) by nsec_scale, 2107c478bd9Sstevel@tonic-gate * we split (tick << 4) into its high and low 32-bit pieces, H and L, 2117c478bd9Sstevel@tonic-gate * multiply each piece separately, and add up the relevant bits of the 2127c478bd9Sstevel@tonic-gate * partial products. Putting it all together we have: 2137c478bd9Sstevel@tonic-gate * 2147c478bd9Sstevel@tonic-gate * nsec = (tick << 4) * R 2157c478bd9Sstevel@tonic-gate * = ((tick << 4) * nsec_scale) >> 32 2167c478bd9Sstevel@tonic-gate * = ((H << 32) + L) * nsec_scale) >> 32 2177c478bd9Sstevel@tonic-gate * = (H * nsec_scale) + ((L * nsec_scale) >> 32) 2187c478bd9Sstevel@tonic-gate * 2197c478bd9Sstevel@tonic-gate * The last line is the computation we actually perform: it requires no 2207c478bd9Sstevel@tonic-gate * floating point and all intermediate results fit in 64-bit registers. 2217c478bd9Sstevel@tonic-gate * 2227c478bd9Sstevel@tonic-gate * Note that we require that tick is less than (1 << (64 - NSEC_SHIFT)); 2237c478bd9Sstevel@tonic-gate * greater values will result in overflow and misbehavior (not that this 2247c478bd9Sstevel@tonic-gate * is a serious problem; (1 << (64 - NSEC_SHIFT)) nanoseconds is over 2257c478bd9Sstevel@tonic-gate * thirty-six years). Nonetheless, clients may wish to be aware of this 2267c478bd9Sstevel@tonic-gate * limitation; NATIVE_TIME_MAX() returns this maximum native time. 2277c478bd9Sstevel@tonic-gate * 2287c478bd9Sstevel@tonic-gate * We provide two versions of this macro: a "full-service" version that 2297c478bd9Sstevel@tonic-gate * just converts ticks to nanoseconds and a higher-performance version that 2307c478bd9Sstevel@tonic-gate * expects the scaling factor nsec_scale as its second argument (so that 2317c478bd9Sstevel@tonic-gate * callers can distance the load of nsec_scale from its use). Note that 2327c478bd9Sstevel@tonic-gate * we take a fast path if we determine the ticks to be less than 32 bits 2337c478bd9Sstevel@tonic-gate * (as it often is for the delta between %tick values for successive 2347c478bd9Sstevel@tonic-gate * firings of the hres_tick() cyclic). 2357c478bd9Sstevel@tonic-gate * 2367c478bd9Sstevel@tonic-gate * Note that in the 32-bit path we don't even bother clearing NPT. 2377c478bd9Sstevel@tonic-gate * We get away with this by making hardclk.c ensure than nsec_scale 2387c478bd9Sstevel@tonic-gate * is even, so we can take advantage of the associativity of modular 2397c478bd9Sstevel@tonic-gate * arithmetic: multiplying %tick by any even number, say 2*n, is 2407c478bd9Sstevel@tonic-gate * equivalent to multiplying %tick by 2, then by n. Multiplication 2417c478bd9Sstevel@tonic-gate * by 2 is equivalent to shifting left by one, which clears NPT. 2427c478bd9Sstevel@tonic-gate * 2437c478bd9Sstevel@tonic-gate * Finally, note that the macros use the labels "6:" and "7:"; these 2447c478bd9Sstevel@tonic-gate * labels must not be used across an invocation of either macro. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate #define NATIVE_TIME_TO_NSEC_SCALE(out, scr1, scr2, shift) \ 2477c478bd9Sstevel@tonic-gate srlx out, 32, scr2; /* check high 32 bits */ \ 2487c478bd9Sstevel@tonic-gate /* CSTYLED */ \ 2497c478bd9Sstevel@tonic-gate brz,a,pt scr2, 6f; /* if clear, 32-bit fast path */\ 2507c478bd9Sstevel@tonic-gate mulx out, scr1, out; /* delay: 32-bit fast path */ \ 2517c478bd9Sstevel@tonic-gate sllx out, shift, out; /* clear NPT and pre-scale */ \ 2527c478bd9Sstevel@tonic-gate srlx out, 32, scr2; /* scr2 = hi32(tick<<4) = H */ \ 2537c478bd9Sstevel@tonic-gate mulx scr2, scr1, scr2; /* scr2 = (H*F) */ \ 2547c478bd9Sstevel@tonic-gate srl out, 0, out; /* out = lo32(tick<<4) = L */ \ 2557c478bd9Sstevel@tonic-gate mulx out, scr1, scr1; /* scr1 = (L*F) */ \ 2567c478bd9Sstevel@tonic-gate srlx scr1, 32, scr1; /* scr1 = (L*F) >> 32 */ \ 2577c478bd9Sstevel@tonic-gate ba 7f; /* branch over 32-bit path */ \ 2587c478bd9Sstevel@tonic-gate add scr1, scr2, out; /* out = (H*F) + ((L*F) >> 32) */\ 2597c478bd9Sstevel@tonic-gate 6: \ 2607c478bd9Sstevel@tonic-gate srlx out, 32 - shift, out; \ 2617c478bd9Sstevel@tonic-gate 7: 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate #define NATIVE_TIME_TO_NSEC(out, scr1, scr2) \ 2647c478bd9Sstevel@tonic-gate sethi %hi(nsec_scale), scr1; /* load scaling factor */ \ 2657c478bd9Sstevel@tonic-gate ld [scr1 + %lo(nsec_scale)], scr1; \ 2667c478bd9Sstevel@tonic-gate NATIVE_TIME_TO_NSEC_SCALE(out, scr1, scr2, NSEC_SHIFT); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate #define NATIVE_TIME_MAX(out) \ 2697c478bd9Sstevel@tonic-gate mov -1, out; \ 2707c478bd9Sstevel@tonic-gate srlx out, NSEC_SHIFT, out 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * The following macros are only for use in the cpu module. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate #if defined(CPU_MODULE) 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * NSEC_SHIFT and VTRACE_SHIFT constants are defined in 2807c478bd9Sstevel@tonic-gate * <sys/machclock.h> file. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * NOTE: the macros below assume that the various time-related variables 2867c478bd9Sstevel@tonic-gate * (hrestime, hrestime_adj, hres_last_tick, timedelta, nsec_scale, etc) 2877c478bd9Sstevel@tonic-gate * are all stored together on a 64-byte boundary. The primary motivation 2887c478bd9Sstevel@tonic-gate * is cache performance, but we also take advantage of a convenient side 2897c478bd9Sstevel@tonic-gate * effect: these variables all have the same high 22 address bits, so only 2907c478bd9Sstevel@tonic-gate * one sethi is needed to access them all. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * GET_HRESTIME() returns the value of hrestime, hrestime_adj and the 2957c478bd9Sstevel@tonic-gate * number of nanoseconds since the last clock tick ('nslt'). It also 2967c478bd9Sstevel@tonic-gate * sets 'nano' to the value NANOSEC (one billion). 2977c478bd9Sstevel@tonic-gate * 2987c478bd9Sstevel@tonic-gate * This macro assumes that all registers are globals or outs so they can 2997c478bd9Sstevel@tonic-gate * safely contain 64-bit data, and that it's safe to use the label "5:". 3007c478bd9Sstevel@tonic-gate * Further, this macro calls the NATIVE_TIME_TO_NSEC_SCALE which in turn 3017c478bd9Sstevel@tonic-gate * uses the labels "6:" and "7:"; labels "5:", "6:" and "7:" must not 3027c478bd9Sstevel@tonic-gate * be used across invocations of this macro. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate #define GET_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano, scr, hrlock, \ 3057c478bd9Sstevel@tonic-gate gnt1, gnt2) \ 3067c478bd9Sstevel@tonic-gate 5: sethi %hi(hres_lock), scr; \ 3077c478bd9Sstevel@tonic-gate lduw [scr + %lo(hres_lock)], hrlock; /* load clock lock */ \ 3087c478bd9Sstevel@tonic-gate lduw [scr + %lo(nsec_scale)], nano; /* tick-to-ns factor */ \ 3097c478bd9Sstevel@tonic-gate andn hrlock, 1, hrlock; /* see comments above! */ \ 3107c478bd9Sstevel@tonic-gate ldx [scr + %lo(hres_last_tick)], nslt; \ 3117c478bd9Sstevel@tonic-gate ldn [scr + %lo(hrestime)], hrestsec; /* load hrestime.sec */\ 3127c478bd9Sstevel@tonic-gate add scr, %lo(hrestime), hrestnsec; \ 3137c478bd9Sstevel@tonic-gate ldn [hrestnsec + CLONGSIZE], hrestnsec; \ 3147c478bd9Sstevel@tonic-gate GET_NATIVE_TIME(adj, gnt1, gnt2); /* get current %tick */ \ 3157c478bd9Sstevel@tonic-gate subcc adj, nslt, nslt; /* nslt = ticks since last clockint */ \ 3167c478bd9Sstevel@tonic-gate movneg %xcc, %g0, nslt; /* ignore neg delta from tick skew */ \ 3177c478bd9Sstevel@tonic-gate ldx [scr + %lo(hrestime_adj)], adj; /* load hrestime_adj */ \ 3187c478bd9Sstevel@tonic-gate /* membar #LoadLoad; (see comment (2) above) */ \ 3197c478bd9Sstevel@tonic-gate lduw [scr + %lo(hres_lock)], scr; /* load clock lock */ \ 3207c478bd9Sstevel@tonic-gate NATIVE_TIME_TO_NSEC_SCALE(nslt, nano, gnt1, NSEC_SHIFT); \ 3217c478bd9Sstevel@tonic-gate sethi %hi(NANOSEC), nano; \ 3227c478bd9Sstevel@tonic-gate xor hrlock, scr, scr; \ 3237c478bd9Sstevel@tonic-gate /* CSTYLED */ \ 3247c478bd9Sstevel@tonic-gate brnz,pn scr, 5b; \ 3257c478bd9Sstevel@tonic-gate or nano, %lo(NANOSEC), nano; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Similar to above, but returns current gethrtime() value in 'base'. 3297c478bd9Sstevel@tonic-gate */ 3307c478bd9Sstevel@tonic-gate #define GET_HRTIME(base, now, nslt, scale, scr, hrlock, gnt1, gnt2) \ 3317c478bd9Sstevel@tonic-gate 5: sethi %hi(hres_lock), scr; \ 3327c478bd9Sstevel@tonic-gate lduw [scr + %lo(hres_lock)], hrlock; /* load clock lock */ \ 3337c478bd9Sstevel@tonic-gate lduw [scr + %lo(nsec_scale)], scale; /* tick-to-ns factor */ \ 3347c478bd9Sstevel@tonic-gate andn hrlock, 1, hrlock; /* see comments above! */ \ 3357c478bd9Sstevel@tonic-gate ldx [scr + %lo(hres_last_tick)], nslt; \ 3367c478bd9Sstevel@tonic-gate ldx [scr + %lo(hrtime_base)], base; /* load hrtime_base */ \ 3377c478bd9Sstevel@tonic-gate GET_NATIVE_TIME(now, gnt1, gnt2); /* get current %tick */ \ 3387c478bd9Sstevel@tonic-gate subcc now, nslt, nslt; /* nslt = ticks since last clockint */ \ 3397c478bd9Sstevel@tonic-gate movneg %xcc, %g0, nslt; /* ignore neg delta from tick skew */ \ 3407c478bd9Sstevel@tonic-gate /* membar #LoadLoad; (see comment (2) above) */ \ 3417c478bd9Sstevel@tonic-gate ld [scr + %lo(hres_lock)], scr; /* load clock lock */ \ 3427c478bd9Sstevel@tonic-gate NATIVE_TIME_TO_NSEC_SCALE(nslt, scale, gnt1, NSEC_SHIFT); \ 3437c478bd9Sstevel@tonic-gate xor hrlock, scr, scr; \ 3447c478bd9Sstevel@tonic-gate /* CSTYLED */ \ 3457c478bd9Sstevel@tonic-gate brnz,pn scr, 5b; \ 3467c478bd9Sstevel@tonic-gate add base, nslt, base; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* 3497c478bd9Sstevel@tonic-gate * Maximum-performance timestamp for kernel tracing. We don't bother 3507c478bd9Sstevel@tonic-gate * clearing NPT because vtrace expresses everything in 32-bit deltas, 3517c478bd9Sstevel@tonic-gate * so only the low-order 32 bits matter. We do shift down a few bits, 3527c478bd9Sstevel@tonic-gate * however, so that the trace framework doesn't emit a ridiculous number 3537c478bd9Sstevel@tonic-gate * of 32_bit_elapsed_time records (trace points are more expensive when 3547c478bd9Sstevel@tonic-gate * the time since the last trace point doesn't fit in a 16-bit delta). 3557c478bd9Sstevel@tonic-gate * We currently shift by 4 (divide by 16) on the grounds that (1) there's 3567c478bd9Sstevel@tonic-gate * no point making the timing finer-grained than the trace point latency, 3577c478bd9Sstevel@tonic-gate * which exceeds 16 cycles; and (2) the cost and probe effect of many 3587c478bd9Sstevel@tonic-gate * 32-bit time records far exceeds the cost of the 'srlx' instruction. 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate #define GET_VTRACE_TIME(out, scr1, scr2) \ 3617c478bd9Sstevel@tonic-gate GET_NATIVE_TIME(out, scr1, scr2); /* get current %tick */ \ 3627c478bd9Sstevel@tonic-gate srlx out, VTRACE_SHIFT, out; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * Full 64-bit version for those truly rare occasions when you need it. 3667c478bd9Sstevel@tonic-gate * Currently this is only needed to generate the TR_START_TIME record. 3677c478bd9Sstevel@tonic-gate */ 3687c478bd9Sstevel@tonic-gate #define GET_VTRACE_TIME_64(out, scr1, scr2) \ 3697c478bd9Sstevel@tonic-gate GET_NATIVE_TIME(out, scr1, scr2); /* get current %tick */ \ 3707c478bd9Sstevel@tonic-gate add out, out, out; \ 3717c478bd9Sstevel@tonic-gate srlx out, VTRACE_SHIFT + 1, out; 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * Return the rate at which the vtrace clock runs. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate #define GET_VTRACE_FREQUENCY(out, scr1, scr2) \ 3777c478bd9Sstevel@tonic-gate sethi %hi(sys_tick_freq), out; \ 3787c478bd9Sstevel@tonic-gate ldx [out + %lo(sys_tick_freq)], out; \ 3797c478bd9Sstevel@tonic-gate srlx out, VTRACE_SHIFT, out; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate #endif /* CPU_MODULE */ 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate #ifdef __cplusplus 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate #endif 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate #endif /* !_SYS_CLOCK_H */ 388