8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / sun4u / cpu / spitfire_asm.s
blob37e030c0c10cbb014e7eea00a25cc8d590c28e35
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #if !defined(lint)
29 #include "assym.h"
30 #endif /* lint */
32 #include <sys/asm_linkage.h>
33 #include <sys/mmu.h>
34 #include <vm/hat_sfmmu.h>
35 #include <sys/machparam.h>
36 #include <sys/machcpuvar.h>
37 #include <sys/machthread.h>
38 #include <sys/privregs.h>
39 #include <sys/asm_linkage.h>
40 #include <sys/machasi.h>
41 #include <sys/trap.h>
42 #include <sys/spitregs.h>
43 #include <sys/xc_impl.h>
44 #include <sys/intreg.h>
45 #include <sys/async.h>
47 #ifdef TRAPTRACE
48 #include <sys/traptrace.h>
49 #endif /* TRAPTRACE */
51 #ifndef lint
53 /* BEGIN CSTYLED */
54 #define DCACHE_FLUSHPAGE(arg1, arg2, tmp1, tmp2, tmp3) \
55 ldxa [%g0]ASI_LSU, tmp1 ;\
56 btst LSU_DC, tmp1 /* is dcache enabled? */ ;\
57 bz,pn %icc, 1f ;\
58 sethi %hi(dcache_linesize), tmp1 ;\
59 ld [tmp1 + %lo(dcache_linesize)], tmp1 ;\
60 sethi %hi(dflush_type), tmp2 ;\
61 ld [tmp2 + %lo(dflush_type)], tmp2 ;\
62 cmp tmp2, FLUSHPAGE_TYPE ;\
63 be,pt %icc, 2f ;\
64 sllx arg1, SF_DC_VBIT_SHIFT, arg1 /* tag to compare */ ;\
65 sethi %hi(dcache_size), tmp3 ;\
66 ld [tmp3 + %lo(dcache_size)], tmp3 ;\
67 cmp tmp2, FLUSHMATCH_TYPE ;\
68 be,pt %icc, 3f ;\
69 nop ;\
70 /* \
71 * flushtype = FLUSHALL_TYPE, flush the whole thing \
72 * tmp3 = cache size \
73 * tmp1 = cache line size \
74 */ \
75 sub tmp3, tmp1, tmp2 ;\
76 4: \
77 stxa %g0, [tmp2]ASI_DC_TAG ;\
78 membar #Sync ;\
79 cmp %g0, tmp2 ;\
80 bne,pt %icc, 4b ;\
81 sub tmp2, tmp1, tmp2 ;\
82 ba,pt %icc, 1f ;\
83 nop ;\
84 /* \
85 * flushtype = FLUSHPAGE_TYPE \
86 * arg1 = tag to compare against \
87 * arg2 = virtual color \
88 * tmp1 = cache line size \
89 * tmp2 = tag from cache \
90 * tmp3 = counter \
91 */ \
92 2: \
93 set MMU_PAGESIZE, tmp3 ;\
94 sllx arg2, MMU_PAGESHIFT, arg2 /* color to dcache page */ ;\
95 sub tmp3, tmp1, tmp3 ;\
96 4: \
97 ldxa [arg2 + tmp3]ASI_DC_TAG, tmp2 /* read tag */ ;\
98 btst SF_DC_VBIT_MASK, tmp2 ;\
99 bz,pn %icc, 5f /* branch if no valid sub-blocks */ ;\
100 andn tmp2, SF_DC_VBIT_MASK, tmp2 /* clear out v bits */ ;\
101 cmp tmp2, arg1 ;\
102 bne,pn %icc, 5f /* br if tag miss */ ;\
103 nop ;\
104 stxa %g0, [arg2 + tmp3]ASI_DC_TAG ;\
105 membar #Sync ;\
106 5: \
107 cmp %g0, tmp3 ;\
108 bnz,pt %icc, 4b /* branch if not done */ ;\
109 sub tmp3, tmp1, tmp3 ;\
110 ba,pt %icc, 1f ;\
111 nop ;\
112 /* \
113 * flushtype = FLUSHMATCH_TYPE \
114 * arg1 = tag to compare against \
115 * tmp1 = cache line size \
116 * tmp3 = cache size \
117 * arg2 = counter \
118 * tmp2 = cache tag \
119 */ \
120 3: \
121 sub tmp3, tmp1, arg2 ;\
122 4: \
123 ldxa [arg2]ASI_DC_TAG, tmp2 /* read tag */ ;\
124 btst SF_DC_VBIT_MASK, tmp2 ;\
125 bz,pn %icc, 5f /* br if no valid sub-blocks */ ;\
126 andn tmp2, SF_DC_VBIT_MASK, tmp2 /* clear out v bits */ ;\
127 cmp tmp2, arg1 ;\
128 bne,pn %icc, 5f /* branch if tag miss */ ;\
129 nop ;\
130 stxa %g0, [arg2]ASI_DC_TAG ;\
131 membar #Sync ;\
132 5: \
133 cmp %g0, arg2 ;\
134 bne,pt %icc, 4b /* branch if not done */ ;\
135 sub arg2, tmp1, arg2 ;\
139 * macro that flushes the entire dcache color
141 #define DCACHE_FLUSHCOLOR(arg, tmp1, tmp2) \
142 ldxa [%g0]ASI_LSU, tmp1; \
143 btst LSU_DC, tmp1; /* is dcache enabled? */ \
144 bz,pn %icc, 1f; \
145 sethi %hi(dcache_linesize), tmp1; \
146 ld [tmp1 + %lo(dcache_linesize)], tmp1; \
147 set MMU_PAGESIZE, tmp2; \
148 /* \
149 * arg = virtual color \
150 * tmp2 = page size \
151 * tmp1 = cache line size \
152 */ \
153 sllx arg, MMU_PAGESHIFT, arg; /* color to dcache page */ \
154 sub tmp2, tmp1, tmp2; \
155 2: \
156 stxa %g0, [arg + tmp2]ASI_DC_TAG; \
157 membar #Sync; \
158 cmp %g0, tmp2; \
159 bne,pt %icc, 2b; \
160 sub tmp2, tmp1, tmp2; \
164 * macro that flushes the entire dcache
166 #define DCACHE_FLUSHALL(size, linesize, tmp) \
167 ldxa [%g0]ASI_LSU, tmp; \
168 btst LSU_DC, tmp; /* is dcache enabled? */ \
169 bz,pn %icc, 1f; \
171 sub size, linesize, tmp; \
172 2: \
173 stxa %g0, [tmp]ASI_DC_TAG; \
174 membar #Sync; \
175 cmp %g0, tmp; \
176 bne,pt %icc, 2b; \
177 sub tmp, linesize, tmp; \
181 * macro that flushes the entire icache
183 #define ICACHE_FLUSHALL(size, linesize, tmp) \
184 ldxa [%g0]ASI_LSU, tmp; \
185 btst LSU_IC, tmp; \
186 bz,pn %icc, 1f; \
188 sub size, linesize, tmp; \
189 2: \
190 stxa %g0, [tmp]ASI_IC_TAG; \
191 membar #Sync; \
192 cmp %g0, tmp; \
193 bne,pt %icc, 2b; \
194 sub tmp, linesize, tmp; \
197 #ifdef SF_ERRATA_32
198 #define SF_WORKAROUND(tmp1, tmp2) \
199 sethi %hi(FLUSH_ADDR), tmp2 ;\
200 set MMU_PCONTEXT, tmp1 ;\
201 stxa %g0, [tmp1]ASI_DMMU ;\
202 flush tmp2 ;
203 #else
204 #define SF_WORKAROUND(tmp1, tmp2)
205 #endif /* SF_ERRATA_32 */
208 * arg1 = vaddr
209 * arg2 = ctxnum
210 * - disable interrupts and clear address mask
211 * to access 64 bit physaddr
212 * - Blow out the TLB, flush user page.
213 * . use secondary context.
215 #define VTAG_FLUSHUPAGE(lbl, arg1, arg2, tmp1, tmp2, tmp3, tmp4) \
216 rdpr %pstate, tmp1 ;\
217 andn tmp1, PSTATE_IE, tmp2 ;\
218 wrpr tmp2, 0, %pstate ;\
219 sethi %hi(FLUSH_ADDR), tmp2 ;\
220 set MMU_SCONTEXT, tmp3 ;\
221 ldxa [tmp3]ASI_DMMU, tmp4 ;\
222 or DEMAP_SECOND | DEMAP_PAGE_TYPE, arg1, arg1 ;\
223 cmp tmp4, arg2 ;\
224 be,a,pt %icc, lbl/**/4 ;\
225 nop ;\
226 stxa arg2, [tmp3]ASI_DMMU ;\
227 lbl/**/4: ;\
228 stxa %g0, [arg1]ASI_DTLB_DEMAP ;\
229 stxa %g0, [arg1]ASI_ITLB_DEMAP ;\
230 flush tmp2 ;\
231 be,a,pt %icc, lbl/**/5 ;\
232 nop ;\
233 stxa tmp4, [tmp3]ASI_DMMU ;\
234 flush tmp2 ;\
235 lbl/**/5: ;\
236 wrpr %g0, tmp1, %pstate
240 * macro that flushes all the user entries in dtlb
241 * arg1 = dtlb entries
242 * - Before first compare:
243 * tmp4 = tte
244 * tmp5 = vaddr
245 * tmp6 = cntxnum
247 #define DTLB_FLUSH_UNLOCKED_UCTXS(lbl, arg1, tmp1, tmp2, tmp3, \
248 tmp4, tmp5, tmp6) \
249 lbl/**/0: ;\
250 sllx arg1, 3, tmp3 ;\
251 SF_WORKAROUND(tmp1, tmp2) ;\
252 ldxa [tmp3]ASI_DTLB_ACCESS, tmp4 ;\
253 srlx tmp4, 6, tmp4 ;\
254 andcc tmp4, 1, %g0 ;\
255 bnz,pn %xcc, lbl/**/1 ;\
256 srlx tmp4, 57, tmp4 ;\
257 andcc tmp4, 1, %g0 ;\
258 beq,pn %xcc, lbl/**/1 ;\
259 nop ;\
260 set TAGREAD_CTX_MASK, tmp1 ;\
261 ldxa [tmp3]ASI_DTLB_TAGREAD, tmp2 ;\
262 and tmp2, tmp1, tmp6 ;\
263 andn tmp2, tmp1, tmp5 ;\
264 set KCONTEXT, tmp4 ;\
265 cmp tmp6, tmp4 ;\
266 be lbl/**/1 ;\
267 nop ;\
268 VTAG_FLUSHUPAGE(VD/**/lbl, tmp5, tmp6, tmp1, tmp2, tmp3, tmp4) ;\
269 lbl/**/1: ;\
270 brgz,pt arg1, lbl/**/0 ;\
271 sub arg1, 1, arg1
275 * macro that flushes all the user entries in itlb
276 * arg1 = itlb entries
277 * - Before first compare:
278 * tmp4 = tte
279 * tmp5 = vaddr
280 * tmp6 = cntxnum
282 #define ITLB_FLUSH_UNLOCKED_UCTXS(lbl, arg1, tmp1, tmp2, tmp3, \
283 tmp4, tmp5, tmp6) \
284 lbl/**/0: ;\
285 sllx arg1, 3, tmp3 ;\
286 SF_WORKAROUND(tmp1, tmp2) ;\
287 ldxa [tmp3]ASI_ITLB_ACCESS, tmp4 ;\
288 srlx tmp4, 6, tmp4 ;\
289 andcc tmp4, 1, %g0 ;\
290 bnz,pn %xcc, lbl/**/1 ;\
291 srlx tmp4, 57, tmp4 ;\
292 andcc tmp4, 1, %g0 ;\
293 beq,pn %xcc, lbl/**/1 ;\
294 nop ;\
295 set TAGREAD_CTX_MASK, tmp1 ;\
296 ldxa [tmp3]ASI_ITLB_TAGREAD, tmp2 ;\
297 and tmp2, tmp1, tmp6 ;\
298 andn tmp2, tmp1, tmp5 ;\
299 set KCONTEXT, tmp4 ;\
300 cmp tmp6, tmp4 ;\
301 be lbl/**/1 ;\
302 nop ;\
303 VTAG_FLUSHUPAGE(VI/**/lbl, tmp5, tmp6, tmp1, tmp2, tmp3, tmp4) ;\
304 lbl/**/1: ;\
305 brgz,pt arg1, lbl/**/0 ;\
306 sub arg1, 1, arg1
311 * Macro for getting to offset from 'cpu_private' ptr. The 'cpu_private'
312 * ptr is in the machcpu structure.
313 * r_or_s: Register or symbol off offset from 'cpu_private' ptr.
314 * scr1: Scratch, ptr is returned in this register.
315 * scr2: Scratch
317 #define GET_CPU_PRIVATE_PTR(r_or_s, scr1, scr2, label) \
318 CPU_ADDR(scr1, scr2); \
319 ldn [scr1 + CPU_PRIVATE], scr1; \
320 cmp scr1, 0; \
321 be label; \
322 nop; \
323 add scr1, r_or_s, scr1; \
325 #ifdef HUMMINGBIRD
327 * UltraSPARC-IIe processor supports both 4-way set associative and
328 * direct map E$. For performance reasons, we flush E$ by placing it
329 * in direct map mode for data load/store and restore the state after
330 * we are done flushing it. Keep interrupts off while flushing in this
331 * manner.
333 * We flush the entire ecache by starting at one end and loading each
334 * successive ecache line for the 2*ecache-size range. We have to repeat
335 * the flush operation to guarantee that the entire ecache has been
336 * flushed.
338 * For flushing a specific physical address, we start at the aliased
339 * address and load at set-size stride, wrapping around at 2*ecache-size
340 * boundary and skipping the physical address being flushed. It takes
341 * 10 loads to guarantee that the physical address has been flushed.
344 #define HB_ECACHE_FLUSH_CNT 2
345 #define HB_PHYS_FLUSH_CNT 10 /* #loads to flush specific paddr */
346 #endif /* HUMMINGBIRD */
348 /* END CSTYLED */
350 #endif /* !lint */
353 * Spitfire MMU and Cache operations.
356 #if defined(lint)
358 /*ARGSUSED*/
359 void
360 vtag_flushpage(caddr_t vaddr, uint64_t sfmmup)
363 /*ARGSUSED*/
364 void
365 vtag_flushall(void)
368 /*ARGSUSED*/
369 void
370 vtag_flushall_uctxs(void)
373 /*ARGSUSED*/
374 void
375 vtag_flushpage_tl1(uint64_t vaddr, uint64_t sfmmup)
378 /*ARGSUSED*/
379 void
380 vtag_flush_pgcnt_tl1(uint64_t vaddr, uint64_t sfmmup_pgcnt)
383 /*ARGSUSED*/
384 void
385 vtag_flushall_tl1(uint64_t dummy1, uint64_t dummy2)
388 /*ARGSUSED*/
389 void
390 vac_flushpage(pfn_t pfnum, int vcolor)
393 /*ARGSUSED*/
394 void
395 vac_flushpage_tl1(uint64_t pfnum, uint64_t vcolor)
398 /*ARGSUSED*/
399 void
400 init_mondo(xcfunc_t *func, uint64_t arg1, uint64_t arg2)
403 /*ARGSUSED*/
404 void
405 init_mondo_nocheck(xcfunc_t *func, uint64_t arg1, uint64_t arg2)
408 /*ARGSUSED*/
409 void
410 flush_instr_mem(caddr_t vaddr, size_t len)
413 /*ARGSUSED*/
414 void
415 flush_ecache(uint64_t physaddr, size_t size, size_t linesize)
418 /*ARGSUSED*/
419 void
420 get_ecache_dtag(uint32_t ecache_idx, uint64_t *ecache_data,
421 uint64_t *ecache_tag, uint64_t *oafsr, uint64_t *acc_afsr)
424 /* ARGSUSED */
425 uint64_t
426 get_ecache_tag(uint32_t id, uint64_t *nafsr, uint64_t *acc_afsr)
428 return ((uint64_t)0);
431 /* ARGSUSED */
432 uint64_t
433 check_ecache_line(uint32_t id, uint64_t *acc_afsr)
435 return ((uint64_t)0);
438 /*ARGSUSED*/
439 void
440 kdi_flush_idcache(int dcache_size, int dcache_lsize,
441 int icache_size, int icache_lsize)
444 #else /* lint */
446 ENTRY_NP(vtag_flushpage)
448 * flush page from the tlb
450 * %o0 = vaddr
451 * %o1 = sfmmup
453 rdpr %pstate, %o5
454 #ifdef DEBUG
455 PANIC_IF_INTR_DISABLED_PSTR(%o5, sfdi_label1, %g1)
456 #endif /* DEBUG */
458 * disable ints
460 andn %o5, PSTATE_IE, %o4
461 wrpr %o4, 0, %pstate
464 * Then, blow out the tlb
465 * Interrupts are disabled to prevent the secondary ctx register
466 * from changing underneath us.
468 sethi %hi(ksfmmup), %o3
469 ldx [%o3 + %lo(ksfmmup)], %o3
470 cmp %o3, %o1
471 bne,pt %xcc, 1f ! if not kernel as, go to 1
472 sethi %hi(FLUSH_ADDR), %o3
474 * For KCONTEXT demaps use primary. type = page implicitly
476 stxa %g0, [%o0]ASI_DTLB_DEMAP /* dmmu flush for KCONTEXT */
477 stxa %g0, [%o0]ASI_ITLB_DEMAP /* immu flush for KCONTEXT */
478 flush %o3
479 b 5f
483 * User demap. We need to set the secondary context properly.
484 * %o0 = vaddr
485 * %o1 = sfmmup
486 * %o3 = FLUSH_ADDR
488 SFMMU_CPU_CNUM(%o1, %g1, %g2) /* %g1 = sfmmu cnum on this CPU */
490 set MMU_SCONTEXT, %o4
491 ldxa [%o4]ASI_DMMU, %o2 /* rd old ctxnum */
492 or DEMAP_SECOND | DEMAP_PAGE_TYPE, %o0, %o0
493 cmp %o2, %g1
494 be,pt %icc, 4f
496 stxa %g1, [%o4]ASI_DMMU /* wr new ctxum */
498 stxa %g0, [%o0]ASI_DTLB_DEMAP
499 stxa %g0, [%o0]ASI_ITLB_DEMAP
500 flush %o3
501 be,pt %icc, 5f
503 stxa %o2, [%o4]ASI_DMMU /* restore old ctxnum */
504 flush %o3
506 retl
507 wrpr %g0, %o5, %pstate /* enable interrupts */
508 SET_SIZE(vtag_flushpage)
510 .seg ".text"
511 .flushallmsg:
512 .asciz "sfmmu_asm: unimplemented flush operation"
514 ENTRY_NP(vtag_flushall)
515 sethi %hi(.flushallmsg), %o0
516 call panic
517 or %o0, %lo(.flushallmsg), %o0
518 SET_SIZE(vtag_flushall)
520 ENTRY_NP(vtag_flushall_uctxs)
522 * flush entire DTLB/ITLB.
524 CPU_INDEX(%g1, %g2)
525 mulx %g1, CPU_NODE_SIZE, %g1
526 set cpunodes, %g2
527 add %g1, %g2, %g1
528 lduh [%g1 + ITLB_SIZE], %g2 ! %g2 = # entries in ITLB
529 lduh [%g1 + DTLB_SIZE], %g1 ! %g1 = # entries in DTLB
530 sub %g2, 1, %g2 ! %g2 = # entries in ITLB - 1
531 sub %g1, 1, %g1 ! %g1 = # entries in DTLB - 1
534 ! Flush itlb's
536 ITLB_FLUSH_UNLOCKED_UCTXS(I, %g2, %g3, %g4, %o2, %o3, %o4, %o5)
539 ! Flush dtlb's
541 DTLB_FLUSH_UNLOCKED_UCTXS(D, %g1, %g3, %g4, %o2, %o3, %o4, %o5)
543 membar #Sync
544 retl
547 SET_SIZE(vtag_flushall_uctxs)
549 ENTRY_NP(vtag_flushpage_tl1)
551 * x-trap to flush page from tlb and tsb
553 * %g1 = vaddr, zero-extended on 32-bit kernel
554 * %g2 = sfmmup
556 * assumes TSBE_TAG = 0
558 srln %g1, MMU_PAGESHIFT, %g1
559 slln %g1, MMU_PAGESHIFT, %g1 /* g1 = vaddr */
561 SFMMU_CPU_CNUM(%g2, %g3, %g4) /* %g3 = sfmmu cnum on this CPU */
563 /* We need to set the secondary context properly. */
564 set MMU_SCONTEXT, %g4
565 ldxa [%g4]ASI_DMMU, %g5 /* rd old ctxnum */
566 or DEMAP_SECOND | DEMAP_PAGE_TYPE, %g1, %g1
567 stxa %g3, [%g4]ASI_DMMU /* wr new ctxum */
568 stxa %g0, [%g1]ASI_DTLB_DEMAP
569 stxa %g0, [%g1]ASI_ITLB_DEMAP
570 stxa %g5, [%g4]ASI_DMMU /* restore old ctxnum */
571 membar #Sync
572 retry
573 SET_SIZE(vtag_flushpage_tl1)
575 ENTRY_NP(vtag_flush_pgcnt_tl1)
577 * x-trap to flush pgcnt MMU_PAGESIZE pages from tlb
579 * %g1 = vaddr, zero-extended on 32-bit kernel
580 * %g2 = <sfmmup58 | pgcnt6>
582 * NOTE: this handler relies on the fact that no
583 * interrupts or traps can occur during the loop
584 * issuing the TLB_DEMAP operations. It is assumed
585 * that interrupts are disabled and this code is
586 * fetching from the kernel locked text address.
588 * assumes TSBE_TAG = 0
590 srln %g1, MMU_PAGESHIFT, %g1
591 slln %g1, MMU_PAGESHIFT, %g1 /* g1 = vaddr */
592 or DEMAP_SECOND | DEMAP_PAGE_TYPE, %g1, %g1
594 set SFMMU_PGCNT_MASK, %g4
595 and %g4, %g2, %g3 /* g3 = pgcnt - 1 */
596 add %g3, 1, %g3 /* g3 = pgcnt */
598 andn %g2, SFMMU_PGCNT_MASK, %g2 /* g2 = sfmmup */
600 SFMMU_CPU_CNUM(%g2, %g5, %g6) ! %g5 = sfmmu cnum on this CPU
602 /* We need to set the secondary context properly. */
603 set MMU_SCONTEXT, %g4
604 ldxa [%g4]ASI_DMMU, %g6 /* read old ctxnum */
605 stxa %g5, [%g4]ASI_DMMU /* write new ctxum */
607 set MMU_PAGESIZE, %g2 /* g2 = pgsize */
608 sethi %hi(FLUSH_ADDR), %g5
610 stxa %g0, [%g1]ASI_DTLB_DEMAP
611 stxa %g0, [%g1]ASI_ITLB_DEMAP
612 flush %g5
613 deccc %g3 /* decr pgcnt */
614 bnz,pt %icc,1b
615 add %g1, %g2, %g1 /* go to nextpage */
617 stxa %g6, [%g4]ASI_DMMU /* restore old ctxnum */
618 membar #Sync
619 retry
620 SET_SIZE(vtag_flush_pgcnt_tl1)
622 ! Not implemented on US1/US2
623 ENTRY_NP(vtag_flushall_tl1)
624 retry
625 SET_SIZE(vtag_flushall_tl1)
628 * vac_flushpage(pfnum, color)
629 * Flush 1 8k page of the D-$ with physical page = pfnum
630 * Algorithm:
631 * The spitfire dcache is a 16k direct mapped virtual indexed,
632 * physically tagged cache. Given the pfnum we read all cache
633 * lines for the corresponding page in the cache (determined by
634 * the color). Each cache line is compared with
635 * the tag created from the pfnum. If the tags match we flush
636 * the line.
638 .seg ".data"
639 .align 8
640 .global dflush_type
641 dflush_type:
642 .word FLUSHPAGE_TYPE
643 .seg ".text"
645 ENTRY(vac_flushpage)
647 * flush page from the d$
649 * %o0 = pfnum, %o1 = color
651 DCACHE_FLUSHPAGE(%o0, %o1, %o2, %o3, %o4)
652 retl
654 SET_SIZE(vac_flushpage)
656 ENTRY_NP(vac_flushpage_tl1)
658 * x-trap to flush page from the d$
660 * %g1 = pfnum, %g2 = color
662 DCACHE_FLUSHPAGE(%g1, %g2, %g3, %g4, %g5)
663 retry
664 SET_SIZE(vac_flushpage_tl1)
666 ENTRY(vac_flushcolor)
668 * %o0 = vcolor
670 DCACHE_FLUSHCOLOR(%o0, %o1, %o2)
671 retl
673 SET_SIZE(vac_flushcolor)
675 ENTRY(vac_flushcolor_tl1)
677 * %g1 = vcolor
679 DCACHE_FLUSHCOLOR(%g1, %g2, %g3)
680 retry
681 SET_SIZE(vac_flushcolor_tl1)
684 .global _dispatch_status_busy
685 _dispatch_status_busy:
686 .asciz "ASI_INTR_DISPATCH_STATUS error: busy"
687 .align 4
690 * Determine whether or not the IDSR is busy.
691 * Entry: no arguments
692 * Returns: 1 if busy, 0 otherwise
694 ENTRY(idsr_busy)
695 ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %g1
696 clr %o0
697 btst IDSR_BUSY, %g1
698 bz,a,pt %xcc, 1f
699 mov 1, %o0
701 retl
703 SET_SIZE(idsr_busy)
706 * Setup interrupt dispatch data registers
707 * Entry:
708 * %o0 - function or inumber to call
709 * %o1, %o2 - arguments (2 uint64_t's)
711 .seg "text"
713 ENTRY(init_mondo)
714 #ifdef DEBUG
716 ! IDSR should not be busy at the moment
718 ldxa [%g0]ASI_INTR_DISPATCH_STATUS, %g1
719 btst IDSR_BUSY, %g1
720 bz,pt %xcc, 1f
723 sethi %hi(_dispatch_status_busy), %o0
724 call panic
725 or %o0, %lo(_dispatch_status_busy), %o0
726 #endif /* DEBUG */
728 ALTENTRY(init_mondo_nocheck)
730 ! interrupt vector dispach data reg 0
733 mov IDDR_0, %g1
734 mov IDDR_1, %g2
735 mov IDDR_2, %g3
736 stxa %o0, [%g1]ASI_INTR_DISPATCH
739 ! interrupt vector dispach data reg 1
741 stxa %o1, [%g2]ASI_INTR_DISPATCH
744 ! interrupt vector dispach data reg 2
746 stxa %o2, [%g3]ASI_INTR_DISPATCH
748 retl
749 membar #Sync ! allowed to be in the delay slot
750 SET_SIZE(init_mondo)
753 * Ship mondo to upaid
755 ENTRY_NP(shipit)
756 sll %o0, IDCR_PID_SHIFT, %g1 ! IDCR<18:14> = upa id
757 or %g1, IDCR_OFFSET, %g1 ! IDCR<13:0> = 0x70
758 stxa %g0, [%g1]ASI_INTR_DISPATCH ! interrupt vector dispatch
759 #if defined(SF_ERRATA_54)
760 membar #Sync ! store must occur before load
761 mov 0x20, %g3 ! UDBH Control Register Read
762 ldxa [%g3]ASI_SDB_INTR_R, %g0
763 #endif
764 retl
765 membar #Sync
766 SET_SIZE(shipit)
770 * flush_instr_mem:
771 * Flush a portion of the I-$ starting at vaddr
772 * %o0 vaddr
773 * %o1 bytes to be flushed
776 ENTRY(flush_instr_mem)
777 membar #StoreStore ! Ensure the stores
778 ! are globally visible
780 flush %o0
781 subcc %o1, ICACHE_FLUSHSZ, %o1 ! bytes = bytes-0x20
782 bgu,pt %ncc, 1b
783 add %o0, ICACHE_FLUSHSZ, %o0 ! vaddr = vaddr+0x20
785 retl
787 SET_SIZE(flush_instr_mem)
790 * flush_ecache:
791 * Flush the entire e$ using displacement flush by reading through a
792 * physically contiguous area. We use mmu bypass asi (ASI_MEM) while
793 * reading this physical address range so that data doesn't go to d$.
794 * incoming arguments:
795 * %o0 - 64 bit physical address
796 * %o1 - size of address range to read
797 * %o2 - ecache linesize
799 ENTRY(flush_ecache)
800 #ifndef HUMMINGBIRD
801 b 2f
804 ldxa [%o0 + %o1]ASI_MEM, %g0 ! start reading from physaddr + size
806 subcc %o1, %o2, %o1
807 bcc,a,pt %ncc, 1b
810 #else /* HUMMINGBIRD */
812 * UltraSPARC-IIe processor supports both 4-way set associative
813 * and direct map E$. For performance reasons, we flush E$ by
814 * placing it in direct map mode for data load/store and restore
815 * the state after we are done flushing it. It takes 2 iterations
816 * to guarantee that the entire ecache has been flushed.
818 * Keep the interrupts disabled while flushing E$ in this manner.
820 rdpr %pstate, %g4 ! current pstate (restored later)
821 andn %g4, PSTATE_IE, %g5
822 wrpr %g0, %g5, %pstate ! disable interrupts
824 ! Place E$ in direct map mode for data access
825 or %g0, 1, %g5
826 sllx %g5, HB_UPA_DMAP_DATA_BIT, %g5
827 ldxa [%g0]ASI_UPA_CONFIG, %g1 ! current UPA config (restored later)
828 or %g1, %g5, %g5
829 membar #Sync
830 stxa %g5, [%g0]ASI_UPA_CONFIG ! enable direct map for data access
831 membar #Sync
833 ! flush entire ecache HB_ECACHE_FLUSH_CNT times
834 mov HB_ECACHE_FLUSH_CNT-1, %g5
836 sub %o1, %o2, %g3 ! start from last entry
838 ldxa [%o0 + %g3]ASI_MEM, %g0 ! start reading from physaddr + size
839 subcc %g3, %o2, %g3
840 bgeu,a,pt %ncc, 1b
842 brgz,a,pt %g5, 2b
843 dec %g5
845 membar #Sync
846 stxa %g1, [%g0]ASI_UPA_CONFIG ! restore UPA config reg
847 membar #Sync
848 wrpr %g0, %g4, %pstate ! restore earlier pstate
849 #endif /* HUMMINGBIRD */
851 retl
853 SET_SIZE(flush_ecache)
856 * void kdi_flush_idcache(int dcache_size, int dcache_linesize,
857 * int icache_size, int icache_linesize)
859 ENTRY(kdi_flush_idcache)
860 DCACHE_FLUSHALL(%o0, %o1, %g1)
861 ICACHE_FLUSHALL(%o2, %o3, %g1)
862 membar #Sync
863 retl
865 SET_SIZE(kdi_flush_idcache)
869 * void get_ecache_dtag(uint32_t ecache_idx, uint64_t *data, uint64_t *tag,
870 * uint64_t *oafsr, uint64_t *acc_afsr)
872 * Get ecache data and tag. The ecache_idx argument is assumed to be aligned
873 * on a 64-byte boundary. The corresponding AFSR value is also read for each
874 * 8 byte ecache data obtained. The ecache data is assumed to be a pointer
875 * to an array of 16 uint64_t's (e$data & afsr value). The action to read the
876 * data and tag should be atomic to make sense. We will be executing at PIL15
877 * and will disable IE, so nothing can occur between the two reads. We also
878 * assume that the execution of this code does not interfere with what we are
879 * reading - not really possible, but we'll live with it for now.
880 * We also pass the old AFSR value before clearing it, and caller will take
881 * appropriate actions if the important bits are non-zero.
883 * If the caller wishes to track the AFSR in cases where the CP bit is
884 * set, an address should be passed in for acc_afsr. Otherwise, this
885 * argument may be null.
887 * Register Usage:
888 * i0: In: 32-bit e$ index
889 * i1: In: addr of e$ data
890 * i2: In: addr of e$ tag
891 * i3: In: addr of old afsr
892 * i4: In: addr of accumulated afsr - may be null
894 ENTRY(get_ecache_dtag)
895 save %sp, -SA(MINFRAME), %sp
896 or %g0, 1, %l4
897 sllx %l4, 39, %l4 ! set bit 39 for e$ data access
898 or %i0, %l4, %g6 ! %g6 = e$ addr for data read
899 sllx %l4, 1, %l4 ! set bit 40 for e$ tag access
900 or %i0, %l4, %l4 ! %l4 = e$ addr for tag read
902 rdpr %pstate, %i5
903 andn %i5, PSTATE_IE | PSTATE_AM, %i0
904 wrpr %i0, %g0, %pstate ! clear IE, AM bits
906 ldxa [%g0]ASI_ESTATE_ERR, %g1
907 stxa %g0, [%g0]ASI_ESTATE_ERR ! disable errors
908 membar #Sync
910 ldxa [%g0]ASI_AFSR, %i0 ! grab the old-afsr before tag read
911 stx %i0, [%i3] ! write back the old-afsr
913 ldxa [%l4]ASI_EC_R, %g0 ! read tag into E$ tag reg
914 ldxa [%g0]ASI_EC_DIAG, %i0 ! read tag from E$ tag reg
915 stx %i0, [%i2] ! write back tag result
917 clr %i2 ! loop count
919 brz %i4, 1f ! acc_afsr == NULL?
920 ldxa [%g0]ASI_AFSR, %i0 ! grab the old-afsr before clearing
921 srlx %i0, P_AFSR_CP_SHIFT, %l0
922 btst 1, %l0
923 bz 1f
925 ldx [%i4], %g4
926 or %g4, %i0, %g4 ! aggregate AFSR in cpu private
927 stx %g4, [%i4]
929 stxa %i0, [%g0]ASI_AFSR ! clear AFSR
930 membar #Sync
931 ldxa [%g6]ASI_EC_R, %i0 ! read the 8byte E$data
932 stx %i0, [%i1] ! save the E$data
933 add %g6, 8, %g6
934 add %i1, 8, %i1
935 ldxa [%g0]ASI_AFSR, %i0 ! read AFSR for this 16byte read
936 srlx %i0, P_AFSR_CP_SHIFT, %l0
937 btst 1, %l0
938 bz 2f
939 stx %i0, [%i1] ! save the AFSR
941 brz %i4, 2f ! acc_afsr == NULL?
943 ldx [%i4], %g4
944 or %g4, %i0, %g4 ! aggregate AFSR in cpu private
945 stx %g4, [%i4]
947 add %i2, 8, %i2
948 cmp %i2, 64
949 bl,a 1b
950 add %i1, 8, %i1
951 stxa %i0, [%g0]ASI_AFSR ! clear AFSR
952 membar #Sync
953 stxa %g1, [%g0]ASI_ESTATE_ERR ! restore error enable
954 membar #Sync
955 wrpr %g0, %i5, %pstate
957 restore
958 SET_SIZE(get_ecache_dtag)
959 #endif /* lint */
961 #if defined(lint)
963 * The ce_err function handles trap type 0x63 (corrected_ECC_error) at tl=0.
964 * Steps: 1. GET AFSR 2. Get AFAR <40:4> 3. Get datapath error status
965 * 4. Clear datapath error bit(s) 5. Clear AFSR error bit
966 * 6. package data in %g2 and %g3 7. call cpu_ce_error vis sys_trap
967 * %g2: [ 52:43 UDB lower | 42:33 UDB upper | 32:0 afsr ] - arg #3/arg #1
968 * %g3: [ 40:4 afar ] - sys_trap->have_win: arg #4/arg #2
970 void
971 ce_err(void)
974 void
975 ce_err_tl1(void)
980 * The async_err function handles trap types 0x0A (instruction_access_error)
981 * and 0x32 (data_access_error) at TL = 0 and TL > 0. When we branch here,
982 * %g5 will have the trap type (with 0x200 set if we're at TL > 0).
984 * Steps: 1. Get AFSR 2. Get AFAR <40:4> 3. If not UE error skip UDP registers.
985 * 4. Else get and clear datapath error bit(s) 4. Clear AFSR error bits
986 * 6. package data in %g2 and %g3 7. disable all cpu errors, because
987 * trap is likely to be fatal 8. call cpu_async_error vis sys_trap
989 * %g3: [ 63:53 tt | 52:43 UDB_L | 42:33 UDB_U | 32:0 afsr ] - arg #3/arg #1
990 * %g2: [ 40:4 afar ] - sys_trap->have_win: arg #4/arg #2
992 void
993 async_err(void)
997 * The clr_datapath function clears any error bits set in the UDB regs.
999 void
1000 clr_datapath(void)
1004 * The get_udb_errors() function gets the current value of the
1005 * Datapath Error Registers.
1007 /*ARGSUSED*/
1008 void
1009 get_udb_errors(uint64_t *udbh, uint64_t *udbl)
1011 *udbh = 0;
1012 *udbl = 0;
1015 #else /* lint */
1017 ENTRY_NP(ce_err)
1018 ldxa [%g0]ASI_AFSR, %g3 ! save afsr in g3
1021 ! Check for a UE... From Kevin.Normoyle:
1022 ! We try to switch to the trap for the UE, but since that's
1023 ! a hardware pipeline, we might get to the CE trap before we
1024 ! can switch. The UDB and AFSR registers will have both the
1025 ! UE and CE bits set but the UDB syndrome and the AFAR will be
1026 ! for the UE.
1028 or %g0, 1, %g1 ! put 1 in g1
1029 sllx %g1, 21, %g1 ! shift left to <21> afsr UE
1030 andcc %g1, %g3, %g0 ! check for UE in afsr
1031 bnz async_err ! handle the UE, not the CE
1032 or %g0, 0x63, %g5 ! pass along the CE ttype
1034 ! Disable further CE traps to avoid recursion (stack overflow)
1035 ! and staying above XCALL_PIL for extended periods.
1037 ldxa [%g0]ASI_ESTATE_ERR, %g2
1038 andn %g2, 0x1, %g2 ! clear bit 0 - CEEN
1039 stxa %g2, [%g0]ASI_ESTATE_ERR
1040 membar #Sync ! required
1042 ! handle the CE
1043 ldxa [%g0]ASI_AFAR, %g2 ! save afar in g2
1045 set P_DER_H, %g4 ! put P_DER_H in g4
1046 ldxa [%g4]ASI_SDB_INTR_R, %g5 ! read sdb upper half into g5
1047 or %g0, 1, %g6 ! put 1 in g6
1048 sllx %g6, 8, %g6 ! shift g6 to <8> sdb CE
1049 andcc %g5, %g6, %g1 ! check for CE in upper half
1050 sllx %g5, 33, %g5 ! shift upper bits to <42:33>
1051 or %g3, %g5, %g3 ! or with afsr bits
1052 bz,a 1f ! no error, goto 1f
1054 stxa %g1, [%g4]ASI_SDB_INTR_W ! clear sdb reg error bit
1055 membar #Sync ! membar sync required
1057 set P_DER_L, %g4 ! put P_DER_L in g4
1058 ldxa [%g4]ASI_SDB_INTR_R, %g5 ! read sdb lower half into g6
1059 andcc %g5, %g6, %g1 ! check for CE in lower half
1060 sllx %g5, 43, %g5 ! shift upper bits to <52:43>
1061 or %g3, %g5, %g3 ! or with afsr bits
1062 bz,a 2f ! no error, goto 2f
1064 stxa %g1, [%g4]ASI_SDB_INTR_W ! clear sdb reg error bit
1065 membar #Sync ! membar sync required
1067 or %g0, 1, %g4 ! put 1 in g4
1068 sllx %g4, 20, %g4 ! shift left to <20> afsr CE
1069 stxa %g4, [%g0]ASI_AFSR ! use g4 to clear afsr CE error
1070 membar #Sync ! membar sync required
1072 set cpu_ce_error, %g1 ! put *cpu_ce_error() in g1
1073 rdpr %pil, %g6 ! read pil into %g6
1074 subcc %g6, PIL_15, %g0
1075 movneg %icc, PIL_14, %g4 ! run at pil 14 unless already at 15
1076 sethi %hi(sys_trap), %g5
1077 jmp %g5 + %lo(sys_trap) ! goto sys_trap
1078 movge %icc, PIL_15, %g4 ! already at pil 15
1079 SET_SIZE(ce_err)
1081 ENTRY_NP(ce_err_tl1)
1082 #ifndef TRAPTRACE
1083 ldxa [%g0]ASI_AFSR, %g7
1084 stxa %g7, [%g0]ASI_AFSR
1085 membar #Sync
1086 retry
1087 #else
1088 set ce_trap_tl1, %g1
1089 sethi %hi(dis_err_panic1), %g4
1090 jmp %g4 + %lo(dis_err_panic1)
1092 #endif
1093 SET_SIZE(ce_err_tl1)
1095 #ifdef TRAPTRACE
1096 .celevel1msg:
1097 .asciz "Softerror with trap tracing at tl1: AFAR 0x%08x.%08x AFSR 0x%08x.%08x";
1099 ENTRY_NP(ce_trap_tl1)
1100 ! upper 32 bits of AFSR already in o3
1101 mov %o4, %o0 ! save AFAR upper 32 bits
1102 mov %o2, %o4 ! lower 32 bits of AFSR
1103 mov %o1, %o2 ! lower 32 bits of AFAR
1104 mov %o0, %o1 ! upper 32 bits of AFAR
1105 set .celevel1msg, %o0
1106 call panic
1108 SET_SIZE(ce_trap_tl1)
1109 #endif
1112 ! async_err is the assembly glue code to get us from the actual trap
1113 ! into the CPU module's C error handler. Note that we also branch
1114 ! here from ce_err() above.
1116 ENTRY_NP(async_err)
1117 stxa %g0, [%g0]ASI_ESTATE_ERR ! disable ecc and other cpu errors
1118 membar #Sync ! membar sync required
1120 ldxa [%g0]ASI_AFSR, %g3 ! save afsr in g3
1121 ldxa [%g0]ASI_AFAR, %g2 ! save afar in g2
1123 sllx %g5, 53, %g5 ! move ttype to <63:53>
1124 or %g3, %g5, %g3 ! or to afsr in g3
1126 or %g0, 1, %g1 ! put 1 in g1
1127 sllx %g1, 21, %g1 ! shift left to <21> afsr UE
1128 andcc %g1, %g3, %g0 ! check for UE in afsr
1129 bz,a,pn %icc, 2f ! if !UE skip sdb read/clear
1132 set P_DER_H, %g4 ! put P_DER_H in g4
1133 ldxa [%g4]ASI_SDB_INTR_R, %g5 ! read sdb upper half into 56
1134 or %g0, 1, %g6 ! put 1 in g6
1135 sllx %g6, 9, %g6 ! shift g6 to <9> sdb UE
1136 andcc %g5, %g6, %g1 ! check for UE in upper half
1137 sllx %g5, 33, %g5 ! shift upper bits to <42:33>
1138 or %g3, %g5, %g3 ! or with afsr bits
1139 bz,a 1f ! no error, goto 1f
1141 stxa %g1, [%g4]ASI_SDB_INTR_W ! clear sdb reg UE error bit
1142 membar #Sync ! membar sync required
1144 set P_DER_L, %g4 ! put P_DER_L in g4
1145 ldxa [%g4]ASI_SDB_INTR_R, %g5 ! read sdb lower half into g5
1146 andcc %g5, %g6, %g1 ! check for UE in lower half
1147 sllx %g5, 43, %g5 ! shift upper bits to <52:43>
1148 or %g3, %g5, %g3 ! or with afsr bits
1149 bz,a 2f ! no error, goto 2f
1151 stxa %g1, [%g4]ASI_SDB_INTR_W ! clear sdb reg UE error bit
1152 membar #Sync ! membar sync required
1154 stxa %g3, [%g0]ASI_AFSR ! clear all the sticky bits
1155 membar #Sync ! membar sync required
1157 RESET_USER_RTT_REGS(%g4, %g5, async_err_resetskip)
1158 async_err_resetskip:
1160 set cpu_async_error, %g1 ! put cpu_async_error in g1
1161 sethi %hi(sys_trap), %g5
1162 jmp %g5 + %lo(sys_trap) ! goto sys_trap
1163 or %g0, PIL_15, %g4 ! run at pil 15
1164 SET_SIZE(async_err)
1166 ENTRY_NP(dis_err_panic1)
1167 stxa %g0, [%g0]ASI_ESTATE_ERR ! disable all error traps
1168 membar #Sync
1169 ! save destination routine is in g1
1170 ldxa [%g0]ASI_AFAR, %g2 ! read afar
1171 ldxa [%g0]ASI_AFSR, %g3 ! read afsr
1172 set P_DER_H, %g4 ! put P_DER_H in g4
1173 ldxa [%g4]ASI_SDB_INTR_R, %g5 ! read sdb upper half into g5
1174 sllx %g5, 33, %g5 ! shift upper bits to <42:33>
1175 or %g3, %g5, %g3 ! or with afsr bits
1176 set P_DER_L, %g4 ! put P_DER_L in g4
1177 ldxa [%g4]ASI_SDB_INTR_R, %g5 ! read sdb lower half into g5
1178 sllx %g5, 43, %g5 ! shift upper bits to <52:43>
1179 or %g3, %g5, %g3 ! or with afsr bits
1181 RESET_USER_RTT_REGS(%g4, %g5, dis_err_panic1_resetskip)
1182 dis_err_panic1_resetskip:
1184 sethi %hi(sys_trap), %g5
1185 jmp %g5 + %lo(sys_trap) ! goto sys_trap
1186 sub %g0, 1, %g4
1187 SET_SIZE(dis_err_panic1)
1189 ENTRY(clr_datapath)
1190 set P_DER_H, %o4 ! put P_DER_H in o4
1191 ldxa [%o4]ASI_SDB_INTR_R, %o5 ! read sdb upper half into o3
1192 or %g0, 0x3, %o2 ! put 0x3 in o2
1193 sllx %o2, 8, %o2 ! shift o2 to <9:8> sdb
1194 andcc %o5, %o2, %o1 ! check for UE,CE in upper half
1195 bz,a 1f ! no error, goto 1f
1197 stxa %o1, [%o4]ASI_SDB_INTR_W ! clear sdb reg UE,CE error bits
1198 membar #Sync ! membar sync required
1200 set P_DER_L, %o4 ! put P_DER_L in o4
1201 ldxa [%o4]ASI_SDB_INTR_R, %o5 ! read sdb lower half into o5
1202 andcc %o5, %o2, %o1 ! check for UE,CE in lower half
1203 bz,a 2f ! no error, goto 2f
1205 stxa %o1, [%o4]ASI_SDB_INTR_W ! clear sdb reg UE,CE error bits
1206 membar #Sync
1208 retl
1210 SET_SIZE(clr_datapath)
1212 ENTRY(get_udb_errors)
1213 set P_DER_H, %o3
1214 ldxa [%o3]ASI_SDB_INTR_R, %o2
1215 stx %o2, [%o0]
1216 set P_DER_L, %o3
1217 ldxa [%o3]ASI_SDB_INTR_R, %o2
1218 retl
1219 stx %o2, [%o1]
1220 SET_SIZE(get_udb_errors)
1222 #endif /* lint */
1224 #if defined(lint)
1226 * The itlb_rd_entry and dtlb_rd_entry functions return the tag portion of the
1227 * tte, the virtual address, and the ctxnum of the specified tlb entry. They
1228 * should only be used in places where you have no choice but to look at the
1229 * tlb itself.
1231 * Note: These two routines are required by the Estar "cpr" loadable module.
1233 /*ARGSUSED*/
1234 void
1235 itlb_rd_entry(uint_t entry, tte_t *tte, uint64_t *va_tag)
1238 /*ARGSUSED*/
1239 void
1240 dtlb_rd_entry(uint_t entry, tte_t *tte, uint64_t *va_tag)
1242 #else /* lint */
1244 * NB - In Spitfire cpus, when reading a tte from the hardware, we
1245 * need to clear [42-41] because the general definitions in pte.h
1246 * define the PA to be [42-13] whereas Spitfire really uses [40-13].
1247 * When cloning these routines for other cpus the "andn" below is not
1248 * necessary.
1250 ENTRY_NP(itlb_rd_entry)
1251 sllx %o0, 3, %o0
1252 #if defined(SF_ERRATA_32)
1253 sethi %hi(FLUSH_ADDR), %g2
1254 set MMU_PCONTEXT, %g1
1255 stxa %g0, [%g1]ASI_DMMU ! KCONTEXT
1256 flush %g2
1257 #endif
1258 ldxa [%o0]ASI_ITLB_ACCESS, %g1
1259 set TTE_SPITFIRE_PFNHI_CLEAR, %g2 ! spitfire only
1260 sllx %g2, TTE_SPITFIRE_PFNHI_SHIFT, %g2 ! see comment above
1261 andn %g1, %g2, %g1 ! for details
1262 stx %g1, [%o1]
1263 ldxa [%o0]ASI_ITLB_TAGREAD, %g2
1264 set TAGREAD_CTX_MASK, %o4
1265 andn %g2, %o4, %o5
1266 retl
1267 stx %o5, [%o2]
1268 SET_SIZE(itlb_rd_entry)
1270 ENTRY_NP(dtlb_rd_entry)
1271 sllx %o0, 3, %o0
1272 #if defined(SF_ERRATA_32)
1273 sethi %hi(FLUSH_ADDR), %g2
1274 set MMU_PCONTEXT, %g1
1275 stxa %g0, [%g1]ASI_DMMU ! KCONTEXT
1276 flush %g2
1277 #endif
1278 ldxa [%o0]ASI_DTLB_ACCESS, %g1
1279 set TTE_SPITFIRE_PFNHI_CLEAR, %g2 ! spitfire only
1280 sllx %g2, TTE_SPITFIRE_PFNHI_SHIFT, %g2 ! see comment above
1281 andn %g1, %g2, %g1 ! itlb_rd_entry
1282 stx %g1, [%o1]
1283 ldxa [%o0]ASI_DTLB_TAGREAD, %g2
1284 set TAGREAD_CTX_MASK, %o4
1285 andn %g2, %o4, %o5
1286 retl
1287 stx %o5, [%o2]
1288 SET_SIZE(dtlb_rd_entry)
1289 #endif /* lint */
1291 #if defined(lint)
1294 * routines to get and set the LSU register
1296 uint64_t
1297 get_lsu(void)
1299 return ((uint64_t)0);
1302 /*ARGSUSED*/
1303 void
1304 set_lsu(uint64_t lsu)
1307 #else /* lint */
1309 ENTRY(set_lsu)
1310 stxa %o0, [%g0]ASI_LSU ! store to LSU
1311 retl
1312 membar #Sync
1313 SET_SIZE(set_lsu)
1315 ENTRY(get_lsu)
1316 retl
1317 ldxa [%g0]ASI_LSU, %o0 ! load LSU
1318 SET_SIZE(get_lsu)
1320 #endif /* lint */
1322 #ifndef lint
1324 * Clear the NPT (non-privileged trap) bit in the %tick
1325 * registers. In an effort to make the change in the
1326 * tick counter as consistent as possible, we disable
1327 * all interrupts while we're changing the registers. We also
1328 * ensure that the read and write instructions are in the same
1329 * line in the instruction cache.
1331 ENTRY_NP(cpu_clearticknpt)
1332 rdpr %pstate, %g1 /* save processor state */
1333 andn %g1, PSTATE_IE, %g3 /* turn off */
1334 wrpr %g0, %g3, %pstate /* interrupts */
1335 rdpr %tick, %g2 /* get tick register */
1336 brgez,pn %g2, 1f /* if NPT bit off, we're done */
1337 mov 1, %g3 /* create mask */
1338 sllx %g3, 63, %g3 /* for NPT bit */
1339 ba,a,pt %xcc, 2f
1340 .align 64 /* Align to I$ boundary */
1342 rdpr %tick, %g2 /* get tick register */
1343 wrpr %g3, %g2, %tick /* write tick register, */
1344 /* clearing NPT bit */
1345 #if defined(BB_ERRATA_1)
1346 rdpr %tick, %g0 /* read (s)tick (BB_ERRATA_1) */
1347 #endif
1349 jmp %g4 + 4
1350 wrpr %g0, %g1, %pstate /* restore processor state */
1351 SET_SIZE(cpu_clearticknpt)
1354 * get_ecache_tag()
1355 * Register Usage:
1356 * %o0: In: 32-bit E$ index
1357 * Out: 64-bit E$ tag value
1358 * %o1: In: 64-bit AFSR value after clearing sticky bits
1359 * %o2: In: address of cpu private afsr storage
1361 ENTRY(get_ecache_tag)
1362 or %g0, 1, %o4
1363 sllx %o4, 40, %o4 ! set bit 40 for e$ tag access
1364 or %o0, %o4, %o4 ! %o4 = e$ addr for tag read
1365 rdpr %pstate, %o5
1366 andn %o5, PSTATE_IE | PSTATE_AM, %o0
1367 wrpr %o0, %g0, %pstate ! clear IE, AM bits
1369 ldxa [%g0]ASI_ESTATE_ERR, %g1
1370 stxa %g0, [%g0]ASI_ESTATE_ERR ! Turn off Error enable
1371 membar #Sync
1373 ldxa [%g0]ASI_AFSR, %o0
1374 srlx %o0, P_AFSR_CP_SHIFT, %o3
1375 btst 1, %o3
1376 bz 1f
1378 ldx [%o2], %g4
1379 or %g4, %o0, %g4 ! aggregate AFSR in cpu private
1380 stx %g4, [%o2]
1382 stxa %o0, [%g0]ASI_AFSR ! clear AFSR
1383 membar #Sync
1385 ldxa [%o4]ASI_EC_R, %g0
1386 ldxa [%g0]ASI_EC_DIAG, %o0 ! read tag from e$ tag reg
1388 ldxa [%g0]ASI_AFSR, %o3
1389 srlx %o3, P_AFSR_CP_SHIFT, %o4
1390 btst 1, %o4
1391 bz 2f
1392 stx %o3, [%o1] ! AFSR after sticky clear
1393 ldx [%o2], %g4
1394 or %g4, %o3, %g4 ! aggregate AFSR in cpu private
1395 stx %g4, [%o2]
1397 membar #Sync
1399 stxa %g1, [%g0]ASI_ESTATE_ERR ! Turn error enable back on
1400 membar #Sync
1401 retl
1402 wrpr %g0, %o5, %pstate
1403 SET_SIZE(get_ecache_tag)
1406 * check_ecache_line()
1407 * Register Usage:
1408 * %o0: In: 32-bit E$ index
1409 * Out: 64-bit accumulated AFSR
1410 * %o1: In: address of cpu private afsr storage
1412 ENTRY(check_ecache_line)
1413 or %g0, 1, %o4
1414 sllx %o4, 39, %o4 ! set bit 39 for e$ data access
1415 or %o0, %o4, %o4 ! %o4 = e$ addr for data read
1417 rdpr %pstate, %o5
1418 andn %o5, PSTATE_IE | PSTATE_AM, %o0
1419 wrpr %o0, %g0, %pstate ! clear IE, AM bits
1421 ldxa [%g0]ASI_ESTATE_ERR, %g1
1422 stxa %g0, [%g0]ASI_ESTATE_ERR ! Turn off Error enable
1423 membar #Sync
1425 ldxa [%g0]ASI_AFSR, %o0
1426 srlx %o0, P_AFSR_CP_SHIFT, %o2
1427 btst 1, %o2
1428 bz 1f
1429 clr %o2 ! loop count
1430 ldx [%o1], %o3
1431 or %o3, %o0, %o3 ! aggregate AFSR in cpu private
1432 stx %o3, [%o1]
1434 stxa %o0, [%g0]ASI_AFSR ! clear AFSR
1435 membar #Sync
1438 ldxa [%o4]ASI_EC_R, %g0 ! Read the E$ data 8bytes each
1439 add %o2, 1, %o2
1440 cmp %o2, 8
1441 bl,a 2b
1442 add %o4, 8, %o4
1444 membar #Sync
1445 ldxa [%g0]ASI_AFSR, %o0 ! read accumulated AFSR
1446 srlx %o0, P_AFSR_CP_SHIFT, %o2
1447 btst 1, %o2
1448 bz 3f
1450 ldx [%o1], %o3
1451 or %o3, %o0, %o3 ! aggregate AFSR in cpu private
1452 stx %o3, [%o1]
1454 stxa %o0, [%g0]ASI_AFSR ! clear AFSR
1455 membar #Sync
1456 stxa %g1, [%g0]ASI_ESTATE_ERR ! Turn error enable back on
1457 membar #Sync
1458 retl
1459 wrpr %g0, %o5, %pstate
1460 SET_SIZE(check_ecache_line)
1461 #endif /* lint */
1463 #if defined(lint)
1464 uint64_t
1465 read_and_clear_afsr()
1467 return ((uint64_t)0);
1469 #else /* lint */
1470 ENTRY(read_and_clear_afsr)
1471 ldxa [%g0]ASI_AFSR, %o0
1472 retl
1473 stxa %o0, [%g0]ASI_AFSR ! clear AFSR
1474 SET_SIZE(read_and_clear_afsr)
1475 #endif /* lint */
1477 #if defined(lint)
1478 /* ARGSUSED */
1479 void
1480 scrubphys(uint64_t paddr, int ecache_size)
1484 #else /* lint */
1487 * scrubphys - Pass in the aligned physical memory address that you want
1488 * to scrub, along with the ecache size.
1490 * 1) Displacement flush the E$ line corresponding to %addr.
1491 * The first ldxa guarantees that the %addr is no longer in
1492 * M, O, or E (goes to I or S (if instruction fetch also happens).
1493 * 2) "Write" the data using a CAS %addr,%g0,%g0.
1494 * The casxa guarantees a transition from I to M or S to M.
1495 * 3) Displacement flush the E$ line corresponding to %addr.
1496 * The second ldxa pushes the M line out of the ecache, into the
1497 * writeback buffers, on the way to memory.
1498 * 4) The "membar #Sync" pushes the cache line out of the writeback
1499 * buffers onto the bus, on the way to dram finally.
1501 * This is a modified version of the algorithm suggested by Gary Lauterbach.
1502 * In theory the CAS %addr,%g0,%g0 is supposed to mark the addr's cache line
1503 * as modified, but then we found out that for spitfire, if it misses in the
1504 * E$ it will probably install as an M, but if it hits in the E$, then it
1505 * will stay E, if the store doesn't happen. So the first displacement flush
1506 * should ensure that the CAS will miss in the E$. Arrgh.
1509 ENTRY(scrubphys)
1510 or %o1, %g0, %o2 ! put ecache size in %o2
1511 #ifndef HUMMINGBIRD
1512 xor %o0, %o2, %o1 ! calculate alias address
1513 add %o2, %o2, %o3 ! 2 * ecachesize in case
1514 ! addr == ecache_flushaddr
1515 sub %o3, 1, %o3 ! -1 == mask
1516 and %o1, %o3, %o1 ! and with xor'd address
1517 set ecache_flushaddr, %o3
1518 ldx [%o3], %o3
1520 rdpr %pstate, %o4
1521 andn %o4, PSTATE_IE | PSTATE_AM, %o5
1522 wrpr %o5, %g0, %pstate ! clear IE, AM bits
1524 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1525 casxa [%o0]ASI_MEM, %g0, %g0
1526 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1528 #else /* HUMMINGBIRD */
1530 * UltraSPARC-IIe processor supports both 4-way set associative
1531 * and direct map E$. We need to reconfigure E$ to direct map
1532 * mode for data load/store before displacement flush. Also, we
1533 * need to flush all 4 sets of the E$ to ensure that the physaddr
1534 * has been flushed. Keep the interrupts disabled while flushing
1535 * E$ in this manner.
1537 * For flushing a specific physical address, we start at the
1538 * aliased address and load at set-size stride, wrapping around
1539 * at 2*ecache-size boundary and skipping fault physical address.
1540 * It takes 10 loads to guarantee that the physical address has
1541 * been flushed.
1543 * Usage:
1544 * %o0 physaddr
1545 * %o5 physaddr - ecache_flushaddr
1546 * %g1 UPA config (restored later)
1547 * %g2 E$ set size
1548 * %g3 E$ flush address range mask (i.e. 2 * E$ -1)
1549 * %g4 #loads to flush phys address
1550 * %g5 temp
1553 sethi %hi(ecache_associativity), %g5
1554 ld [%g5 + %lo(ecache_associativity)], %g5
1555 udivx %o2, %g5, %g2 ! set size (i.e. ecache_size/#sets)
1556 xor %o0, %o2, %o1 ! calculate alias address
1557 add %o2, %o2, %g3 ! 2 * ecachesize in case
1558 ! addr == ecache_flushaddr
1559 sub %g3, 1, %g3 ! 2 * ecachesize -1 == mask
1560 and %o1, %g3, %o1 ! and with xor'd address
1561 sethi %hi(ecache_flushaddr), %o3
1562 ldx [%o3 + %lo(ecache_flushaddr)], %o3
1564 rdpr %pstate, %o4
1565 andn %o4, PSTATE_IE | PSTATE_AM, %o5
1566 wrpr %o5, %g0, %pstate ! clear IE, AM bits
1568 ! Place E$ in direct map mode for data access
1569 or %g0, 1, %g5
1570 sllx %g5, HB_UPA_DMAP_DATA_BIT, %g5
1571 ldxa [%g0]ASI_UPA_CONFIG, %g1 ! current UPA config (restored later)
1572 or %g1, %g5, %g5
1573 membar #Sync
1574 stxa %g5, [%g0]ASI_UPA_CONFIG ! enable direct map for data access
1575 membar #Sync
1577 ! Displace cache line from each set of E$ starting at the
1578 ! aliased address. at set-size stride, wrapping at 2*ecache_size
1579 ! and skipping load from physaddr. We need 10 loads to flush the
1580 ! physaddr from E$.
1581 mov HB_PHYS_FLUSH_CNT-1, %g4 ! #loads to flush phys addr
1582 sub %o0, %o3, %o5 ! physaddr - ecache_flushaddr
1583 or %o1, %g0, %g5 ! starting aliased offset
1585 ldxa [%g5 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1587 add %g5, %g2, %g5 ! calculate offset in next set
1588 and %g5, %g3, %g5 ! force offset within aliased range
1589 cmp %g5, %o5 ! skip loads from physaddr
1590 be,pn %ncc, 1b
1592 brgz,pt %g4, 2b
1593 dec %g4
1595 casxa [%o0]ASI_MEM, %g0, %g0
1597 ! Flush %o0 from ecahe again.
1598 ! Need single displacement flush at offset %o1 this time as
1599 ! the E$ is already in direct map mode.
1600 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1602 membar #Sync
1603 stxa %g1, [%g0]ASI_UPA_CONFIG ! restore UPA config (DM bits)
1604 membar #Sync
1605 #endif /* HUMMINGBIRD */
1606 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
1608 retl
1609 membar #Sync ! move the data out of the load buffer
1610 SET_SIZE(scrubphys)
1612 #endif /* lint */
1614 #if defined(lint)
1617 * clearphys - Pass in the aligned physical memory address that you want
1618 * to push out, as a 64 byte block of zeros, from the ecache zero-filled.
1619 * Since this routine does not bypass the ecache, it is possible that
1620 * it could generate a UE error while trying to clear the a bad line.
1621 * This routine clears and restores the error enable flag.
1622 * TBD - Hummingbird may need similar protection
1624 /* ARGSUSED */
1625 void
1626 clearphys(uint64_t paddr, int ecache_size, int ecache_linesize)
1630 #else /* lint */
1632 ENTRY(clearphys)
1633 or %o2, %g0, %o3 ! ecache linesize
1634 or %o1, %g0, %o2 ! ecache size
1635 #ifndef HUMMINGBIRD
1636 or %o3, %g0, %o4 ! save ecache linesize
1637 xor %o0, %o2, %o1 ! calculate alias address
1638 add %o2, %o2, %o3 ! 2 * ecachesize
1639 sub %o3, 1, %o3 ! -1 == mask
1640 and %o1, %o3, %o1 ! and with xor'd address
1641 set ecache_flushaddr, %o3
1642 ldx [%o3], %o3
1643 or %o4, %g0, %o2 ! saved ecache linesize
1645 rdpr %pstate, %o4
1646 andn %o4, PSTATE_IE | PSTATE_AM, %o5
1647 wrpr %o5, %g0, %pstate ! clear IE, AM bits
1649 ldxa [%g0]ASI_ESTATE_ERR, %g1
1650 stxa %g0, [%g0]ASI_ESTATE_ERR ! disable errors
1651 membar #Sync
1653 ! need to put zeros in the cache line before displacing it
1655 sub %o2, 8, %o2 ! get offset of last double word in ecache line
1657 stxa %g0, [%o0 + %o2]ASI_MEM ! put zeros in the ecache line
1658 sub %o2, 8, %o2
1659 brgez,a,pt %o2, 1b
1661 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1662 casxa [%o0]ASI_MEM, %g0, %g0
1663 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1665 stxa %g1, [%g0]ASI_ESTATE_ERR ! restore error enable
1666 membar #Sync
1668 #else /* HUMMINGBIRD... */
1670 * UltraSPARC-IIe processor supports both 4-way set associative
1671 * and direct map E$. We need to reconfigure E$ to direct map
1672 * mode for data load/store before displacement flush. Also, we
1673 * need to flush all 4 sets of the E$ to ensure that the physaddr
1674 * has been flushed. Keep the interrupts disabled while flushing
1675 * E$ in this manner.
1677 * For flushing a specific physical address, we start at the
1678 * aliased address and load at set-size stride, wrapping around
1679 * at 2*ecache-size boundary and skipping fault physical address.
1680 * It takes 10 loads to guarantee that the physical address has
1681 * been flushed.
1683 * Usage:
1684 * %o0 physaddr
1685 * %o5 physaddr - ecache_flushaddr
1686 * %g1 UPA config (restored later)
1687 * %g2 E$ set size
1688 * %g3 E$ flush address range mask (i.e. 2 * E$ -1)
1689 * %g4 #loads to flush phys address
1690 * %g5 temp
1693 or %o3, %g0, %o4 ! save ecache linesize
1694 sethi %hi(ecache_associativity), %g5
1695 ld [%g5 + %lo(ecache_associativity)], %g5
1696 udivx %o2, %g5, %g2 ! set size (i.e. ecache_size/#sets)
1698 xor %o0, %o2, %o1 ! calculate alias address
1699 add %o2, %o2, %g3 ! 2 * ecachesize
1700 sub %g3, 1, %g3 ! 2 * ecachesize -1 == mask
1701 and %o1, %g3, %o1 ! and with xor'd address
1702 sethi %hi(ecache_flushaddr), %o3
1703 ldx [%o3 +%lo(ecache_flushaddr)], %o3
1704 or %o4, %g0, %o2 ! saved ecache linesize
1706 rdpr %pstate, %o4
1707 andn %o4, PSTATE_IE | PSTATE_AM, %o5
1708 wrpr %o5, %g0, %pstate ! clear IE, AM bits
1710 ! Place E$ in direct map mode for data access
1711 or %g0, 1, %g5
1712 sllx %g5, HB_UPA_DMAP_DATA_BIT, %g5
1713 ldxa [%g0]ASI_UPA_CONFIG, %g1 ! current UPA config (restored later)
1714 or %g1, %g5, %g5
1715 membar #Sync
1716 stxa %g5, [%g0]ASI_UPA_CONFIG ! enable direct map for data access
1717 membar #Sync
1719 ! need to put zeros in the cache line before displacing it
1721 sub %o2, 8, %o2 ! get offset of last double word in ecache line
1723 stxa %g0, [%o0 + %o2]ASI_MEM ! put zeros in the ecache line
1724 sub %o2, 8, %o2
1725 brgez,a,pt %o2, 1b
1728 ! Displace cache line from each set of E$ starting at the
1729 ! aliased address. at set-size stride, wrapping at 2*ecache_size
1730 ! and skipping load from physaddr. We need 10 loads to flush the
1731 ! physaddr from E$.
1732 mov HB_PHYS_FLUSH_CNT-1, %g4 ! #loads to flush phys addr
1733 sub %o0, %o3, %o5 ! physaddr - ecache_flushaddr
1734 or %o1, %g0, %g5 ! starting offset
1736 ldxa [%g5 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1738 add %g5, %g2, %g5 ! calculate offset in next set
1739 and %g5, %g3, %g5 ! force offset within aliased range
1740 cmp %g5, %o5 ! skip loads from physaddr
1741 be,pn %ncc, 3b
1743 brgz,pt %g4, 2b
1744 dec %g4
1746 casxa [%o0]ASI_MEM, %g0, %g0
1748 ! Flush %o0 from ecahe again.
1749 ! Need single displacement flush at offset %o1 this time as
1750 ! the E$ is already in direct map mode.
1751 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1753 membar #Sync
1754 stxa %g1, [%g0]ASI_UPA_CONFIG ! restore UPA config (DM bits)
1755 membar #Sync
1756 #endif /* HUMMINGBIRD... */
1758 retl
1759 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
1760 SET_SIZE(clearphys)
1762 #endif /* lint */
1764 #if defined(lint)
1765 /* ARGSUSED */
1766 void
1767 flushecacheline(uint64_t paddr, int ecache_size)
1771 #else /* lint */
1773 * flushecacheline - This is a simpler version of scrubphys
1774 * which simply does a displacement flush of the line in
1775 * question. This routine is mainly used in handling async
1776 * errors where we want to get rid of a bad line in ecache.
1777 * Note that if the line is modified and it has suffered
1778 * data corruption - we are guarantee that the hw will write
1779 * a UE back to mark the page poisoned.
1781 ENTRY(flushecacheline)
1782 or %o1, %g0, %o2 ! put ecache size in %o2
1783 #ifndef HUMMINGBIRD
1784 xor %o0, %o2, %o1 ! calculate alias address
1785 add %o2, %o2, %o3 ! 2 * ecachesize in case
1786 ! addr == ecache_flushaddr
1787 sub %o3, 1, %o3 ! -1 == mask
1788 and %o1, %o3, %o1 ! and with xor'd address
1789 set ecache_flushaddr, %o3
1790 ldx [%o3], %o3
1792 rdpr %pstate, %o4
1793 andn %o4, PSTATE_IE | PSTATE_AM, %o5
1794 wrpr %o5, %g0, %pstate ! clear IE, AM bits
1796 ldxa [%g0]ASI_ESTATE_ERR, %g1
1797 stxa %g0, [%g0]ASI_ESTATE_ERR ! disable errors
1798 membar #Sync
1800 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1801 membar #Sync
1802 stxa %g1, [%g0]ASI_ESTATE_ERR ! restore error enable
1803 membar #Sync
1804 #else /* HUMMINGBIRD */
1806 * UltraSPARC-IIe processor supports both 4-way set associative
1807 * and direct map E$. We need to reconfigure E$ to direct map
1808 * mode for data load/store before displacement flush. Also, we
1809 * need to flush all 4 sets of the E$ to ensure that the physaddr
1810 * has been flushed. Keep the interrupts disabled while flushing
1811 * E$ in this manner.
1813 * For flushing a specific physical address, we start at the
1814 * aliased address and load at set-size stride, wrapping around
1815 * at 2*ecache-size boundary and skipping fault physical address.
1816 * It takes 10 loads to guarantee that the physical address has
1817 * been flushed.
1819 * Usage:
1820 * %o0 physaddr
1821 * %o5 physaddr - ecache_flushaddr
1822 * %g1 error enable register
1823 * %g2 E$ set size
1824 * %g3 E$ flush address range mask (i.e. 2 * E$ -1)
1825 * %g4 UPA config (restored later)
1826 * %g5 temp
1829 sethi %hi(ecache_associativity), %g5
1830 ld [%g5 + %lo(ecache_associativity)], %g5
1831 udivx %o2, %g5, %g2 ! set size (i.e. ecache_size/#sets)
1832 xor %o0, %o2, %o1 ! calculate alias address
1833 add %o2, %o2, %g3 ! 2 * ecachesize in case
1834 ! addr == ecache_flushaddr
1835 sub %g3, 1, %g3 ! 2 * ecachesize -1 == mask
1836 and %o1, %g3, %o1 ! and with xor'd address
1837 sethi %hi(ecache_flushaddr), %o3
1838 ldx [%o3 + %lo(ecache_flushaddr)], %o3
1840 rdpr %pstate, %o4
1841 andn %o4, PSTATE_IE | PSTATE_AM, %o5
1842 wrpr %o5, %g0, %pstate ! clear IE, AM bits
1844 ! Place E$ in direct map mode for data access
1845 or %g0, 1, %g5
1846 sllx %g5, HB_UPA_DMAP_DATA_BIT, %g5
1847 ldxa [%g0]ASI_UPA_CONFIG, %g4 ! current UPA config (restored later)
1848 or %g4, %g5, %g5
1849 membar #Sync
1850 stxa %g5, [%g0]ASI_UPA_CONFIG ! enable direct map for data access
1851 membar #Sync
1853 ldxa [%g0]ASI_ESTATE_ERR, %g1
1854 stxa %g0, [%g0]ASI_ESTATE_ERR ! disable errors
1855 membar #Sync
1857 ! Displace cache line from each set of E$ starting at the
1858 ! aliased address. at set-size stride, wrapping at 2*ecache_size
1859 ! and skipping load from physaddr. We need 10 loads to flush the
1860 ! physaddr from E$.
1861 mov HB_PHYS_FLUSH_CNT-1, %g5 ! #loads to flush physaddr
1862 sub %o0, %o3, %o5 ! physaddr - ecache_flushaddr
1864 ldxa [%o1 + %o3]ASI_MEM, %g0 ! load ecache_flushaddr + alias
1866 add %o1, %g2, %o1 ! calculate offset in next set
1867 and %o1, %g3, %o1 ! force offset within aliased range
1868 cmp %o1, %o5 ! skip loads from physaddr
1869 be,pn %ncc, 3b
1871 brgz,pt %g5, 2b
1872 dec %g5
1874 membar #Sync
1875 stxa %g1, [%g0]ASI_ESTATE_ERR ! restore error enable
1876 membar #Sync
1878 stxa %g4, [%g0]ASI_UPA_CONFIG ! restore UPA config (DM bits)
1879 membar #Sync
1880 #endif /* HUMMINGBIRD */
1881 retl
1882 wrpr %g0, %o4, %pstate
1883 SET_SIZE(flushecacheline)
1885 #endif /* lint */
1887 #if defined(lint)
1888 /* ARGSUSED */
1889 void
1890 ecache_scrubreq_tl1(uint64_t inum, uint64_t dummy)
1894 #else /* lint */
1896 * ecache_scrubreq_tl1 is the crosstrap handler called at ecache_calls_a_sec Hz
1897 * from the clock CPU. It atomically increments the outstanding request
1898 * counter and, if there was not already an outstanding request,
1899 * branches to setsoftint_tl1 to enqueue an intr_vec for the given inum.
1902 ! Register usage:
1904 ! Arguments:
1905 ! %g1 - inum
1907 ! Internal:
1908 ! %g2, %g3, %g5 - scratch
1909 ! %g4 - ptr. to spitfire_scrub_misc ec_scrub_outstanding.
1910 ! %g6 - setsoftint_tl1 address
1912 ENTRY_NP(ecache_scrubreq_tl1)
1913 set SFPR_SCRUB_MISC + EC_SCRUB_OUTSTANDING, %g2
1914 GET_CPU_PRIVATE_PTR(%g2, %g4, %g5, 1f);
1915 ld [%g4], %g2 ! cpu's ec_scrub_outstanding.
1916 set setsoftint_tl1, %g6
1918 ! no need to use atomic instructions for the following
1919 ! increment - we're at tl1
1921 add %g2, 0x1, %g3
1922 brnz,pn %g2, 1f ! no need to enqueue more intr_vec
1923 st %g3, [%g4] ! delay - store incremented counter
1924 jmp %g6 ! setsoftint_tl1(%g1) - queue intr_vec
1926 ! not reached
1928 retry
1929 SET_SIZE(ecache_scrubreq_tl1)
1931 #endif /* lint */
1933 #if defined(lint)
1934 /*ARGSUSED*/
1935 void
1936 write_ec_tag_parity(uint32_t id)
1938 #else /* lint */
1941 * write_ec_tag_parity(), which zero's the ecache tag,
1942 * marks the state as invalid and writes good parity to the tag.
1943 * Input %o1= 32 bit E$ index
1945 ENTRY(write_ec_tag_parity)
1946 or %g0, 1, %o4
1947 sllx %o4, 39, %o4 ! set bit 40 for e$ tag access
1948 or %o0, %o4, %o4 ! %o4 = ecache addr for tag write
1950 rdpr %pstate, %o5
1951 andn %o5, PSTATE_IE | PSTATE_AM, %o1
1952 wrpr %o1, %g0, %pstate ! clear IE, AM bits
1954 ldxa [%g0]ASI_ESTATE_ERR, %g1
1955 stxa %g0, [%g0]ASI_ESTATE_ERR ! Turn off Error enable
1956 membar #Sync
1958 ba 1f
1961 * Align on the ecache boundary in order to force
1962 * ciritical code section onto the same ecache line.
1964 .align 64
1967 set S_EC_PARITY, %o3 ! clear tag, state invalid
1968 sllx %o3, S_ECPAR_SHIFT, %o3 ! and with good tag parity
1969 stxa %o3, [%g0]ASI_EC_DIAG ! update with the above info
1970 stxa %g0, [%o4]ASI_EC_W
1971 membar #Sync
1973 stxa %g1, [%g0]ASI_ESTATE_ERR ! Turn error enable back on
1974 membar #Sync
1975 retl
1976 wrpr %g0, %o5, %pstate
1977 SET_SIZE(write_ec_tag_parity)
1979 #endif /* lint */
1981 #if defined(lint)
1982 /*ARGSUSED*/
1983 void
1984 write_hb_ec_tag_parity(uint32_t id)
1986 #else /* lint */
1989 * write_hb_ec_tag_parity(), which zero's the ecache tag,
1990 * marks the state as invalid and writes good parity to the tag.
1991 * Input %o1= 32 bit E$ index
1993 ENTRY(write_hb_ec_tag_parity)
1994 or %g0, 1, %o4
1995 sllx %o4, 39, %o4 ! set bit 40 for e$ tag access
1996 or %o0, %o4, %o4 ! %o4 = ecache addr for tag write
1998 rdpr %pstate, %o5
1999 andn %o5, PSTATE_IE | PSTATE_AM, %o1
2000 wrpr %o1, %g0, %pstate ! clear IE, AM bits
2002 ldxa [%g0]ASI_ESTATE_ERR, %g1
2003 stxa %g0, [%g0]ASI_ESTATE_ERR ! Turn off Error enable
2004 membar #Sync
2006 ba 1f
2009 * Align on the ecache boundary in order to force
2010 * ciritical code section onto the same ecache line.
2012 .align 64
2014 #ifdef HUMMINGBIRD
2015 set HB_EC_PARITY, %o3 ! clear tag, state invalid
2016 sllx %o3, HB_ECPAR_SHIFT, %o3 ! and with good tag parity
2017 #else /* !HUMMINGBIRD */
2018 set SB_EC_PARITY, %o3 ! clear tag, state invalid
2019 sllx %o3, SB_ECPAR_SHIFT, %o3 ! and with good tag parity
2020 #endif /* !HUMMINGBIRD */
2022 stxa %o3, [%g0]ASI_EC_DIAG ! update with the above info
2023 stxa %g0, [%o4]ASI_EC_W
2024 membar #Sync
2026 stxa %g1, [%g0]ASI_ESTATE_ERR ! Turn error enable back on
2027 membar #Sync
2028 retl
2029 wrpr %g0, %o5, %pstate
2030 SET_SIZE(write_hb_ec_tag_parity)
2032 #endif /* lint */
2034 #define VIS_BLOCKSIZE 64
2036 #if defined(lint)
2038 /*ARGSUSED*/
2040 dtrace_blksuword32(uintptr_t addr, uint32_t *data, int tryagain)
2041 { return (0); }
2043 #else
2045 ENTRY(dtrace_blksuword32)
2046 save %sp, -SA(MINFRAME + 4), %sp
2048 rdpr %pstate, %l1
2049 andn %l1, PSTATE_IE, %l2 ! disable interrupts to
2050 wrpr %g0, %l2, %pstate ! protect our FPU diddling
2052 rd %fprs, %l0
2053 andcc %l0, FPRS_FEF, %g0
2054 bz,a,pt %xcc, 1f ! if the fpu is disabled
2055 wr %g0, FPRS_FEF, %fprs ! ... enable the fpu
2057 st %f0, [%fp + STACK_BIAS - 4] ! save %f0 to the stack
2059 set 0f, %l5
2061 * We're about to write a block full or either total garbage
2062 * (not kernel data, don't worry) or user floating-point data
2063 * (so it only _looks_ like garbage).
2065 ld [%i1], %f0 ! modify the block
2066 membar #Sync
2067 stn %l5, [THREAD_REG + T_LOFAULT] ! set up the lofault handler
2068 stda %d0, [%i0]ASI_BLK_COMMIT_S ! store the modified block
2069 membar #Sync
2070 stn %g0, [THREAD_REG + T_LOFAULT] ! remove the lofault handler
2072 bz,a,pt %xcc, 1f
2073 wr %g0, %l0, %fprs ! restore %fprs
2075 ld [%fp + STACK_BIAS - 4], %f0 ! restore %f0
2078 wrpr %g0, %l1, %pstate ! restore interrupts
2081 restore %g0, %g0, %o0
2084 membar #Sync
2085 stn %g0, [THREAD_REG + T_LOFAULT] ! remove the lofault handler
2087 bz,a,pt %xcc, 1f
2088 wr %g0, %l0, %fprs ! restore %fprs
2090 ld [%fp + STACK_BIAS - 4], %f0 ! restore %f0
2093 wrpr %g0, %l1, %pstate ! restore interrupts
2096 * If tryagain is set (%i2) we tail-call dtrace_blksuword32_err()
2097 * which deals with watchpoints. Otherwise, just return -1.
2099 brnz,pt %i2, 1f
2102 restore %g0, -1, %o0
2104 call dtrace_blksuword32_err
2105 restore
2107 SET_SIZE(dtrace_blksuword32)
2109 #endif /* lint */