xref: /titanic_41/usr/src/uts/sun4v/cpu/common_asm.s (revision cde2885fdf538266ee2a3b08dee2d5075ce8fa2b)
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*/
101void
102tickcmpr_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
1111:
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		!
1232:
124	retl
125	  nop
126	SET_SIZE(tickcmpr_set)
127
128#endif  /* lint */
129
130#if defined(lint)
131
132void
133tickcmpr_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*/
162void
163tick_write_delta(uint64_t delta)
164{}
165
166#else	/* lint */
167
168	.seg	".text"
169tick_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
187int
188tickcmpr_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
206u_longlong_t
207gettick(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
227uint64_t
228gettick_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
248hrtime_t
249gethrtime(void)
250{
251	return ((hrtime_t)0);
252}
253
254hrtime_t
255gethrtime_unscaled(void)
256{
257	return ((hrtime_t)0);
258}
259
260hrtime_t
261gethrtime_max(void)
262{
263	return ((hrtime_t)0);
264}
265
266void
267scalehrtime(hrtime_t *hrt)
268{
269	*hrt = 0;
270}
271
272void
273gethrestime(timespec_t *tp)
274{
275	tp->tv_sec = 0;
276	tp->tv_nsec = 0;
277}
278
279time_t
280gethrestime_sec(void)
281{
282	return (0);
283}
284
285void
286gethrestime_lasttick(timespec_t *tp)
287{
288	tp->tv_sec = 0;
289	tp->tv_nsec = 0;
290}
291
292/*ARGSUSED*/
293void
294hres_tick(void)
295{
296}
297
298void
299panic_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
3351:
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 */ \
3762:	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 */ \
3803:	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 */	\
3864:
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
4170:
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"
488hrtime_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
4977:	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
5019:	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
5068:
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
5441:
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
5482:
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)]
5695:
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
5829:
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"
601kstat_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 */	\
629QRETURN;								\
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
674int64_t timedelta;
675hrtime_t hres_last_tick;
676volatile timestruc_t hrestime;
677int64_t hrestime_adj;
678volatile int hres_lock;
679uint_t nsec_scale;
680hrtime_t hrtime_base;
681int 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
700timedelta:
701	.word	0, 0		/* int64_t */
702hres_last_tick:
703	.word	0, 0		/* hrtime_t */
704hrestime:
705	.nword	0, 0		/* 2 longs */
706hrestime_adj:
707	.word	0, 0		/* int64_t */
708hres_lock:
709	.word	0
710nsec_scale:
711	.word	0
712hrtime_base:
713	.word	0, 0
714traptrace_use_stick:
715	.word	0
716nsec_shift:
717	.word	NSEC_SHIFT
718adj_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*/
739void
740drv_usecwait(clock_t n)
741{}
742
743/*ARGSUSED*/
744void
745usec_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
7540:
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
7621:	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 */
775void
776pil14_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
7961:	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
8551:	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
8662:	ba	current_thread_complete
867	  nop
868	SET_SIZE(tick_rtt)
869
870#endif /* lint */
871
872#if defined(lint)
873
874/* ARGSUSED */
875void
876pil15_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
8941:     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*/
906void
907prefetch_page_w(void *pp)
908{}
909
910/*ARGSUSED*/
911void
912prefetch_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*/
934void
935prefetch_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*/
954void
955vtag_flushpage(caddr_t vaddr, uint64_t sfmmup)
956{}
957
958/*ARGSUSED*/
959void
960vtag_flushall(void)
961{}
962
963/*ARGSUSED*/
964void
965vtag_unmap_perm_tl1(uint64_t vaddr, uint64_t ctxnum)
966{}
967
968/*ARGSUSED*/
969void
970vtag_flushpage_tl1(uint64_t vaddr, uint64_t sfmmup)
971{}
972
973/*ARGSUSED*/
974void
975vtag_flush_pgcnt_tl1(uint64_t vaddr, uint64_t sfmmup_pgcnt)
976{}
977
978/*ARGSUSED*/
979void
980vtag_flushall_tl1(uint64_t dummy1, uint64_t dummy2)
981{}
982
983/*ARGSUSED*/
984void
985vac_flushpage(pfn_t pfnum, int vcolor)
986{}
987
988/*ARGSUSED*/
989void
990vac_flushpage_tl1(uint64_t pfnum, uint64_t vcolor)
991{}
992
993/*ARGSUSED*/
994void
995flush_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
10161:
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
10311:
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
10631:
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
10951:
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
11331:
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
11422:
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
11701:
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
11891:
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
1209void
1210fp_zero(void)
1211{}
1212
1213#else	/* lint */
1214
1215.global	fp_zero_zero
1216.align 8
1217fp_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