Home | History | Annotate | Download | only in cpu
      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 #if !defined(lint)
     27 #include "assym.h"
     28 #endif
     29 
     30 /*
     31  * General assembly language routines.
     32  * It is the intent of this file to contain routines that are
     33  * specific to cpu architecture.
     34  */
     35 
     36 /*
     37  * WARNING: If you add a fast trap handler which can be invoked by a
     38  * non-privileged user, you may have to use the FAST_TRAP_DONE macro
     39  * instead of "done" instruction to return back to the user mode. See
     40  * comments for the "fast_trap_done" entry point for more information.
     41  */
     42 #define	FAST_TRAP_DONE	\
     43 	ba,a	fast_trap_done
     44 
     45 /*
     46  * Override GET_NATIVE_TIME for the cpu module code.  This is not
     47  * guaranteed to be exactly one instruction, be careful of using
     48  * the macro in delay slots.
     49  *
     50  * Do not use any instruction that modifies condition codes as the
     51  * caller may depend on these to remain unchanged across the macro.
     52  */
     53 
     54 #define	GET_NATIVE_TIME(out, scr1, scr2) \
     55 	rd	STICK, out
     56 
     57 #define	RD_TICKCMPR(out, scr)		\
     58 	rd	STICK_COMPARE, out
     59 
     60 #define	WR_TICKCMPR(in,scr1,scr2,label)		\
     61 	wr	in, STICK_COMPARE
     62 
     63 
     64 #include <sys/clock.h>
     65 
     66 #if defined(lint)
     67 #include <sys/types.h>
     68 #include <sys/scb.h>
     69 #include <sys/systm.h>
     70 #include <sys/regset.h>
     71 #include <sys/sunddi.h>
     72 #include <sys/lockstat.h>
     73 #endif	/* lint */
     74 
     75 
     76 #include <sys/asm_linkage.h>
     77 #include <sys/privregs.h>
     78 #include <vm/hat_sfmmu.h>
     79 #include <sys/machparam.h>	/* To get SYSBASE and PAGESIZE */
     80 #include <sys/machthread.h>
     81 #include <sys/clock.h>
     82 #include <sys/intreg.h>
     83 #include <sys/psr_compat.h>
     84 #include <sys/isa_defs.h>
     85 #include <sys/dditypes.h>
     86 #include <sys/intr.h>
     87 #include <sys/hypervisor_api.h>
     88 
     89 #if !defined(lint)
     90 #include "assym.h"
     91 #endif
     92 
     93 #define	ICACHE_FLUSHSZ	0x20
     94 
     95 #if defined(lint)
     96 /*
     97  * Softint generated when counter field of tick reg matches value field
     98  * of tick_cmpr reg
     99  */
    100 /*ARGSUSED*/
    101 void
    102 tickcmpr_set(uint64_t clock_cycles)
    103 {}
    104 
    105 #else   /* lint */
    106 
    107 	ENTRY_NP(tickcmpr_set)
    108 	! get 64-bit clock_cycles interval
    109 	mov	%o0, %o2
    110 	mov	8, %o3			! A reasonable initial step size
    111 1:
    112 	WR_TICKCMPR(%o2,%o4,%o5,__LINE__)	! Write to TICK_CMPR
    113 
    114 	GET_NATIVE_TIME(%o0, %o4, %o5)	! Read %tick to confirm the
    115 	sllx	%o0, 1, %o0		!   value we wrote was in the future.
    116 	srlx	%o0, 1, %o0
    117 
    118 	cmp	%o2, %o0		! If the value we wrote was in the
    119 	bg,pt	%xcc, 2f		!   future, then blow out of here.
    120 	  sllx	%o3, 1, %o3		! If not, then double our step size,
    121 	ba,pt	%xcc, 1b		!   and take another lap.
    122 	  add	%o0, %o3, %o2		!
    123 2:
    124 	retl
    125 	  nop
    126 	SET_SIZE(tickcmpr_set)
    127 
    128 #endif  /* lint */
    129 
    130 #if defined(lint)
    131 
    132 void
    133 tickcmpr_disable(void)
    134 {}
    135 
    136 #else
    137 
    138 	ENTRY_NP(tickcmpr_disable)
    139 	mov	1, %g1
    140 	sllx	%g1, TICKINT_DIS_SHFT, %o0
    141 	WR_TICKCMPR(%o0,%o4,%o5,__LINE__)	! Write to TICK_CMPR
    142 	retl
    143 	  nop
    144 	SET_SIZE(tickcmpr_disable)
    145 
    146 #endif
    147 
    148 #if defined(lint)
    149 
    150 /*
    151  * tick_write_delta() increments %tick by the specified delta.  This should
    152  * only be called after a CPR event to assure that gethrtime() continues to
    153  * increase monotonically.  Obviously, writing %tick needs to de done very
    154  * carefully to avoid introducing unnecessary %tick skew across CPUs.  For
    155  * this reason, we make sure we're i-cache hot before actually writing to
    156  * %tick.
    157  *
    158  * NOTE: No provision for this on sun4v right now.
    159  */
    160 
    161 /*ARGSUSED*/
    162 void
    163 tick_write_delta(uint64_t delta)
    164 {}
    165 
    166 #else	/* lint */
    167 
    168 	.seg	".text"
    169 tick_write_delta_panic:
    170 	.asciz	"tick_write_delta: not supported"
    171 
    172 	ENTRY_NP(tick_write_delta)
    173 	sethi	%hi(tick_write_delta_panic), %o1
    174         save    %sp, -SA(MINFRAME), %sp ! get a new window to preserve caller
    175 	call	panic
    176 	  or	%i1, %lo(tick_write_delta_panic), %o0
    177 	/*NOTREACHED*/
    178 	retl
    179 	  nop
    180 #endif
    181 
    182 #if defined(lint)
    183 /*
    184  *  return 1 if disabled
    185  */
    186 
    187 int
    188 tickcmpr_disabled(void)
    189 { return (0); }
    190 
    191 #else   /* lint */
    192 
    193 	ENTRY_NP(tickcmpr_disabled)
    194 	RD_TICKCMPR(%g1, %o0)
    195 	retl
    196 	  srlx	%g1, TICKINT_DIS_SHFT, %o0
    197 	SET_SIZE(tickcmpr_disabled)
    198 
    199 #endif  /* lint */
    200 
    201 /*
    202  * Get current tick
    203  */
    204 #if defined(lint)
    205 
    206 u_longlong_t
    207 gettick(void)
    208 { return (0); }
    209 
    210 #else   /* lint */
    211 
    212 	ENTRY(gettick)
    213 	GET_NATIVE_TIME(%o0, %o2, %o3)
    214 	retl
    215 	  nop
    216 	SET_SIZE(gettick)
    217 
    218 #endif  /* lint */
    219 
    220 
    221 /*
    222  * Return the counter portion of the tick register.
    223  */
    224 
    225 #if defined(lint)
    226 
    227 uint64_t
    228 gettick_counter(void)
    229 { return(0); }
    230 
    231 #else	/* lint */
    232 
    233 	ENTRY_NP(gettick_counter)
    234 	rdpr	%tick, %o0
    235 	sllx	%o0, 1, %o0
    236 	retl
    237 	  srlx	%o0, 1, %o0		! shake off npt bit
    238 	SET_SIZE(gettick_counter)
    239 #endif	/* lint */
    240 
    241 /*
    242  * Provide a C callable interface to the trap that reads the hi-res timer.
    243  * Returns 64-bit nanosecond timestamp in %o0 and %o1.
    244  */
    245 
    246 #if defined(lint)
    247 
    248 hrtime_t
    249 gethrtime(void)
    250 {
    251 	return ((hrtime_t)0);
    252 }
    253 
    254 hrtime_t
    255 gethrtime_unscaled(void)
    256 {
    257 	return ((hrtime_t)0);
    258 }
    259 
    260 hrtime_t
    261 gethrtime_max(void)
    262 {
    263 	return ((hrtime_t)0);
    264 }
    265 
    266 void
    267 scalehrtime(hrtime_t *hrt)
    268 {
    269 	*hrt = 0;
    270 }
    271 
    272 void
    273 gethrestime(timespec_t *tp)
    274 {
    275 	tp->tv_sec = 0;
    276 	tp->tv_nsec = 0;
    277 }
    278 
    279 time_t
    280 gethrestime_sec(void)
    281 {
    282 	return (0);
    283 }
    284 
    285 void
    286 gethrestime_lasttick(timespec_t *tp)
    287 {
    288 	tp->tv_sec = 0;
    289 	tp->tv_nsec = 0;
    290 }
    291 
    292 /*ARGSUSED*/
    293 void
    294 hres_tick(void)
    295 {
    296 }
    297 
    298 void
    299 panic_hres_tick(void)
    300 {
    301 }
    302 
    303 #else	/* lint */
    304 
    305 	ENTRY_NP(gethrtime)
    306 	GET_HRTIME(%g1, %o0, %o1, %o2, %o3, %o4, %o5, %g2)
    307 							! %g1 = hrtime
    308 	retl
    309 	  mov	%g1, %o0
    310 	SET_SIZE(gethrtime)
    311 
    312 	ENTRY_NP(gethrtime_unscaled)
    313 	GET_NATIVE_TIME(%g1, %o2, %o3)			! %g1 = native time
    314 	retl
    315 	  mov	%g1, %o0
    316 	SET_SIZE(gethrtime_unscaled)
    317 
    318 	ENTRY_NP(gethrtime_waitfree)
    319 	ALTENTRY(dtrace_gethrtime)
    320 	GET_NATIVE_TIME(%g1, %o2, %o3)			! %g1 = native time
    321 	NATIVE_TIME_TO_NSEC(%g1, %o2, %o3)
    322 	retl
    323 	  mov	%g1, %o0
    324 	SET_SIZE(dtrace_gethrtime)
    325 	SET_SIZE(gethrtime_waitfree)
    326 
    327 	ENTRY(gethrtime_max)
    328 	NATIVE_TIME_MAX(%g1)
    329 	NATIVE_TIME_TO_NSEC(%g1, %o0, %o1)
    330 
    331 	! hrtime_t's are signed, max hrtime_t must be positive
    332 	mov	-1, %o2
    333 	brlz,a	%g1, 1f
    334 	  srlx	%o2, 1, %g1
    335 1:
    336 	retl
    337 	  mov	%g1, %o0
    338 	SET_SIZE(gethrtime_max)
    339 
    340 	ENTRY(scalehrtime)
    341 	ldx	[%o0], %o1
    342 	NATIVE_TIME_TO_NSEC(%o1, %o2, %o3)
    343 	retl
    344 	  stx	%o1, [%o0]
    345 	SET_SIZE(scalehrtime)
    346 
    347 /*
    348  * Fast trap to return a timestamp, uses trap window, leaves traps
    349  * disabled.  Returns a 64-bit nanosecond timestamp in %o0 and %o1.
    350  *
    351  * This is the handler for the ST_GETHRTIME trap.
    352  */
    353 
    354 	ENTRY_NP(get_timestamp)
    355 	GET_HRTIME(%g1, %g2, %g3, %g4, %g5, %o0, %o1, %o2)	! %g1 = hrtime
    356 	srlx	%g1, 32, %o0				! %o0 = hi32(%g1)
    357 	srl	%g1, 0, %o1				! %o1 = lo32(%g1)
    358 	FAST_TRAP_DONE
    359 	SET_SIZE(get_timestamp)
    360 
    361 /*
    362  * Macro to convert GET_HRESTIME() bits into a timestamp.
    363  *
    364  * We use two separate macros so that the platform-dependent GET_HRESTIME()
    365  * can be as small as possible; CONV_HRESTIME() implements the generic part.
    366  */
    367 #define	CONV_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano) \
    368 	brz,pt	adj, 3f;		/* no adjustments, it's easy */	\
    369 	add	hrestnsec, nslt, hrestnsec; /* hrest.tv_nsec += nslt */	\
    370 	brlz,pn	adj, 2f;		/* if hrestime_adj negative */	\
    371 	  srlx	nslt, ADJ_SHIFT, nslt;	/* delay: nslt >>= 4 */		\
    372 	subcc	adj, nslt, %g0;		/* hrestime_adj - nslt/16 */	\
    373 	movg	%xcc, nslt, adj;	/* adj by min(adj, nslt/16) */	\
    374 	ba	3f;			/* go convert to sec/nsec */	\
    375 	  add	hrestnsec, adj, hrestnsec; /* delay: apply adjustment */ \
    376 2:	addcc	adj, nslt, %g0;		/* hrestime_adj + nslt/16 */	\
    377 	bge,a,pt %xcc, 3f;		/* is adj less negative? */	\
    378 	  add	hrestnsec, adj, hrestnsec; /* yes: hrest.nsec += adj */	\
    379 	sub	hrestnsec, nslt, hrestnsec; /* no: hrest.nsec -= nslt/16 */ \
    380 3:	cmp	hrestnsec, nano;	/* more than a billion? */	\
    381 	bl,pt	%xcc, 4f;		/* if not, we're done */	\
    382 	  nop;				/* delay: do nothing :( */	\
    383 	add	hrestsec, 1, hrestsec;	/* hrest.tv_sec++; */		\
    384 	sub	hrestnsec, nano, hrestnsec; /* hrest.tv_nsec -= NANOSEC; */	\
    385 	ba,a	3b;			/* check >= billion again */	\
    386 4:
    387 
    388 	ENTRY_NP(gethrestime)
    389 	GET_HRESTIME(%o1, %o2, %o3, %o4, %o5, %g1, %g2, %g3, %g4)
    390 	CONV_HRESTIME(%o1, %o2, %o3, %o4, %o5)
    391 	stn	%o1, [%o0]
    392 	retl
    393 	  stn	%o2, [%o0 + CLONGSIZE]
    394 	SET_SIZE(gethrestime)
    395 
    396 /*
    397  * Similar to gethrestime(), but gethrestime_sec() returns current hrestime
    398  * seconds.
    399  */
    400 	ENTRY_NP(gethrestime_sec)
    401 	GET_HRESTIME(%o0, %o2, %o3, %o4, %o5, %g1, %g2, %g3, %g4)
    402 	CONV_HRESTIME(%o0, %o2, %o3, %o4, %o5)
    403 	retl					! %o0 current hrestime seconds
    404 	  nop
    405 	SET_SIZE(gethrestime_sec)
    406 
    407 /*
    408  * Returns the hrestime on the last tick.  This is simpler than gethrestime()
    409  * and gethrestime_sec():  no conversion is required.  gethrestime_lasttick()
    410  * follows the same locking algorithm as GET_HRESTIME and GET_HRTIME,
    411  * outlined in detail in clock.h.  (Unlike GET_HRESTIME/GET_HRTIME, we don't
    412  * rely on load dependencies to effect the membar #LoadLoad, instead declaring
    413  * it explicitly.)
    414  */
    415 	ENTRY_NP(gethrestime_lasttick)
    416 	sethi	%hi(hres_lock), %o1
    417 0:
    418 	lduw	[%o1 + %lo(hres_lock)], %o2	! Load lock value
    419 	membar	#LoadLoad			! Load of lock must complete
    420 	andn	%o2, 1, %o2			! Mask off lowest bit
    421 	ldn	[%o1 + %lo(hrestime)], %g1	! Seconds.
    422 	add	%o1, %lo(hrestime), %o4
    423 	ldn	[%o4 + CLONGSIZE], %g2		! Nanoseconds.
    424 	membar	#LoadLoad			! All loads must complete
    425 	lduw	[%o1 + %lo(hres_lock)], %o3	! Reload lock value
    426 	cmp	%o3, %o2			! If lock is locked or has
    427 	bne	0b				!   changed, retry.
    428 	  stn	%g1, [%o0]			! Delay: store seconds
    429 	retl
    430 	  stn	%g2, [%o0 + CLONGSIZE]		! Delay: store nanoseconds
    431 	SET_SIZE(gethrestime_lasttick)
    432 
    433 /*
    434  * Fast trap for gettimeofday().  Returns a timestruc_t in %o0 and %o1.
    435  *
    436  * This is the handler for the ST_GETHRESTIME trap.
    437  */
    438 
    439 	ENTRY_NP(get_hrestime)
    440 	GET_HRESTIME(%o0, %o1, %g1, %g2, %g3, %g4, %g5, %o2, %o3)
    441 	CONV_HRESTIME(%o0, %o1, %g1, %g2, %g3)
    442 	FAST_TRAP_DONE
    443 	SET_SIZE(get_hrestime)
    444 
    445 /*
    446  * Fast trap to return lwp virtual time, uses trap window, leaves traps
    447  * disabled.  Returns a 64-bit number in %o0:%o1, which is the number
    448  * of nanoseconds consumed.
    449  *
    450  * This is the handler for the ST_GETHRVTIME trap.
    451  *
    452  * Register usage:
    453  *	%o0, %o1 = return lwp virtual time
    454  * 	%o2 = CPU/thread
    455  * 	%o3 = lwp
    456  * 	%g1 = scratch
    457  * 	%g5 = scratch
    458  */
    459 	ENTRY_NP(get_virtime)
    460 	GET_NATIVE_TIME(%g5, %g1, %g2)	! %g5 = native time in ticks
    461 	CPU_ADDR(%g2, %g3)			! CPU struct ptr to %g2
    462 	ldn	[%g2 + CPU_THREAD], %g2		! thread pointer to %g2
    463 	ldn	[%g2 + T_LWP], %g3		! lwp pointer to %g3
    464 
    465 	/*
    466 	 * Subtract start time of current microstate from time
    467 	 * of day to get increment for lwp virtual time.
    468 	 */
    469 	ldx	[%g3 + LWP_STATE_START], %g1	! ms_state_start
    470 	sub	%g5, %g1, %g5
    471 
    472 	/*
    473 	 * Add current value of ms_acct[LMS_USER]
    474 	 */
    475 	ldx	[%g3 + LWP_ACCT_USER], %g1	! ms_acct[LMS_USER]
    476 	add	%g5, %g1, %g5
    477 	NATIVE_TIME_TO_NSEC(%g5, %g1, %o0)
    478 
    479 	srl	%g5, 0, %o1			! %o1 = lo32(%g5)
    480 	srlx	%g5, 32, %o0			! %o0 = hi32(%g5)
    481 
    482 	FAST_TRAP_DONE
    483 	SET_SIZE(get_virtime)
    484 
    485 
    486 
    487 	.seg	".text"
    488 hrtime_base_panic:
    489 	.asciz	"hrtime_base stepping back"
    490 
    491 
    492 	ENTRY_NP(hres_tick)
    493 	save	%sp, -SA(MINFRAME), %sp	! get a new window
    494 
    495 	sethi	%hi(hrestime), %l4
    496 	ldstub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5	! try locking
    497 7:	tst	%l5
    498 	bz,pt	%xcc, 8f			! if we got it, drive on
    499 	  ld	[%l4 + %lo(nsec_scale)], %l5	! delay: %l5 = scaling factor
    500 	ldub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5
    501 9:	tst	%l5
    502 	bz,a,pn	%xcc, 7b
    503 	  ldstub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5
    504 	ba,pt	%xcc, 9b
    505 	  ldub	[%l4 + %lo(hres_lock + HRES_LOCK_OFFSET)], %l5
    506 8:
    507 	membar	#StoreLoad|#StoreStore
    508 
    509 	!
    510 	! update hres_last_tick.  %l5 has the scaling factor (nsec_scale).
    511 	!
    512 	ldx	[%l4 + %lo(hrtime_base)], %g1	! load current hrtime_base
    513 	GET_NATIVE_TIME(%l0, %l3, %l6)		! current native time
    514 	stx	%l0, [%l4 + %lo(hres_last_tick)]! prev = current
    515 	! convert native time to nsecs
    516 	NATIVE_TIME_TO_NSEC_SCALE(%l0, %l5, %l2, NSEC_SHIFT)
    517 
    518 	sub	%l0, %g1, %i1			! get accurate nsec delta
    519 
    520 	ldx	[%l4 + %lo(hrtime_base)], %l1
    521 	cmp	%l1, %l0
    522 	bg,pn	%xcc, 9f
    523 	  nop
    524 
    525 	stx	%l0, [%l4 + %lo(hrtime_base)]	! update hrtime_base
    526 
    527 	!
    528 	! apply adjustment, if any
    529 	!
    530 	ldx	[%l4 + %lo(hrestime_adj)], %l0	! %l0 = hrestime_adj
    531 	brz	%l0, 2f
    532 						! hrestime_adj == 0 ?
    533 						! yes, skip adjustments
    534 	  clr	%l5				! delay: set adj to zero
    535 	tst	%l0				! is hrestime_adj >= 0 ?
    536 	bge,pt	%xcc, 1f			! yes, go handle positive case
    537 	  srl	%i1, ADJ_SHIFT, %l5		! delay: %l5 = adj
    538 
    539 	addcc	%l0, %l5, %g0			! hrestime_adj < -adj ?
    540 	bl,pt	%xcc, 2f			! yes, use current adj
    541 	  neg	%l5				! delay: %l5 = -adj
    542 	ba,pt	%xcc, 2f
    543 	  mov	%l0, %l5			! no, so set adj = hrestime_adj
    544 1:
    545 	subcc	%l0, %l5, %g0			! hrestime_adj < adj ?
    546 	bl,a,pt	%xcc, 2f			! yes, set adj = hrestime_adj
    547 	  mov	%l0, %l5			! delay: adj = hrestime_adj
    548 2:
    549 	ldx	[%l4 + %lo(timedelta)], %l0	! %l0 = timedelta
    550 	sub	%l0, %l5, %l0			! timedelta -= adj
    551 
    552 	stx	%l0, [%l4 + %lo(timedelta)]	! store new timedelta
    553 	stx	%l0, [%l4 + %lo(hrestime_adj)]	! hrestime_adj = timedelta
    554 
    555 	or	%l4, %lo(hrestime), %l2
    556 	ldn	[%l2], %i2			! %i2:%i3 = hrestime sec:nsec
    557 	ldn	[%l2 + CLONGSIZE], %i3
    558 	add	%i3, %l5, %i3			! hrestime.nsec += adj
    559 	add	%i3, %i1, %i3			! hrestime.nsec += nslt
    560 
    561 	set	NANOSEC, %l5			! %l5 = NANOSEC
    562 	cmp	%i3, %l5
    563 	bl,pt	%xcc, 5f			! if hrestime.tv_nsec < NANOSEC
    564 	  sethi	%hi(one_sec), %i1		! delay
    565 	add	%i2, 0x1, %i2			! hrestime.tv_sec++
    566 	sub	%i3, %l5, %i3			! hrestime.tv_nsec - NANOSEC
    567 	mov	0x1, %l5
    568 	st	%l5, [%i1 + %lo(one_sec)]
    569 5:
    570 	stn	%i2, [%l2]
    571 	stn	%i3, [%l2 + CLONGSIZE]		! store the new hrestime
    572 
    573 	membar	#StoreStore
    574 
    575 	ld	[%l4 + %lo(hres_lock)], %i1
    576 	inc	%i1				! release lock
    577 	st	%i1, [%l4 + %lo(hres_lock)]	! clear hres_lock
    578 
    579 	ret
    580 	restore
    581 
    582 9:
    583 	!
    584 	! release hres_lock
    585 	!
    586 	ld	[%l4 + %lo(hres_lock)], %i1
    587 	inc	%i1
    588 	st	%i1, [%l4 + %lo(hres_lock)]
    589 
    590 	sethi	%hi(hrtime_base_panic), %o0
    591 	call	panic
    592 	  or	%o0, %lo(hrtime_base_panic), %o0
    593 
    594 	SET_SIZE(hres_tick)
    595 
    596 #endif	/* lint */
    597 
    598 #if !defined(lint) && !defined(__lint)
    599 
    600 	.seg	".text"
    601 kstat_q_panic_msg:
    602 	.asciz	"kstat_q_exit: qlen == 0"
    603 
    604 	ENTRY(kstat_q_panic)
    605 	save	%sp, -SA(MINFRAME), %sp
    606 	sethi	%hi(kstat_q_panic_msg), %o0
    607 	call	panic
    608 	  or	%o0, %lo(kstat_q_panic_msg), %o0
    609 	/*NOTREACHED*/
    610 	SET_SIZE(kstat_q_panic)
    611 
    612 #define	BRZPN	brz,pn
    613 #define	BRZPT	brz,pt
    614 
    615 #define	KSTAT_Q_UPDATE(QOP, QBR, QZERO, QRETURN, QTYPE) \
    616 	ld	[%o0 + QTYPE/**/CNT], %o1;	/* %o1 = old qlen */	\
    617 	QOP	%o1, 1, %o2;			/* %o2 = new qlen */	\
    618 	QBR	%o1, QZERO;			/* done if qlen == 0 */	\
    619 	st	%o2, [%o0 + QTYPE/**/CNT];	/* delay: save qlen */	\
    620 	ldx	[%o0 + QTYPE/**/LASTUPDATE], %o3;			\
    621 	ldx	[%o0 + QTYPE/**/TIME], %o4;	/* %o4 = old time */	\
    622 	ldx	[%o0 + QTYPE/**/LENTIME], %o5;	/* %o5 = old lentime */	\
    623 	sub	%g1, %o3, %o2;			/* %o2 = time delta */	\
    624 	mulx	%o1, %o2, %o3;			/* %o3 = cur lentime */	\
    625 	add	%o4, %o2, %o4;			/* %o4 = new time */	\
    626 	add	%o5, %o3, %o5;			/* %o5 = new lentime */	\
    627 	stx	%o4, [%o0 + QTYPE/**/TIME];	/* save time */		\
    628 	stx	%o5, [%o0 + QTYPE/**/LENTIME];	/* save lentime */	\
    629 QRETURN;								\
    630 	stx	%g1, [%o0 + QTYPE/**/LASTUPDATE]; /* lastupdate = now */
    631 
    632 	.align 16
    633 	ENTRY(kstat_waitq_enter)
    634 	GET_NATIVE_TIME(%g1, %g2, %g3)
    635 	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W)
    636 	SET_SIZE(kstat_waitq_enter)
    637 
    638 	.align 16
    639 	ENTRY(kstat_waitq_exit)
    640 	GET_NATIVE_TIME(%g1, %g2, %g3)
    641 	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_W)
    642 	SET_SIZE(kstat_waitq_exit)
    643 
    644 	.align 16
    645 	ENTRY(kstat_runq_enter)
    646 	GET_NATIVE_TIME(%g1, %g2, %g3)
    647 	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R)
    648 	SET_SIZE(kstat_runq_enter)
    649 
    650 	.align 16
    651 	ENTRY(kstat_runq_exit)
    652 	GET_NATIVE_TIME(%g1, %g2, %g3)
    653 	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, retl, KSTAT_IO_R)
    654 	SET_SIZE(kstat_runq_exit)
    655 
    656 	.align 16
    657 	ENTRY(kstat_waitq_to_runq)
    658 	GET_NATIVE_TIME(%g1, %g2, %g3)
    659 	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_W)
    660 	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_R)
    661 	SET_SIZE(kstat_waitq_to_runq)
    662 
    663 	.align 16
    664 	ENTRY(kstat_runq_back_to_waitq)
    665 	GET_NATIVE_TIME(%g1, %g2, %g3)
    666 	KSTAT_Q_UPDATE(sub, BRZPN, kstat_q_panic, 1:, KSTAT_IO_R)
    667 	KSTAT_Q_UPDATE(add, BRZPT, 1f, 1:retl, KSTAT_IO_W)
    668 	SET_SIZE(kstat_runq_back_to_waitq)
    669 
    670 #endif /* lint */
    671 
    672 #ifdef lint
    673 
    674 int64_t timedelta;
    675 hrtime_t hres_last_tick;
    676 volatile timestruc_t hrestime;
    677 int64_t hrestime_adj;
    678 volatile int hres_lock;
    679 uint_t nsec_scale;
    680 hrtime_t hrtime_base;
    681 int traptrace_use_stick;
    682 
    683 #else
    684 	/*
    685 	 *  -- WARNING --
    686 	 *
    687 	 * The following variables MUST be together on a 128-byte boundary.
    688 	 * In addition to the primary performance motivation (having them all
    689 	 * on the same cache line(s)), code here and in the GET*TIME() macros
    690 	 * assumes that they all have the same high 22 address bits (so
    691 	 * there's only one sethi).
    692 	 */
    693 	.seg	".data"
    694 	.global	timedelta, hres_last_tick, hrestime, hrestime_adj
    695 	.global	hres_lock, nsec_scale, hrtime_base, traptrace_use_stick
    696 	.global	nsec_shift, adj_shift
    697 
    698 	/* XXX - above comment claims 128-bytes is necessary */
    699 	.align	64
    700 timedelta:
    701 	.word	0, 0		/* int64_t */
    702 hres_last_tick:
    703 	.word	0, 0		/* hrtime_t */
    704 hrestime:
    705 	.nword	0, 0		/* 2 longs */
    706 hrestime_adj:
    707 	.word	0, 0		/* int64_t */
    708 hres_lock:
    709 	.word	0
    710 nsec_scale:
    711 	.word	0
    712 hrtime_base:
    713 	.word	0, 0
    714 traptrace_use_stick:
    715 	.word	0
    716 nsec_shift:
    717 	.word	NSEC_SHIFT
    718 adj_shift:
    719 	.word	ADJ_SHIFT
    720 
    721 #endif
    722 
    723 
    724 /*
    725  * drv_usecwait(clock_t n)	[DDI/DKI - section 9F]
    726  * usec_delay(int n)		[compatibility - should go one day]
    727  * Delay by spinning.
    728  *
    729  * delay for n microseconds.  numbers <= 0 delay 1 usec
    730  *
    731  * With UltraSPARC-III the combination of supporting mixed-speed CPUs
    732  * and variable clock rate for power management requires that we
    733  * use %stick to implement this routine.
    734  */
    735 
    736 #if defined(lint)
    737 
    738 /*ARGSUSED*/
    739 void
    740 drv_usecwait(clock_t n)
    741 {}
    742 
    743 /*ARGSUSED*/
    744 void
    745 usec_delay(int n)
    746 {}
    747 
    748 #else	/* lint */
    749 
    750 	ENTRY(drv_usecwait)
    751 	ALTENTRY(usec_delay)
    752 	brlez,a,pn %o0, 0f
    753 	  mov	1, %o0
    754 0:
    755 	sethi	%hi(sticks_per_usec), %o1
    756 	lduw	[%o1 + %lo(sticks_per_usec)], %o1
    757 	mulx	%o1, %o0, %o1		! Scale usec to ticks
    758 	inc	%o1			! We don't start on a tick edge
    759 	GET_NATIVE_TIME(%o2, %o3, %o4)
    760 	add	%o1, %o2, %o1
    761 
    762 1:	cmp	%o1, %o2
    763 	GET_NATIVE_TIME(%o2, %o3, %o4)
    764 	bgeu,pt	%xcc, 1b
    765 	  nop
    766 	retl
    767 	  nop
    768 	SET_SIZE(usec_delay)
    769 	SET_SIZE(drv_usecwait)
    770 #endif	/* lint */
    771 
    772 #if defined(lint)
    773 
    774 /* ARGSUSED */
    775 void
    776 pil14_interrupt(int level)
    777 {}
    778 
    779 #else
    780 
    781 /*
    782  * Level-14 interrupt prologue.
    783  */
    784 	ENTRY_NP(pil14_interrupt)
    785 	CPU_ADDR(%g1, %g2)
    786 	rdpr	%pil, %g6			! %g6 = interrupted PIL
    787 	stn	%g6, [%g1 + CPU_PROFILE_PIL]	! record interrupted PIL
    788 	rdpr	%tstate, %g6
    789 	rdpr	%tpc, %g5
    790 	btst	TSTATE_PRIV, %g6		! trap from supervisor mode?
    791 	bnz,a,pt %xcc, 1f
    792 	  stn	%g5, [%g1 + CPU_PROFILE_PC]	! if so, record kernel PC
    793 	stn	%g5, [%g1 + CPU_PROFILE_UPC]	! if not, record user PC
    794 	ba	pil_interrupt_common		! must be large-disp branch
    795 	  stn	%g0, [%g1 + CPU_PROFILE_PC]	! zero kernel PC
    796 1:	ba	pil_interrupt_common		! must be large-disp branch
    797 	  stn	%g0, [%g1 + CPU_PROFILE_UPC]	! zero user PC
    798 	SET_SIZE(pil14_interrupt)
    799 
    800 	ENTRY_NP(tick_rtt)
    801 	!
    802 	! Load TICK_COMPARE into %o5; if bit 63 is set, then TICK_COMPARE is
    803 	! disabled.  If TICK_COMPARE is enabled, we know that we need to
    804 	! reenqueue the interrupt request structure.  We'll then check TICKINT
    805 	! in SOFTINT; if it's set, then we know that we were in a TICK_COMPARE
    806 	! interrupt.  In this case, TICK_COMPARE may have been rewritten
    807 	! recently; we'll compare %o5 to the current time to verify that it's
    808 	! in the future.
    809 	!
    810 	! Note that %o5 is live until after 1f.
    811 	! XXX - there is a subroutine call while %o5 is live!
    812 	!
    813 	RD_TICKCMPR(%o5, %g1)
    814 	srlx	%o5, TICKINT_DIS_SHFT, %g1
    815 	brnz,pt	%g1, 2f
    816 	  nop
    817 
    818 	rdpr 	%pstate, %g5
    819 	andn	%g5, PSTATE_IE, %g1
    820 	wrpr	%g0, %g1, %pstate		! Disable vec interrupts
    821 
    822 	sethi	%hi(cbe_level14_inum), %o1
    823 	ldx	[%o1 + %lo(cbe_level14_inum)], %o1
    824 	call	intr_enqueue_req ! preserves %o5 and %g5
    825 	  mov	PIL_14, %o0
    826 
    827 	! Check SOFTINT for TICKINT/STICKINT
    828 	rd	SOFTINT, %o4
    829 	set	(TICK_INT_MASK | STICK_INT_MASK), %o0
    830 	andcc	%o4, %o0, %g0
    831 	bz,a,pn	%icc, 2f
    832 	  wrpr	%g0, %g5, %pstate		! Enable vec interrupts
    833 
    834 	! clear TICKINT/STICKINT
    835 	wr	%o0, CLEAR_SOFTINT
    836 
    837 	!
    838 	! Now that we've cleared TICKINT, we can reread %tick and confirm
    839 	! that the value we programmed is still in the future.  If it isn't,
    840 	! we need to reprogram TICK_COMPARE to fire as soon as possible.
    841 	!
    842 	GET_NATIVE_TIME(%o0, %g1, %g2)		! %o0 = tick
    843 	sllx	%o0, 1, %o0			! Clear the DIS bit
    844 	srlx	%o0, 1, %o0
    845 	cmp	%o5, %o0			! In the future?
    846 	bg,a,pt	%xcc, 2f			! Yes, drive on.
    847 	  wrpr	%g0, %g5, %pstate		!   delay: enable vec intr
    848 
    849 	!
    850 	! If we're here, then we have programmed TICK_COMPARE with a %tick
    851 	! which is in the past; we'll now load an initial step size, and loop
    852 	! until we've managed to program TICK_COMPARE to fire in the future.
    853 	!
    854 	mov	8, %o4				! 8 = arbitrary inital step
    855 1:	add	%o0, %o4, %o5			! Add the step
    856 	WR_TICKCMPR(%o5,%g1,%g2,__LINE__)	! Write to TICK_CMPR
    857 	GET_NATIVE_TIME(%o0, %g1, %g2)		! %o0 = tick
    858 	sllx	%o0, 1, %o0			! Clear the DIS bit
    859 	srlx	%o0, 1, %o0
    860 	cmp	%o5, %o0			! In the future?
    861 	bg,a,pt	%xcc, 2f			! Yes, drive on.
    862 	  wrpr	%g0, %g5, %pstate		!    delay: enable vec intr
    863 	ba	1b				! No, try again.
    864 	  sllx	%o4, 1, %o4			!    delay: double step size
    865 
    866 2:	ba	current_thread_complete
    867 	  nop
    868 	SET_SIZE(tick_rtt)
    869 
    870 #endif /* lint */
    871 
    872 #if defined(lint)
    873 
    874 /* ARGSUSED */
    875 void
    876 pil15_interrupt(int level)
    877 {}
    878 
    879 #else   /* lint */
    880 
    881 /*
    882  * Level-15 interrupt prologue.
    883  */
    884        ENTRY_NP(pil15_interrupt)
    885        CPU_ADDR(%g1, %g2)
    886        rdpr    %tstate, %g6
    887        rdpr    %tpc, %g5
    888        btst    TSTATE_PRIV, %g6                ! trap from supervisor mode?
    889        bnz,a,pt %xcc, 1f
    890        stn     %g5, [%g1 + CPU_CPCPROFILE_PC]  ! if so, record kernel PC
    891        stn     %g5, [%g1 + CPU_CPCPROFILE_UPC] ! if not, record user PC
    892        ba      pil15_epilogue                  ! must be large-disp branch
    893        stn     %g0, [%g1 + CPU_CPCPROFILE_PC]  ! zero kernel PC
    894 1:     ba      pil15_epilogue                  ! must be large-disp branch
    895        stn     %g0, [%g1 + CPU_CPCPROFILE_UPC] ! zero user PC
    896        SET_SIZE(pil15_interrupt)
    897 
    898 #endif  /* lint */
    899 
    900 #if defined(lint)
    901 /*
    902  * Prefetch a page_t for write or read, this assumes a linear
    903  * scan of sequential page_t's.
    904  */
    905 /*ARGSUSED*/
    906 void
    907 prefetch_page_w(void *pp)
    908 {}
    909 
    910 /*ARGSUSED*/
    911 void
    912 prefetch_page_r(void *pp)
    913 {}
    914 #else	/* lint */
    915 
    916 /* XXXQ These should be inline templates, not functions */
    917         ENTRY(prefetch_page_w)
    918         retl
    919 	  nop
    920         SET_SIZE(prefetch_page_w)
    921 
    922         ENTRY(prefetch_page_r)
    923         retl
    924 	  nop
    925         SET_SIZE(prefetch_page_r)
    926 
    927 #endif	/* lint */
    928 
    929 #if defined(lint)
    930 /*
    931  * Prefetch struct smap for write.
    932  */
    933 /*ARGSUSED*/
    934 void
    935 prefetch_smap_w(void *smp)
    936 {}
    937 #else	/* lint */
    938 
    939 /* XXXQ These should be inline templates, not functions */
    940 	ENTRY(prefetch_smap_w)
    941 	retl
    942 	  nop
    943 	SET_SIZE(prefetch_smap_w)
    944 
    945 #endif	/* lint */
    946 
    947 /*
    948  * Generic sun4v MMU and Cache operations.
    949  */
    950 
    951 #if defined(lint)
    952 
    953 /*ARGSUSED*/
    954 void
    955 vtag_flushpage(caddr_t vaddr, uint64_t sfmmup)
    956 {}
    957 
    958 /*ARGSUSED*/
    959 void
    960 vtag_flushall(void)
    961 {}
    962 
    963 /*ARGSUSED*/
    964 void
    965 vtag_unmap_perm_tl1(uint64_t vaddr, uint64_t ctxnum)
    966 {}
    967 
    968 /*ARGSUSED*/
    969 void
    970 vtag_flushpage_tl1(uint64_t vaddr, uint64_t sfmmup)
    971 {}
    972 
    973 /*ARGSUSED*/
    974 void
    975 vtag_flush_pgcnt_tl1(uint64_t vaddr, uint64_t sfmmup_pgcnt)
    976 {}
    977 
    978 /*ARGSUSED*/
    979 void
    980 vtag_flushall_tl1(uint64_t dummy1, uint64_t dummy2)
    981 {}
    982 
    983 /*ARGSUSED*/
    984 void
    985 vac_flushpage(pfn_t pfnum, int vcolor)
    986 {}
    987 
    988 /*ARGSUSED*/
    989 void
    990 vac_flushpage_tl1(uint64_t pfnum, uint64_t vcolor)
    991 {}
    992 
    993 /*ARGSUSED*/
    994 void
    995 flush_instr_mem(caddr_t vaddr, size_t len)
    996 {}
    997 
    998 #else	/* lint */
    999 
   1000 	ENTRY_NP(vtag_flushpage)
   1001 	/*
   1002 	 * flush page from the tlb
   1003 	 *
   1004 	 * %o0 = vaddr
   1005 	 * %o1 = sfmmup
   1006 	 */
   1007 	SFMMU_CPU_CNUM(%o1, %g1, %g2)   /* %g1 = sfmmu cnum on this CPU */
   1008 
   1009 	mov	%g1, %o1
   1010 	mov	MAP_ITLB | MAP_DTLB, %o2
   1011 	ta	MMU_UNMAP_ADDR
   1012 	brz,pt	%o0, 1f
   1013 	  nop
   1014 	ba	panic_bad_hcall
   1015 	  mov	MMU_UNMAP_ADDR, %o1
   1016 1:
   1017  	retl
   1018 	  nop
   1019 	SET_SIZE(vtag_flushpage)
   1020 
   1021 	ENTRY_NP(vtag_flushall)
   1022 	mov	%g0, %o0	! XXX no cpu list yet
   1023 	mov	%g0, %o1	! XXX no cpu list yet
   1024 	mov	MAP_ITLB | MAP_DTLB, %o2
   1025 	mov	MMU_DEMAP_ALL, %o5
   1026 	ta	FAST_TRAP
   1027 	brz,pt	%o0, 1f
   1028 	  nop
   1029 	ba	panic_bad_hcall
   1030 	  mov	MMU_DEMAP_ALL, %o1
   1031 1:
   1032 	retl
   1033 	  nop
   1034 	SET_SIZE(vtag_flushall)
   1035 
   1036 	ENTRY_NP(vtag_unmap_perm_tl1)
   1037 	/*
   1038 	 * x-trap to unmap perm map entry
   1039 	 * %g1 = vaddr
   1040 	 * %g2 = ctxnum (KCONTEXT only)
   1041 	 */
   1042 	mov	%o0, %g3
   1043 	mov	%o1, %g4
   1044 	mov	%o2, %g5
   1045 	mov	%o5, %g6
   1046 	mov	%g1, %o0
   1047 	mov	%g2, %o1
   1048 	mov	MAP_ITLB | MAP_DTLB, %o2
   1049 	mov	UNMAP_PERM_ADDR, %o5
   1050 	ta	FAST_TRAP
   1051 	brz,pt	%o0, 1f
   1052 	nop
   1053 
   1054 	mov	PTL1_BAD_HCALL, %g1
   1055 
   1056 	cmp	%o0, H_ENOMAP
   1057 	move	%xcc, PTL1_BAD_HCALL_UNMAP_PERM_ENOMAP, %g1
   1058 
   1059 	cmp	%o0, H_EINVAL
   1060 	move	%xcc, PTL1_BAD_HCALL_UNMAP_PERM_EINVAL, %g1
   1061 
   1062 	ba,a	ptl1_panic
   1063 1:
   1064 	mov	%g6, %o5
   1065 	mov	%g5, %o2
   1066 	mov	%g4, %o1
   1067 	mov	%g3, %o0
   1068 	retry
   1069 	SET_SIZE(vtag_unmap_perm_tl1)
   1070 
   1071 	ENTRY_NP(vtag_flushpage_tl1)
   1072 	/*
   1073 	 * x-trap to flush page from tlb and tsb
   1074 	 *
   1075 	 * %g1 = vaddr, zero-extended on 32-bit kernel
   1076 	 * %g2 = sfmmup
   1077 	 *
   1078 	 * assumes TSBE_TAG = 0
   1079 	 */
   1080 	srln	%g1, MMU_PAGESHIFT, %g1
   1081 	slln	%g1, MMU_PAGESHIFT, %g1			/* g1 = vaddr */
   1082 	mov	%o0, %g3
   1083 	mov	%o1, %g4
   1084 	mov	%o2, %g5
   1085 	mov	%g1, %o0			/* vaddr */
   1086 
   1087 	SFMMU_CPU_CNUM(%g2, %o1, %g6)   /* %o1 = sfmmu cnum on this CPU */
   1088 
   1089 	mov	MAP_ITLB | MAP_DTLB, %o2
   1090 	ta	MMU_UNMAP_ADDR
   1091 	brz,pt	%o0, 1f
   1092 	nop
   1093 	  ba	ptl1_panic
   1094 	mov	PTL1_BAD_HCALL, %g1
   1095 1:
   1096 	mov	%g5, %o2
   1097 	mov	%g4, %o1
   1098 	mov	%g3, %o0
   1099 	membar #Sync
   1100 	retry
   1101 	SET_SIZE(vtag_flushpage_tl1)
   1102 
   1103 	ENTRY_NP(vtag_flush_pgcnt_tl1)
   1104 	/*
   1105 	 * x-trap to flush pgcnt MMU_PAGESIZE pages from tlb
   1106 	 *
   1107 	 * %g1 = vaddr, zero-extended on 32-bit kernel
   1108 	 * %g2 = <sfmmup58|pgcnt6>, (pgcnt - 1) is pass'ed in via pgcnt6 bits.
   1109 	 *
   1110 	 * NOTE: this handler relies on the fact that no
   1111 	 *	interrupts or traps can occur during the loop
   1112 	 *	issuing the TLB_DEMAP operations. It is assumed
   1113 	 *	that interrupts are disabled and this code is
   1114 	 *	fetching from the kernel locked text address.
   1115 	 *
   1116 	 * assumes TSBE_TAG = 0
   1117 	 */
   1118 	srln	%g1, MMU_PAGESHIFT, %g1
   1119 	slln	%g1, MMU_PAGESHIFT, %g1		/* g1 = vaddr */
   1120 	mov	%o0, %g3
   1121 	mov	%o1, %g4
   1122 	mov	%o2, %g5
   1123 
   1124 	and	%g2, SFMMU_PGCNT_MASK, %g7	/* g7 = pgcnt - 1 */
   1125 	add	%g7, 1, %g7			/* g7 = pgcnt */
   1126 
   1127         andn    %g2, SFMMU_PGCNT_MASK, %o0      /* %o0 = sfmmup */
   1128 
   1129 	SFMMU_CPU_CNUM(%o0, %g2, %g6)    /* %g2 = sfmmu cnum on this CPU */
   1130 
   1131 	set	MMU_PAGESIZE, %g6		/* g6 = pgsize */
   1132 
   1133 1:
   1134 	mov	%g1, %o0			/* vaddr */
   1135 	mov	%g2, %o1			/* cnum */
   1136 	mov	MAP_ITLB | MAP_DTLB, %o2
   1137 	ta	MMU_UNMAP_ADDR
   1138 	brz,pt	%o0, 2f
   1139 	  nop
   1140 	ba	ptl1_panic
   1141 	  mov	PTL1_BAD_HCALL, %g1
   1142 2:
   1143 	deccc	%g7				/* decr pgcnt */
   1144 	bnz,pt	%icc,1b
   1145 	  add	%g1, %g6, %g1			/* go to nextpage */
   1146 
   1147 	mov	%g5, %o2
   1148 	mov	%g4, %o1
   1149 	mov	%g3, %o0
   1150 	membar #Sync
   1151 	retry
   1152 	SET_SIZE(vtag_flush_pgcnt_tl1)
   1153 
   1154 	! Not implemented on US1/US2
   1155 	ENTRY_NP(vtag_flushall_tl1)
   1156 	mov	%o0, %g3
   1157 	mov	%o1, %g4
   1158 	mov	%o2, %g5
   1159 	mov	%o3, %g6	! XXXQ not used?
   1160 	mov	%o5, %g7
   1161 	mov	%g0, %o0	! XXX no cpu list yet
   1162 	mov	%g0, %o1	! XXX no cpu list yet
   1163 	mov	MAP_ITLB | MAP_DTLB, %o2
   1164 	mov	MMU_DEMAP_ALL, %o5
   1165 	ta	FAST_TRAP
   1166 	brz,pt	%o0, 1f
   1167 	  nop
   1168 	ba	ptl1_panic
   1169 	  mov	PTL1_BAD_HCALL, %g1
   1170 1:
   1171 	mov	%g7, %o5
   1172 	mov	%g6, %o3	! XXXQ not used?
   1173 	mov	%g5, %o2
   1174 	mov	%g4, %o1
   1175 	mov	%g3, %o0
   1176 	retry
   1177 	SET_SIZE(vtag_flushall_tl1)
   1178 
   1179 /*
   1180  * flush_instr_mem:
   1181  *	Flush a portion of the I-$ starting at vaddr
   1182  * 	%o0 vaddr
   1183  *	%o1 bytes to be flushed
   1184  */
   1185 
   1186 	ENTRY(flush_instr_mem)
   1187 	membar	#StoreStore				! Ensure the stores
   1188 							! are globally visible
   1189 1:
   1190 	flush	%o0
   1191 	subcc	%o1, ICACHE_FLUSHSZ, %o1		! bytes = bytes-0x20
   1192 	bgu,pt	%ncc, 1b
   1193 	  add	%o0, ICACHE_FLUSHSZ, %o0		! vaddr = vaddr+0x20
   1194 
   1195 	retl
   1196 	  nop
   1197 	SET_SIZE(flush_instr_mem)
   1198 
   1199 #endif /* !lint */
   1200 
   1201 #if !defined(CUSTOM_FPZERO)
   1202 
   1203 /*
   1204  * fp_zero() - clear all fp data registers and the fsr
   1205  */
   1206 
   1207 #if defined(lint) || defined(__lint)
   1208 
   1209 void
   1210 fp_zero(void)
   1211 {}
   1212 
   1213 #else	/* lint */
   1214 
   1215 .global	fp_zero_zero
   1216 .align 8
   1217 fp_zero_zero:
   1218 	.xword	0
   1219 
   1220 	ENTRY_NP(fp_zero)
   1221 	sethi	%hi(fp_zero_zero), %o0
   1222 	ldx	[%o0 + %lo(fp_zero_zero)], %fsr
   1223 	ldd	[%o0 + %lo(fp_zero_zero)], %f0
   1224 	fmovd	%f0, %f2
   1225 	fmovd	%f0, %f4
   1226 	fmovd	%f0, %f6
   1227 	fmovd	%f0, %f8
   1228 	fmovd	%f0, %f10
   1229 	fmovd	%f0, %f12
   1230 	fmovd	%f0, %f14
   1231 	fmovd	%f0, %f16
   1232 	fmovd	%f0, %f18
   1233 	fmovd	%f0, %f20
   1234 	fmovd	%f0, %f22
   1235 	fmovd	%f0, %f24
   1236 	fmovd	%f0, %f26
   1237 	fmovd	%f0, %f28
   1238 	fmovd	%f0, %f30
   1239 	fmovd	%f0, %f32
   1240 	fmovd	%f0, %f34
   1241 	fmovd	%f0, %f36
   1242 	fmovd	%f0, %f38
   1243 	fmovd	%f0, %f40
   1244 	fmovd	%f0, %f42
   1245 	fmovd	%f0, %f44
   1246 	fmovd	%f0, %f46
   1247 	fmovd	%f0, %f48
   1248 	fmovd	%f0, %f50
   1249 	fmovd	%f0, %f52
   1250 	fmovd	%f0, %f54
   1251 	fmovd	%f0, %f56
   1252 	fmovd	%f0, %f58
   1253 	fmovd	%f0, %f60
   1254 	retl
   1255 	fmovd	%f0, %f62
   1256 	SET_SIZE(fp_zero)
   1257 
   1258 #endif	/* lint */
   1259 #endif  /* CUSTOM_FPZERO */
   1260