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