xref: /titanic_41/usr/src/uts/sun4u/vm/mach_sfmmu_asm.s (revision 890e8ff10cfc85bc7d33064a9a30c3e8477b4813)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * SFMMU primitives.  These primitives should only be used by sfmmu
30 * routines.
31 */
32
33#if defined(lint)
34#include <sys/types.h>
35#else	/* lint */
36#include "assym.h"
37#endif	/* lint */
38
39#include <sys/asm_linkage.h>
40#include <sys/machtrap.h>
41#include <sys/machasi.h>
42#include <sys/sun4asi.h>
43#include <sys/pte.h>
44#include <sys/mmu.h>
45#include <vm/hat_sfmmu.h>
46#include <vm/seg_spt.h>
47#include <sys/machparam.h>
48#include <sys/privregs.h>
49#include <sys/scb.h>
50#include <sys/intreg.h>
51#include <sys/machthread.h>
52#include <sys/clock.h>
53#include <sys/trapstat.h>
54
55/*
56 * sfmmu related subroutines
57 */
58
59#if defined (lint)
60
61/*
62 * sfmmu related subroutines
63 */
64
65/* ARGSUSED */
66void
67sfmmu_ctx_steal_tl1(uint64_t sctx, uint64_t rctx)
68{}
69
70/* ARGSUSED */
71void
72sfmmu_raise_tsb_exception(uint64_t sctx, uint64_t rctx)
73{}
74
75/* ARGSUSED */
76void
77sfmmu_itlb_ld(caddr_t vaddr, int ctxnum, tte_t *tte)
78{}
79
80/* ARGSUSED */
81void
82sfmmu_dtlb_ld(caddr_t vaddr, int ctxnum, tte_t *tte)
83{}
84
85int
86sfmmu_getctx_pri()
87{ return(0); }
88
89int
90sfmmu_getctx_sec()
91{ return(0); }
92
93/* ARGSUSED */
94void
95sfmmu_setctx_sec(int ctx)
96{}
97
98/* ARGSUSED */
99void
100sfmmu_load_mmustate(sfmmu_t *sfmmup)
101{
102}
103
104#else	/* lint */
105
106/*
107 * 1. If stealing ctx, flush all TLB entries whose ctx is ctx-being-stolen.
108 * 2. If processor is running in the ctx-being-stolen, set the
109 *    context to the resv context. That is
110 *    If processor in User-mode - pri/sec-ctx both set to ctx-being-stolen,
111 *		change both pri/sec-ctx registers to resv ctx.
112 *    If processor in Kernel-mode - pri-ctx is 0, sec-ctx is ctx-being-stolen,
113 *		just change sec-ctx register to resv ctx. When it returns to
114 *		kernel-mode, user_rtt will change pri-ctx.
115 *
116 * Note: For multiple page size TLB, no need to set page sizes for
117 *       DEMAP context.
118 *
119 * %g1 = ctx being stolen (victim)
120 * %g2 = invalid ctx to replace victim with
121 */
122	ENTRY(sfmmu_ctx_steal_tl1)
123	/*
124	 * Flush TLBs.
125	 */
126	set	MMU_PCONTEXT, %g3
127	set	DEMAP_CTX_TYPE | DEMAP_PRIMARY, %g4
128	ldxa	[%g3]ASI_MMU_CTX, %g5		/* get pri-ctx */
129	sethi	%hi(FLUSH_ADDR), %g6
130	stxa	%g1, [%g3]ASI_MMU_CTX		/* temporarily set our */
131						/*   pri-ctx to victim */
132	stxa	%g0, [%g4]ASI_DTLB_DEMAP	/* flush DTLB */
133	stxa	%g0, [%g4]ASI_ITLB_DEMAP	/* flush ITLB */
134	stxa	%g5, [%g3]ASI_MMU_CTX		/* restore original pri-ctx */
135	flush	%g6				/* ensure stxa's committed */
136	/* fall through to the code below */
137
138	/*
139	 * We enter here if we're just raising a TSB miss
140	 * exception, without switching MMU contexts.  In
141	 * this case, there is no need to flush the TLB.
142	 */
143	ALTENTRY(sfmmu_raise_tsb_exception)
144	!
145	! if (sec-ctx != victim) {
146	!	return
147	! } else {
148	!	if (pri-ctx == victim) {
149	!		write INVALID_CONTEXT to sec-ctx
150	!		write INVALID_CONTEXT to pri-ctx
151	!	} else {
152	!		write INVALID_CONTEXT to sec-ctx
153	!	}
154	! }
155	!
156	cmp	%g1, NUM_LOCKED_CTXS
157	blt,a,pn %icc, ptl1_panic		/* can't steal locked ctx */
158	  mov	PTL1_BAD_CTX_STEAL, %g1
159	set	CTXREG_CTX_MASK, %g6
160	set	MMU_SCONTEXT, %g3
161	ldxa	[%g3]ASI_MMU_CTX, %g5		/* get sec-ctx */
162	and	%g5, %g6, %g5
163	cmp	%g5, %g1			/* is it the victim? */
164	bne,pn	%icc, 2f			/* was our sec-ctx a victim? */
165	  mov	MMU_PCONTEXT, %g7
166	ldxa	[%g7]ASI_MMU_CTX, %g4		/* get pri-ctx */
167	and	%g4, %g6, %g4
168	stxa	%g2, [%g3]ASI_MMU_CTX		/* set sec-ctx to invalid ctx */
169	membar	#Sync
170	cmp	%g1, %g4			/* is it the victim? */
171	bne 	%icc, 2f			/* nope, no need to change it */
172	  nop
173	stxa	%g2, [%g7]ASI_MMU_CTX		/* set pri-ctx to invalid ctx */
174	/* next instruction is retry so no membar sync */
1752:
176	retry
177	SET_SIZE(sfmmu_ctx_steal_tl1)
178
179	ENTRY_NP(sfmmu_itlb_ld)
180	rdpr	%pstate, %o3
181#ifdef DEBUG
182	andcc	%o3, PSTATE_IE, %g0		! If interrupts already
183	bnz,pt %icc, 1f				!   disabled, panic
184	  nop
185
186	sethi	%hi(panicstr), %g1
187	ldx	[%g1 + %lo(panicstr)], %g1
188	tst	%g1
189	bnz,pt	%icc, 1f
190	  nop
191
192	sethi	%hi(sfmmu_panic1), %o0
193	call	panic
194	 or	%o0, %lo(sfmmu_panic1), %o0
1951:
196#endif /* DEBUG */
197	wrpr	%o3, PSTATE_IE, %pstate		! Disable interrupts
198	srln	%o0, MMU_PAGESHIFT, %o0
199	slln	%o0, MMU_PAGESHIFT, %o0		! Clear page offset
200	or	%o0, %o1, %o0
201	ldx	[%o2], %g1
202	set	MMU_TAG_ACCESS, %o5
203#ifdef	CHEETAHPLUS_ERRATUM_34
204	!
205	! If this is Cheetah or derivative and the specified TTE is locked
206	! and hence to be loaded into the T16, fully-associative TLB, we
207	! must avoid Cheetah+ erratum 34.  In Cheetah+ erratum 34, under
208	! certain conditions an ITLB locked index 0 TTE will erroneously be
209	! displaced when a new TTE is loaded via ASI_ITLB_IN.  To avoid
210	! this erratum, we scan the T16 top down for an unlocked TTE and
211	! explicitly load the specified TTE into that index.
212	!
213	GET_CPU_IMPL(%g2)
214	cmp	%g2, CHEETAH_IMPL
215	bl,pn	%icc, 0f
216	  nop
217
218	andcc	%g1, TTE_LCK_INT, %g0
219	bz	%icc, 0f			! Lock bit is not set;
220						!   load normally.
221	  or	%g0, (15 << 3), %g3		! Start searching from the
222						!   top down.
223
2241:
225	ldxa	[%g3]ASI_ITLB_ACCESS, %g4	! Load TTE from t16
226
227	!
228	! If this entry isn't valid, we'll choose to displace it (regardless
229	! of the lock bit).
230	!
231	cmp	%g4, %g0
232	bge	%xcc, 2f			! TTE is > 0 iff not valid
233	  andcc	%g4, TTE_LCK_INT, %g0		! Check for lock bit
234	bz	%icc, 2f			! If unlocked, go displace
235	  nop
236	sub	%g3, (1 << 3), %g3
237	brgz	%g3, 1b				! Still more TLB entries
238	  nop					! to search
239
240	sethi   %hi(sfmmu_panic5), %o0          ! We searched all entries and
241	call    panic                           ! found no unlocked TTE so
242	  or    %o0, %lo(sfmmu_panic5), %o0     ! give up.
243
244
2452:
246	!
247	! We have found an unlocked or non-valid entry; we'll explicitly load
248	! our locked entry here.
249	!
250	sethi	%hi(FLUSH_ADDR), %o1		! Flush addr doesn't matter
251	stxa	%o0, [%o5]ASI_IMMU
252	stxa	%g1, [%g3]ASI_ITLB_ACCESS
253	flush	%o1				! Flush required for I-MMU
254	ba	3f				! Delay slot of ba is empty
255	nop					!   per Erratum 64
256
2570:
258#endif	/* CHEETAHPLUS_ERRATUM_34 */
259	sethi	%hi(FLUSH_ADDR), %o1		! Flush addr doesn't matter
260	stxa	%o0, [%o5]ASI_IMMU
261	stxa	%g1, [%g0]ASI_ITLB_IN
262	flush	%o1				! Flush required for I-MMU
2633:
264	retl
265	  wrpr	%g0, %o3, %pstate		! Enable interrupts
266	SET_SIZE(sfmmu_itlb_ld)
267
268	/*
269	 * Load an entry into the DTLB.
270	 *
271	 * Special handling is required for locked entries since there
272	 * are some TLB slots that are reserved for the kernel but not
273	 * always held locked.  We want to avoid loading locked TTEs
274	 * into those slots since they could be displaced.
275	 */
276	ENTRY_NP(sfmmu_dtlb_ld)
277	rdpr	%pstate, %o3
278#ifdef DEBUG
279	andcc	%o3, PSTATE_IE, %g0		! if interrupts already
280	bnz,pt	%icc, 1f			! disabled, panic
281	  nop
282
283	sethi	%hi(panicstr), %g1
284	ldx	[%g1 + %lo(panicstr)], %g1
285	tst	%g1
286	bnz,pt	%icc, 1f
287	  nop
288
289	sethi	%hi(sfmmu_panic1), %o0
290	call	panic
291	 or	%o0, %lo(sfmmu_panic1), %o0
2921:
293#endif /* DEBUG */
294	wrpr	%o3, PSTATE_IE, %pstate		! disable interrupts
295	srln	%o0, MMU_PAGESHIFT, %o0
296	slln	%o0, MMU_PAGESHIFT, %o0		! clear page offset
297	or	%o0, %o1, %o0			! or in ctx to form tagacc
298	ldx	[%o2], %g1
299	sethi	%hi(ctx_pgsz_array), %o2	! Check for T8s
300	ldn	[%o2 + %lo(ctx_pgsz_array)], %o2
301	brz	%o2, 1f
302	set	MMU_TAG_ACCESS, %o5
303	ldub	[%o2 + %o1], %o2		! Cheetah+: set up tag access
304	sll	%o2, TAGACCEXT_SHIFT, %o2	! extension register so entry
305	set	MMU_TAG_ACCESS_EXT, %o4		! can go into T8 if unlocked
306	stxa	%o2,[%o4]ASI_DMMU
307	membar	#Sync
3081:
309	andcc	%g1, TTE_LCK_INT, %g0		! Locked entries require
310	bnz,pn	%icc, 2f			! special handling
311	  sethi	%hi(dtlb_resv_ttenum), %g3
312	stxa	%o0,[%o5]ASI_DMMU		! Load unlocked TTE
313	stxa	%g1,[%g0]ASI_DTLB_IN		! via DTLB_IN
314	membar	#Sync
315	retl
316	  wrpr	%g0, %o3, %pstate		! enable interrupts
3172:
318	ld	[%g3 + %lo(dtlb_resv_ttenum)], %g3
319	sll	%g3, 3, %g3			! First reserved idx in TLB 0
320	sub	%g3, (1 << 3), %g3		! Decrement idx
3213:
322	ldxa	[%g3]ASI_DTLB_ACCESS, %g4	! Load TTE from TLB 0
323	!
324	! If this entry isn't valid, we'll choose to displace it (regardless
325	! of the lock bit).
326	!
327	brgez,pn %g4, 4f			! TTE is > 0 iff not valid
328	  nop
329	andcc	%g4, TTE_LCK_INT, %g0		! Check for lock bit
330	bz,pn	%icc, 4f			! If unlocked, go displace
331	  nop
332	sub	%g3, (1 << 3), %g3		! Decrement idx
333	brgez	%g3, 3b
334	  nop
335	sethi	%hi(sfmmu_panic5), %o0		! We searched all entries and
336	call	panic				! found no unlocked TTE so
337	  or	%o0, %lo(sfmmu_panic5), %o0	! give up.
3384:
339	stxa	%o0,[%o5]ASI_DMMU		! Setup tag access
340#ifdef	OLYMPUS_SHARED_FTLB
341	stxa	%g1,[%g0]ASI_DTLB_IN
342#else
343	stxa	%g1,[%g3]ASI_DTLB_ACCESS	! Displace entry at idx
344#endif
345	membar	#Sync
346	retl
347	  wrpr	%g0, %o3, %pstate		! enable interrupts
348	SET_SIZE(sfmmu_dtlb_ld)
349
350	ENTRY_NP(sfmmu_getctx_pri)
351	set	MMU_PCONTEXT, %o0
352	retl
353	  ldxa	[%o0]ASI_MMU_CTX, %o0
354	SET_SIZE(sfmmu_getctx_pri)
355
356	ENTRY_NP(sfmmu_getctx_sec)
357	set	MMU_SCONTEXT, %o0
358	set	CTXREG_CTX_MASK, %o1
359	ldxa	[%o0]ASI_MMU_CTX, %o0
360	retl
361	and	%o0, %o1, %o0
362	SET_SIZE(sfmmu_getctx_sec)
363
364	/*
365	 * Set the secondary context register for this process.
366	 * %o0 = context number for this process.
367	 */
368	ENTRY_NP(sfmmu_setctx_sec)
369	/*
370	 * From resume we call sfmmu_setctx_sec with interrupts disabled.
371	 * But we can also get called from C with interrupts enabled. So,
372	 * we need to check first. Also, resume saves state in %o3 and %o5
373	 * so we can't use those registers here.
374	 */
375
376	/* If interrupts are not disabled, then disable them */
377	rdpr	%pstate, %g1
378	btst	PSTATE_IE, %g1
379	bnz,a,pt %icc, 1f
380	wrpr	%g1, PSTATE_IE, %pstate		/* disable interrupts */
3811:
382	mov	MMU_SCONTEXT, %o1
383	sethi	%hi(ctx_pgsz_array), %g2
384	ldn	[%g2 + %lo(ctx_pgsz_array)], %g2
385	brz	%g2, 2f
386	nop
387	ldub	[%g2 + %o0], %g2
388	sll	%g2, CTXREG_EXT_SHIFT, %g2
389	or	%g2, %o0, %o0
3902:
391	sethi	%hi(FLUSH_ADDR), %o4
392	stxa	%o0, [%o1]ASI_MMU_CTX		/* set 2nd context reg. */
393	flush	%o4
394
395	btst	PSTATE_IE, %g1
396	bnz,a,pt %icc, 1f
397	wrpr	%g0, %g1, %pstate		/* enable interrupts */
3981:	retl
399	nop
400	SET_SIZE(sfmmu_setctx_sec)
401
402	/*
403	 * set ktsb_phys to 1 if the processor supports ASI_QUAD_LDD_PHYS.
404	 * returns the detection value in %o0.
405	 *
406	 * Currently ASI_QUAD_LDD_PHYS is supported in processors as follows
407	 *  - cheetah+ and later (greater or equal to CHEETAH_PLUS_IMPL)
408	 *  - FJ OPL Olympus-C and later  (less than SPITFIRE_IMPL)
409	 *
410	 */
411	ENTRY_NP(sfmmu_setup_4lp)
412	GET_CPU_IMPL(%o0);
413	cmp	%o0, CHEETAH_PLUS_IMPL
414	bge,pt	%icc, 4f
415	  mov	1, %o1
416	cmp	%o0, SPITFIRE_IMPL
417	bge,a,pn %icc, 3f
418	  clr	%o1
4194:
420	set	ktsb_phys, %o2
421	st	%o1, [%o2]
4223:	retl
423	mov	%o1, %o0
424	SET_SIZE(sfmmu_setup_4lp)
425
426
427	/*
428	 * Called to load MMU registers and tsbmiss area
429	 * for the active process.  This function should
430	 * only be called from TL=0.
431	 *
432	 * %o0 - hat pointer
433	 */
434	ENTRY_NP(sfmmu_load_mmustate)
435	/*
436	 * From resume we call sfmmu_load_mmustate with interrupts disabled.
437	 * But we can also get called from C with interrupts enabled. So,
438	 * we need to check first. Also, resume saves state in %o5 and we
439	 * can't use this register here.
440	 */
441
442	sethi	%hi(ksfmmup), %o3
443	ldx	[%o3 + %lo(ksfmmup)], %o3
444	cmp	%o3, %o0
445	be,pn	%xcc, 3f			! if kernel as, do nothing
446	  nop
447
448	/* If interrupts are not disabled, then disable them */
449	rdpr	%pstate, %g1
450	btst	PSTATE_IE, %g1
451	bnz,a,pt %icc, 1f
452	wrpr	%g1, PSTATE_IE, %pstate		! disable interrupts
4531:
454	/*
455	 * We need to set up the TSB base register, tsbmiss
456	 * area, and load locked TTE(s) for the TSB.
457	 */
458	ldx	[%o0 + SFMMU_TSB], %o1		! %o1 = first tsbinfo
459	ldx	[%o1 + TSBINFO_NEXTPTR], %g2	! %g2 = second tsbinfo
460
461#ifdef UTSB_PHYS
462	/*
463	 * UTSB_PHYS accesses user TSBs via physical addresses.  The first
464	 * TSB is in the MMU I/D TSB Base registers.  The second TSB uses a
465	 * designated ASI_SCRATCHPAD register as a pseudo TSB base register.
466	 */
467	MAKE_UTSBREG_PHYS(%o1, %o2, %o3)	! %o2 = first utsbreg
468	LOAD_TSBREG(%o2, %o3, %o4)		! write TSB base register
469
470	brz,a,pt %g2, 2f
471	  mov   -1, %o2				! use -1 if no second TSB
472
473	MAKE_UTSBREG_PHYS(%g2, %o2, %o3)	! %o2 = second utsbreg
4742:
475	LOAD_2ND_TSBREG(%o2, %o3)		! write 2nd pseudo TSB base register
476#else /* UTSB_PHYS */
477	brz,pt  %g2, 4f
478	  nop
479	/*
480	 * We have a second TSB for this process, so we need to
481	 * encode data for both the first and second TSB in our single
482	 * TSB base register.  See hat_sfmmu.h for details on what bits
483	 * correspond to which TSB.
484	 * We also need to load a locked TTE into the TLB for the second TSB
485	 * in this case.
486	 */
487	MAKE_TSBREG_SECTSB(%o2, %o1, %g2, %o3, %o4, %g3, sfmmu_tsb_2nd)
488	! %o2 = tsbreg
489	sethi	%hi(utsb4m_dtlb_ttenum), %o3
490	sethi	%hi(utsb4m_vabase), %o4
491	ld	[%o3 + %lo(utsb4m_dtlb_ttenum)], %o3
492	ldx	[%o4 + %lo(utsb4m_vabase)], %o4	! %o4 = TLB tag for sec TSB
493	sll	%o3, DTACC_SHIFT, %o3		! %o3 = sec TSB TLB index
494	RESV_OFFSET(%g2, %o4, %g3, sfmmu_tsb_2nd)	! or-in bits of TSB VA
495	LOAD_TSBTTE(%g2, %o3, %o4, %g3)		! load sec TSB locked TTE
496	sethi	%hi(utsb_vabase), %g3
497	ldx	[%g3 + %lo(utsb_vabase)], %g3	! %g3 = TLB tag for first TSB
498	ba,pt	%xcc, 5f
499	  nop
500
5014:	sethi	%hi(utsb_vabase), %g3
502	ldx	[%g3 + %lo(utsb_vabase)], %g3	! %g3 = TLB tag for first TSB
503	MAKE_TSBREG(%o2, %o1, %g3, %o3, %o4, sfmmu_tsb_1st)	! %o2 = tsbreg
504
5055:	LOAD_TSBREG(%o2, %o3, %o4)		! write TSB base register
506
507	/*
508	 * Load the TTE for the first TSB at the appropriate location in
509	 * the TLB
510	 */
511	sethi	%hi(utsb_dtlb_ttenum), %o2
512	ld	[%o2 + %lo(utsb_dtlb_ttenum)], %o2
513	sll	%o2, DTACC_SHIFT, %o2		! %o1 = first TSB TLB index
514	RESV_OFFSET(%o1, %g3, %o3, sfmmu_tsb_1st)	! or-in bits of TSB VA
515	LOAD_TSBTTE(%o1, %o2, %g3, %o4)		! load first TSB locked TTE
516#endif /* UTSB_PHYS */
517
5186:	ldx	[%o0 + SFMMU_ISMBLKPA], %o1	! copy members of sfmmu
519	CPU_TSBMISS_AREA(%o2, %o3)		! we need to access from
520	stx	%o1, [%o2 + TSBMISS_ISMBLKPA]	! sfmmu_tsb_miss into the
521	lduh	[%o0 + SFMMU_FLAGS], %o3	! per-CPU tsbmiss area.
522	stx	%o0, [%o2 + TSBMISS_UHATID]
523	stuh	%o3, [%o2 + TSBMISS_HATFLAGS]
524
525	btst	PSTATE_IE, %g1
526	bnz,a,pt %icc, 3f
527	wrpr	%g0, %g1, %pstate		! enable interrupts
5283:	retl
529	nop
530	SET_SIZE(sfmmu_load_mmustate)
531
532#endif /* lint */
533
534#if defined (lint)
535/*
536 * Invalidate all of the entries within the tsb, by setting the inv bit
537 * in the tte_tag field of each tsbe.
538 *
539 * We take advantage of the fact TSBs are page aligned and a multiple of
540 * PAGESIZE to use block stores.
541 *
542 * See TSB_LOCK_ENTRY and the miss handlers for how this works in practice
543 * (in short, we set all bits in the upper word of the tag, and we give the
544 * invalid bit precedence over other tag bits in both places).
545 */
546/* ARGSUSED */
547void
548sfmmu_inv_tsb_fast(caddr_t tsb_base, uint_t tsb_bytes)
549{}
550
551#else /* lint */
552
553#define	VIS_BLOCKSIZE	64
554
555	ENTRY(sfmmu_inv_tsb_fast)
556
557	! Get space for aligned block of saved fp regs.
558	save	%sp, -SA(MINFRAME + 2*VIS_BLOCKSIZE), %sp
559
560	! kpreempt_disable();
561	ldsb	[THREAD_REG + T_PREEMPT], %l3
562	inc	%l3
563	stb	%l3, [THREAD_REG + T_PREEMPT]
564
565	! See if fpu was in use.  If it was, we need to save off the
566	! floating point registers to the stack.
567	rd	%fprs, %l0			! %l0 = cached copy of fprs
568	btst	FPRS_FEF, %l0
569	bz,pt	%icc, 4f
570	  nop
571
572	! save in-use fpregs on stack
573	membar	#Sync				! make sure tranx to fp regs
574						! have completed
575	add	%fp, STACK_BIAS - 65, %l1	! get stack frame for fp regs
576	and	%l1, -VIS_BLOCKSIZE, %l1	! block align frame
577	stda	%d0, [%l1]ASI_BLK_P		! %l1 = addr of saved fp regs
578
579	! enable fp
5804:	membar	#StoreStore|#StoreLoad|#LoadStore
581	wr	%g0, FPRS_FEF, %fprs
582	wr	%g0, ASI_BLK_P, %asi
583
584	! load up FP registers with invalid TSB tag.
585	fone	%d0			! ones in tag
586	fzero	%d2			! zeros in TTE
587	fone	%d4			! ones in tag
588	fzero	%d6			! zeros in TTE
589	fone	%d8			! ones in tag
590	fzero	%d10			! zeros in TTE
591	fone	%d12			! ones in tag
592	fzero	%d14			! zeros in TTE
593	ba,pt	%xcc, .sfmmu_inv_doblock
594	  mov	(4*VIS_BLOCKSIZE), %i4	! we do 4 stda's each loop below
595
596.sfmmu_inv_blkstart:
597      ! stda	%d0, [%i0+192]%asi  ! in dly slot of branch that got us here
598	stda	%d0, [%i0+128]%asi
599	stda	%d0, [%i0+64]%asi
600	stda	%d0, [%i0]%asi
601
602	add	%i0, %i4, %i0
603	sub	%i1, %i4, %i1
604
605.sfmmu_inv_doblock:
606	cmp	%i1, (4*VIS_BLOCKSIZE)	! check for completion
607	bgeu,a	%icc, .sfmmu_inv_blkstart
608	  stda	%d0, [%i0+192]%asi
609
610.sfmmu_inv_finish:
611	membar	#Sync
612	btst	FPRS_FEF, %l0		! saved from above
613	bz,a	.sfmmu_inv_finished
614	  wr	%l0, 0, %fprs		! restore fprs
615
616	! restore fpregs from stack
617	ldda    [%l1]ASI_BLK_P, %d0
618	membar	#Sync
619	wr	%l0, 0, %fprs		! restore fprs
620
621.sfmmu_inv_finished:
622	! kpreempt_enable();
623	ldsb	[THREAD_REG + T_PREEMPT], %l3
624	dec	%l3
625	stb	%l3, [THREAD_REG + T_PREEMPT]
626	ret
627	restore
628	SET_SIZE(sfmmu_inv_tsb_fast)
629
630#endif /* lint */
631
632#if defined(lint)
633
634/*
635 * Prefetch "struct tsbe" while walking TSBs.
636 * prefetch 7 cache lines ahead of where we are at now.
637 * #n_reads is being used since #one_read only applies to
638 * floating point reads, and we are not doing floating point
639 * reads.  However, this has the negative side effect of polluting
640 * the ecache.
641 * The 448 comes from (7 * 64) which is how far ahead of our current
642 * address, we want to prefetch.
643 */
644/*ARGSUSED*/
645void
646prefetch_tsbe_read(struct tsbe *tsbep)
647{}
648
649/* Prefetch the tsbe that we are about to write */
650/*ARGSUSED*/
651void
652prefetch_tsbe_write(struct tsbe *tsbep)
653{}
654
655#else /* lint */
656
657	ENTRY(prefetch_tsbe_read)
658	retl
659	prefetch	[%o0+448], #n_reads
660	SET_SIZE(prefetch_tsbe_read)
661
662	ENTRY(prefetch_tsbe_write)
663	retl
664	prefetch	[%o0], #n_writes
665	SET_SIZE(prefetch_tsbe_write)
666#endif /* lint */
667
668
669#ifndef lint
670#endif	/* lint */
671