xref: /titanic_41/usr/src/uts/sun4u/cpu/opl_olympus_asm.s (revision 2b637af7da499c08e98bb81902f8992f624e8d86)
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 * Assembly code support for the Olympus-C module
26 */
27
28#if !defined(lint)
29#include "assym.h"
30#endif	/* lint */
31
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/machtrap.h>
39#include <sys/privregs.h>
40#include <sys/asm_linkage.h>
41#include <sys/trap.h>
42#include <sys/opl_olympus_regs.h>
43#include <sys/opl_module.h>
44#include <sys/xc_impl.h>
45#include <sys/intreg.h>
46#include <sys/async.h>
47#include <sys/clock.h>
48#include <sys/cmpregs.h>
49
50#ifdef TRAPTRACE
51#include <sys/traptrace.h>
52#endif /* TRAPTRACE */
53
54/*
55 * Macro that flushes the entire Ecache.
56 *
57 * arg1 = ecache size
58 * arg2 = ecache linesize
59 * arg3 = ecache flush address - Not used for olympus-C
60 */
61#define	ECACHE_FLUSHALL(arg1, arg2, arg3, tmp1)				\
62	mov	ASI_L2_CTRL_U2_FLUSH, arg1;				\
63	mov	ASI_L2_CTRL_RW_ADDR, arg2;				\
64	stxa	arg1, [arg2]ASI_L2_CTRL
65
66/*
67 * SPARC64-VI MMU and Cache operations.
68 */
69
70#if defined(lint)
71
72/* ARGSUSED */
73void
74vtag_flushpage(caddr_t vaddr, uint64_t sfmmup)
75{}
76
77#else	/* lint */
78
79	ENTRY_NP(vtag_flushpage)
80	/*
81	 * flush page from the tlb
82	 *
83	 * %o0 = vaddr
84	 * %o1 = sfmmup
85	 */
86	rdpr	%pstate, %o5
87#ifdef DEBUG
88	PANIC_IF_INTR_DISABLED_PSTR(%o5, opl_di_l3, %g1)
89#endif /* DEBUG */
90	/*
91	 * disable ints
92	 */
93	andn	%o5, PSTATE_IE, %o4
94	wrpr	%o4, 0, %pstate
95
96	/*
97	 * Then, blow out the tlb
98	 * Interrupts are disabled to prevent the primary ctx register
99	 * from changing underneath us.
100	 */
101	sethi   %hi(ksfmmup), %o3
102        ldx     [%o3 + %lo(ksfmmup)], %o3
103        cmp     %o3, %o1
104        bne,pt   %xcc, 1f			! if not kernel as, go to 1
105	  sethi	%hi(FLUSH_ADDR), %o3
106	/*
107	 * For Kernel demaps use primary. type = page implicitly
108	 */
109	stxa	%g0, [%o0]ASI_DTLB_DEMAP	/* dmmu flush for KCONTEXT */
110	stxa	%g0, [%o0]ASI_ITLB_DEMAP	/* immu flush for KCONTEXT */
111	flush	%o3
112	retl
113	  wrpr	%g0, %o5, %pstate		/* enable interrupts */
1141:
115	/*
116	 * User demap.  We need to set the primary context properly.
117	 * Secondary context cannot be used for SPARC64-VI IMMU.
118	 * %o0 = vaddr
119	 * %o1 = sfmmup
120	 * %o3 = FLUSH_ADDR
121	 */
122	SFMMU_CPU_CNUM(%o1, %g1, %g2)		! %g1 = sfmmu cnum on this CPU
123
124	ldub	[%o1 + SFMMU_CEXT], %o4		! %o4 = sfmmup->sfmmu_cext
125	sll	%o4, CTXREG_EXT_SHIFT, %o4
126	or	%g1, %o4, %g1			! %g1 = primary pgsz | cnum
127
128	wrpr	%g0, 1, %tl
129	set	MMU_PCONTEXT, %o4
130	or	DEMAP_PRIMARY | DEMAP_PAGE_TYPE, %o0, %o0
131	ldxa	[%o4]ASI_DMMU, %o2		! %o2 = save old ctxnum
132	srlx	%o2, CTXREG_NEXT_SHIFT, %o1	! need to preserve nucleus pgsz
133	sllx	%o1, CTXREG_NEXT_SHIFT, %o1	! %o1 = nucleus pgsz
134	or	%g1, %o1, %g1			! %g1 = nucleus pgsz | primary pgsz | cnum
135	stxa	%g1, [%o4]ASI_DMMU		! wr new ctxum
136
137	stxa	%g0, [%o0]ASI_DTLB_DEMAP
138	stxa	%g0, [%o0]ASI_ITLB_DEMAP
139	stxa	%o2, [%o4]ASI_DMMU		/* restore old ctxnum */
140	flush	%o3
141	wrpr	%g0, 0, %tl
142
143	retl
144	wrpr	%g0, %o5, %pstate		/* enable interrupts */
145	SET_SIZE(vtag_flushpage)
146
147#endif	/* lint */
148
149
150#if defined(lint)
151
152void
153vtag_flushall(void)
154{}
155
156#else	/* lint */
157
158	ENTRY_NP2(vtag_flushall, demap_all)
159	/*
160	 * flush the tlb
161	 */
162	sethi	%hi(FLUSH_ADDR), %o3
163	set	DEMAP_ALL_TYPE, %g1
164	stxa	%g0, [%g1]ASI_DTLB_DEMAP
165	stxa	%g0, [%g1]ASI_ITLB_DEMAP
166	flush	%o3
167	retl
168	nop
169	SET_SIZE(demap_all)
170	SET_SIZE(vtag_flushall)
171
172#endif	/* lint */
173
174
175#if defined(lint)
176
177/* ARGSUSED */
178void
179vtag_flushpage_tl1(uint64_t vaddr, uint64_t sfmmup)
180{}
181
182#else	/* lint */
183
184	ENTRY_NP(vtag_flushpage_tl1)
185	/*
186	 * x-trap to flush page from tlb and tsb
187	 *
188	 * %g1 = vaddr, zero-extended on 32-bit kernel
189	 * %g2 = sfmmup
190	 *
191	 * assumes TSBE_TAG = 0
192	 */
193	srln	%g1, MMU_PAGESHIFT, %g1
194
195	sethi   %hi(ksfmmup), %g3
196        ldx     [%g3 + %lo(ksfmmup)], %g3
197        cmp     %g3, %g2
198        bne,pt	%xcc, 1f                        ! if not kernel as, go to 1
199	  slln	%g1, MMU_PAGESHIFT, %g1		/* g1 = vaddr */
200
201	/* We need to demap in the kernel context */
202	or	DEMAP_NUCLEUS | DEMAP_PAGE_TYPE, %g1, %g1
203	stxa	%g0, [%g1]ASI_DTLB_DEMAP
204	stxa	%g0, [%g1]ASI_ITLB_DEMAP
205	retry
2061:
207	/* We need to demap in a user context */
208	or	DEMAP_PRIMARY | DEMAP_PAGE_TYPE, %g1, %g1
209
210	SFMMU_CPU_CNUM(%g2, %g6, %g3)	! %g6 = sfmmu cnum on this CPU
211
212	ldub	[%g2 + SFMMU_CEXT], %g4		! %g4 = sfmmup->cext
213	sll	%g4, CTXREG_EXT_SHIFT, %g4
214	or	%g6, %g4, %g6			! %g6 = primary pgsz | cnum
215
216	set	MMU_PCONTEXT, %g4
217	ldxa	[%g4]ASI_DMMU, %g5		! %g5 = save old ctxnum
218	srlx	%g5, CTXREG_NEXT_SHIFT, %g2	! %g2 = nucleus pgsz
219	sllx	%g2, CTXREG_NEXT_SHIFT, %g2	! preserve nucleus pgsz
220	or	%g6, %g2, %g6			! %g6 = nucleus pgsz | primary pgsz | cnum
221	stxa	%g6, [%g4]ASI_DMMU		! wr new ctxum
222	stxa	%g0, [%g1]ASI_DTLB_DEMAP
223	stxa	%g0, [%g1]ASI_ITLB_DEMAP
224	stxa	%g5, [%g4]ASI_DMMU		! restore old ctxnum
225	retry
226	SET_SIZE(vtag_flushpage_tl1)
227
228#endif	/* lint */
229
230
231#if defined(lint)
232
233/* ARGSUSED */
234void
235vtag_flush_pgcnt_tl1(uint64_t vaddr, uint64_t sfmmup_pgcnt)
236{}
237
238#else	/* lint */
239
240	ENTRY_NP(vtag_flush_pgcnt_tl1)
241	/*
242	 * x-trap to flush pgcnt MMU_PAGESIZE pages from tlb
243	 *
244	 * %g1 = vaddr, zero-extended on 32-bit kernel
245	 * %g2 = <sfmmup58|pgcnt6>
246	 *
247	 * NOTE: this handler relies on the fact that no
248	 *	interrupts or traps can occur during the loop
249	 *	issuing the TLB_DEMAP operations. It is assumed
250	 *	that interrupts are disabled and this code is
251	 *	fetching from the kernel locked text address.
252	 *
253	 * assumes TSBE_TAG = 0
254	 */
255	set	SFMMU_PGCNT_MASK, %g4
256	and	%g4, %g2, %g3			/* g3 = pgcnt - 1 */
257	add	%g3, 1, %g3			/* g3 = pgcnt */
258
259	andn	%g2, SFMMU_PGCNT_MASK, %g2	/* g2 = sfmmup */
260	srln	%g1, MMU_PAGESHIFT, %g1
261
262	sethi   %hi(ksfmmup), %g4
263        ldx     [%g4 + %lo(ksfmmup)], %g4
264        cmp     %g4, %g2
265        bne,pn   %xcc, 1f			/* if not kernel as, go to 1 */
266	  slln	%g1, MMU_PAGESHIFT, %g1		/* g1 = vaddr */
267
268	/* We need to demap in the kernel context */
269	or	DEMAP_NUCLEUS | DEMAP_PAGE_TYPE, %g1, %g1
270	set	MMU_PAGESIZE, %g2		/* g2 = pgsize */
271	sethi   %hi(FLUSH_ADDR), %g5
2724:
273	stxa	%g0, [%g1]ASI_DTLB_DEMAP
274	stxa	%g0, [%g1]ASI_ITLB_DEMAP
275	flush	%g5				! flush required by immu
276
277	deccc	%g3				/* decr pgcnt */
278	bnz,pt	%icc,4b
279	  add	%g1, %g2, %g1			/* next page */
280	retry
2811:
282	/*
283	 * We need to demap in a user context
284	 *
285	 * g2 = sfmmup
286	 * g3 = pgcnt
287	 */
288	SFMMU_CPU_CNUM(%g2, %g5, %g6)		! %g5 = sfmmu cnum on this CPU
289
290	or	DEMAP_PRIMARY | DEMAP_PAGE_TYPE, %g1, %g1
291
292	ldub	[%g2 + SFMMU_CEXT], %g4		! %g4 = sfmmup->cext
293	sll	%g4, CTXREG_EXT_SHIFT, %g4
294	or	%g5, %g4, %g5
295
296	set	MMU_PCONTEXT, %g4
297	ldxa	[%g4]ASI_DMMU, %g6		/* rd old ctxnum */
298	srlx	%g6, CTXREG_NEXT_SHIFT, %g2	/* %g2 = nucleus pgsz */
299	sllx	%g2, CTXREG_NEXT_SHIFT, %g2	/* preserve nucleus pgsz */
300	or	%g5, %g2, %g5			/* %g5 = nucleus pgsz | primary pgsz | cnum */
301	stxa	%g5, [%g4]ASI_DMMU		/* wr new ctxum */
302
303	set	MMU_PAGESIZE, %g2		/* g2 = pgsize */
304	sethi   %hi(FLUSH_ADDR), %g5
3053:
306	stxa	%g0, [%g1]ASI_DTLB_DEMAP
307	stxa	%g0, [%g1]ASI_ITLB_DEMAP
308	flush	%g5				! flush required by immu
309
310	deccc	%g3				/* decr pgcnt */
311	bnz,pt	%icc,3b
312	  add	%g1, %g2, %g1			/* next page */
313
314	stxa	%g6, [%g4]ASI_DMMU		/* restore old ctxnum */
315	retry
316	SET_SIZE(vtag_flush_pgcnt_tl1)
317
318#endif	/* lint */
319
320
321#if defined(lint)
322
323/*ARGSUSED*/
324void
325vtag_flushall_tl1(uint64_t dummy1, uint64_t dummy2)
326{}
327
328#else	/* lint */
329
330	ENTRY_NP(vtag_flushall_tl1)
331	/*
332	 * x-trap to flush tlb
333	 */
334	set	DEMAP_ALL_TYPE, %g4
335	stxa	%g0, [%g4]ASI_DTLB_DEMAP
336	stxa	%g0, [%g4]ASI_ITLB_DEMAP
337	retry
338	SET_SIZE(vtag_flushall_tl1)
339
340#endif	/* lint */
341
342
343/*
344 * VAC (virtual address conflict) does not apply to OPL.
345 * VAC resolution is managed by the Olympus processor hardware.
346 * As a result, all OPL VAC flushing routines are no-ops.
347 */
348
349#if defined(lint)
350
351/* ARGSUSED */
352void
353vac_flushpage(pfn_t pfnum, int vcolor)
354{}
355
356#else	/* lint */
357
358	ENTRY(vac_flushpage)
359	retl
360	  nop
361	SET_SIZE(vac_flushpage)
362
363#endif	/* lint */
364
365#if defined(lint)
366
367/* ARGSUSED */
368void
369vac_flushpage_tl1(uint64_t pfnum, uint64_t vcolor)
370{}
371
372#else	/* lint */
373
374	ENTRY_NP(vac_flushpage_tl1)
375	retry
376	SET_SIZE(vac_flushpage_tl1)
377
378#endif	/* lint */
379
380
381#if defined(lint)
382
383/* ARGSUSED */
384void
385vac_flushcolor(int vcolor, pfn_t pfnum)
386{}
387
388#else	/* lint */
389
390	ENTRY(vac_flushcolor)
391	retl
392	 nop
393	SET_SIZE(vac_flushcolor)
394
395#endif  /* lint */
396
397
398
399#if defined(lint)
400
401/* ARGSUSED */
402void
403vac_flushcolor_tl1(uint64_t vcolor, uint64_t pfnum)
404{}
405
406#else	/* lint */
407
408	ENTRY(vac_flushcolor_tl1)
409	retry
410	SET_SIZE(vac_flushcolor_tl1)
411
412#endif	/* lint */
413
414#if defined(lint)
415
416int
417idsr_busy(void)
418{
419	return (0);
420}
421
422#else	/* lint */
423
424/*
425 * Determine whether or not the IDSR is busy.
426 * Entry: no arguments
427 * Returns: 1 if busy, 0 otherwise
428 */
429	ENTRY(idsr_busy)
430	ldxa	[%g0]ASI_INTR_DISPATCH_STATUS, %g1
431	clr	%o0
432	btst	IDSR_BUSY, %g1
433	bz,a,pt	%xcc, 1f
434	mov	1, %o0
4351:
436	retl
437	nop
438	SET_SIZE(idsr_busy)
439
440#endif	/* lint */
441
442#if defined(lint)
443
444/* ARGSUSED */
445void
446init_mondo(xcfunc_t *func, uint64_t arg1, uint64_t arg2)
447{}
448
449/* ARGSUSED */
450void
451init_mondo_nocheck(xcfunc_t *func, uint64_t arg1, uint64_t arg2)
452{}
453
454#else	/* lint */
455
456	.global _dispatch_status_busy
457_dispatch_status_busy:
458	.asciz	"ASI_INTR_DISPATCH_STATUS error: busy"
459	.align	4
460
461/*
462 * Setup interrupt dispatch data registers
463 * Entry:
464 *	%o0 - function or inumber to call
465 *	%o1, %o2 - arguments (2 uint64_t's)
466 */
467	.seg "text"
468
469	ENTRY(init_mondo)
470#ifdef DEBUG
471	!
472	! IDSR should not be busy at the moment
473	!
474	ldxa	[%g0]ASI_INTR_DISPATCH_STATUS, %g1
475	btst	IDSR_BUSY, %g1
476	bz,pt	%xcc, 1f
477	nop
478	sethi	%hi(_dispatch_status_busy), %o0
479	call	panic
480	or	%o0, %lo(_dispatch_status_busy), %o0
481#endif /* DEBUG */
482
483	ALTENTRY(init_mondo_nocheck)
484	!
485	! interrupt vector dispatch data reg 0
486	!
4871:
488	mov	IDDR_0, %g1
489	mov	IDDR_1, %g2
490	mov	IDDR_2, %g3
491	stxa	%o0, [%g1]ASI_INTR_DISPATCH
492
493	!
494	! interrupt vector dispatch data reg 1
495	!
496	stxa	%o1, [%g2]ASI_INTR_DISPATCH
497
498	!
499	! interrupt vector dispatch data reg 2
500	!
501	stxa	%o2, [%g3]ASI_INTR_DISPATCH
502
503	membar	#Sync
504	retl
505	nop
506	SET_SIZE(init_mondo_nocheck)
507	SET_SIZE(init_mondo)
508
509#endif	/* lint */
510
511
512#if defined(lint)
513
514/* ARGSUSED */
515void
516shipit(int upaid, int bn)
517{ return; }
518
519#else	/* lint */
520
521/*
522 * Ship mondo to aid using busy/nack pair bn
523 */
524	ENTRY_NP(shipit)
525	sll	%o0, IDCR_PID_SHIFT, %g1	! IDCR<23:14> = agent id
526	sll	%o1, IDCR_BN_SHIFT, %g2		! IDCR<28:24> = b/n pair
527	or	%g1, IDCR_OFFSET, %g1		! IDCR<13:0> = 0x70
528	or	%g1, %g2, %g1
529	stxa	%g0, [%g1]ASI_INTR_DISPATCH	! interrupt vector dispatch
530	membar	#Sync
531	retl
532	nop
533	SET_SIZE(shipit)
534
535#endif	/* lint */
536
537
538#if defined(lint)
539
540/* ARGSUSED */
541void
542flush_instr_mem(caddr_t vaddr, size_t len)
543{}
544
545#else	/* lint */
546
547/*
548 * flush_instr_mem:
549 *	Flush 1 page of the I-$ starting at vaddr
550 * 	%o0 vaddr
551 *	%o1 bytes to be flushed
552 *
553 * SPARC64-VI maintains consistency of the on-chip Instruction Cache with
554 * the stores from all processors so that a FLUSH instruction is only needed
555 * to ensure pipeline is consistent. This means a single flush is sufficient at
556 * the end of a sequence of stores that updates the instruction stream to
557 * ensure correct operation.
558 */
559
560	ENTRY(flush_instr_mem)
561	flush	%o0			! address irrelevant
562	retl
563	nop
564	SET_SIZE(flush_instr_mem)
565
566#endif	/* lint */
567
568
569/*
570 * flush_ecache:
571 *	%o0 - 64 bit physical address
572 *	%o1 - ecache size
573 *	%o2 - ecache linesize
574 */
575#if defined(lint)
576
577/*ARGSUSED*/
578void
579flush_ecache(uint64_t physaddr, size_t ecache_size, size_t ecache_linesize)
580{}
581
582#else /* !lint */
583
584	ENTRY(flush_ecache)
585
586	/*
587	 * Flush the entire Ecache.
588	 */
589	ECACHE_FLUSHALL(%o1, %o2, %o0, %o4)
590	retl
591	nop
592	SET_SIZE(flush_ecache)
593
594#endif /* lint */
595
596#if defined(lint)
597
598/*ARGSUSED*/
599void
600kdi_flush_idcache(int dcache_size, int dcache_lsize, int icache_size,
601    int icache_lsize)
602{
603}
604
605#else	/* lint */
606
607	/*
608	 * I/D cache flushing is not needed for OPL processors
609	 */
610	ENTRY(kdi_flush_idcache)
611	retl
612	nop
613	SET_SIZE(kdi_flush_idcache)
614
615#endif	/* lint */
616
617#ifdef	TRAPTRACE
618/*
619 * Simplified trap trace macro for OPL. Adapted from us3.
620 */
621#define	OPL_TRAPTRACE(ptr, scr1, scr2, label)			\
622	CPU_INDEX(scr1, ptr);					\
623	sll	scr1, TRAPTR_SIZE_SHIFT, scr1;			\
624	set	trap_trace_ctl, ptr;				\
625	add	ptr, scr1, scr1;				\
626	ld	[scr1 + TRAPTR_LIMIT], ptr;			\
627	tst	ptr;						\
628	be,pn	%icc, label/**/1;				\
629	 ldx	[scr1 + TRAPTR_PBASE], ptr;			\
630	ld	[scr1 + TRAPTR_OFFSET], scr1;			\
631	add	ptr, scr1, ptr;					\
632	rd	%asi, scr2;					\
633	wr	%g0, TRAPTR_ASI, %asi;				\
634	rd	STICK, scr1;					\
635	stxa    scr1, [ptr + TRAP_ENT_TICK]%asi;		\
636	rdpr	%tl, scr1;					\
637	stha    scr1, [ptr + TRAP_ENT_TL]%asi;			\
638	rdpr	%tt, scr1;					\
639	stha	scr1, [ptr + TRAP_ENT_TT]%asi;			\
640	rdpr	%tpc, scr1;					\
641	stna    scr1, [ptr + TRAP_ENT_TPC]%asi;			\
642	rdpr	%tstate, scr1;					\
643	stxa	scr1, [ptr + TRAP_ENT_TSTATE]%asi;		\
644	stna    %sp, [ptr + TRAP_ENT_SP]%asi;			\
645	stna    %g0, [ptr + TRAP_ENT_TR]%asi;			\
646	stna    %g0, [ptr + TRAP_ENT_F1]%asi;			\
647	stna    %g0, [ptr + TRAP_ENT_F2]%asi;			\
648	stna    %g0, [ptr + TRAP_ENT_F3]%asi;			\
649	stna    %g0, [ptr + TRAP_ENT_F4]%asi;			\
650	wr	%g0, scr2, %asi;				\
651	CPU_INDEX(ptr, scr1);					\
652	sll	ptr, TRAPTR_SIZE_SHIFT, ptr;			\
653	set	trap_trace_ctl, scr1;				\
654	add	scr1, ptr, ptr;					\
655	ld	[ptr + TRAPTR_OFFSET], scr1;			\
656	ld	[ptr + TRAPTR_LIMIT], scr2;			\
657	st	scr1, [ptr + TRAPTR_LAST_OFFSET];		\
658	add	scr1, TRAP_ENT_SIZE, scr1;			\
659	sub	scr2, TRAP_ENT_SIZE, scr2;			\
660	cmp	scr1, scr2;					\
661	movge	%icc, 0, scr1;					\
662	st	scr1, [ptr + TRAPTR_OFFSET];			\
663label/**/1:
664#endif	/* TRAPTRACE */
665
666
667
668/*
669 * Macros facilitating error handling.
670 */
671
672/*
673 * Save alternative global registers reg1, reg2, reg3
674 * to scratchpad registers 1, 2, 3 respectively.
675 */
676#define	OPL_SAVE_GLOBAL(reg1, reg2, reg3)	\
677	stxa	reg1, [%g0]ASI_SCRATCHPAD		;\
678	mov	OPL_SCRATCHPAD_SAVE_AG2, reg1	;\
679	stxa	reg2, [reg1]ASI_SCRATCHPAD		;\
680	mov	OPL_SCRATCHPAD_SAVE_AG3, reg1	;\
681	stxa	reg3, [reg1]ASI_SCRATCHPAD
682
683/*
684 * Restore alternative global registers reg1, reg2, reg3
685 * from scratchpad registers 1, 2, 3 respectively.
686 */
687#define	OPL_RESTORE_GLOBAL(reg1, reg2, reg3)			\
688	mov	OPL_SCRATCHPAD_SAVE_AG3, reg1			;\
689	ldxa	[reg1]ASI_SCRATCHPAD, reg3				;\
690	mov	OPL_SCRATCHPAD_SAVE_AG2, reg1			;\
691	ldxa	[reg1]ASI_SCRATCHPAD, reg2				;\
692	ldxa	[%g0]ASI_SCRATCHPAD, reg1
693
694/*
695 * Logs value `val' into the member `offset' of a structure
696 * at physical address `pa'
697 */
698#define	LOG_REG(pa, offset, val)				\
699	add	pa, offset, pa					;\
700	stxa	val, [pa]ASI_MEM
701
702#define	FLUSH_ALL_TLB(tmp1)					\
703	set	DEMAP_ALL_TYPE, tmp1				;\
704	stxa	%g0, [tmp1]ASI_ITLB_DEMAP			;\
705	stxa	%g0, [tmp1]ASI_DTLB_DEMAP			;\
706	sethi	%hi(FLUSH_ADDR), tmp1				;\
707	flush	tmp1
708
709/*
710 * Extracts the Physaddr to Logging Buffer field of the OPL_SCRATCHPAD_ERRLOG
711 * scratch register by zeroing all other fields. Result is in pa.
712 */
713#define	LOG_ADDR(pa)							\
714	mov	OPL_SCRATCHPAD_ERRLOG, pa				;\
715	ldxa	[pa]ASI_SCRATCHPAD, pa					;\
716	sllx	pa, 64-ERRLOG_REG_EIDR_SHIFT, pa			;\
717	srlx	pa, 64-ERRLOG_REG_EIDR_SHIFT+ERRLOG_REG_ERR_SHIFT, pa	;\
718	sllx	pa, ERRLOG_REG_ERR_SHIFT, pa
719
720/*
721 * Advance the per-cpu error log buffer pointer to the next
722 * ERRLOG_SZ entry, making sure that it will modulo (wraparound)
723 * ERRLOG_BUFSIZ boundary. The args logpa, bufmask, tmp are
724 * unused input registers for this macro.
725 *
726 * Algorithm:
727 * 1. logpa = contents of errorlog scratchpad register
728 * 2. bufmask = ERRLOG_BUFSIZ - 1
729 * 3. tmp = logpa & ~(bufmask)     (tmp is now logbase)
730 * 4. logpa += ERRLOG_SZ
731 * 5. logpa = logpa & bufmask      (get new offset to logbase)
732 * 4. logpa = tmp | logpa
733 * 7. write logpa back into errorlog scratchpad register
734 *
735 * new logpa = (logpa & ~bufmask) | ((logpa + ERRLOG_SZ) & bufmask)
736 *
737 */
738#define	UPDATE_LOGADD(logpa, bufmask, tmp)			\
739	set	OPL_SCRATCHPAD_ERRLOG, tmp			;\
740	ldxa	[tmp]ASI_SCRATCHPAD, logpa				;\
741	set	(ERRLOG_BUFSZ-1), bufmask			;\
742	andn	logpa, bufmask, tmp				;\
743	add	logpa, ERRLOG_SZ, logpa				;\
744	and	logpa, bufmask, logpa				;\
745	or	tmp, logpa, logpa				;\
746	set	OPL_SCRATCHPAD_ERRLOG, tmp			;\
747	stxa	logpa, [tmp]ASI_SCRATCHPAD
748
749/* Log error status registers into the log buffer */
750#define	LOG_SYNC_REG(sfsr, sfar, tmp)				\
751	LOG_ADDR(tmp)						;\
752	LOG_REG(tmp, LOG_SFSR_OFF, sfsr)			;\
753	LOG_ADDR(tmp)						;\
754	mov	tmp, sfsr					;\
755	LOG_REG(tmp, LOG_SFAR_OFF, sfar)			;\
756	rd	STICK, sfar					;\
757	mov	sfsr, tmp					;\
758	LOG_REG(tmp, LOG_STICK_OFF, sfar)			;\
759	rdpr	%tl, tmp					;\
760	sllx	tmp, 32, sfar					;\
761	rdpr	%tt, tmp					;\
762	or	sfar, tmp, sfar					;\
763	mov	sfsr, tmp					;\
764	LOG_REG(tmp, LOG_TL_OFF, sfar)				;\
765	set	OPL_SCRATCHPAD_ERRLOG, tmp			;\
766	ldxa	[tmp]ASI_SCRATCHPAD, sfar				;\
767	mov	sfsr, tmp					;\
768	LOG_REG(tmp, LOG_ASI3_OFF, sfar)			;\
769	rdpr	%tpc, sfar					;\
770	mov	sfsr, tmp					;\
771	LOG_REG(tmp, LOG_TPC_OFF, sfar)				;\
772	UPDATE_LOGADD(sfsr, sfar, tmp)
773
774#define	LOG_UGER_REG(uger, tmp, tmp2)				\
775	LOG_ADDR(tmp)						;\
776	mov	tmp, tmp2					;\
777	LOG_REG(tmp2, LOG_UGER_OFF, uger)			;\
778	mov	tmp, uger					;\
779	rd	STICK, tmp2					;\
780	LOG_REG(tmp, LOG_STICK_OFF, tmp2)			;\
781	rdpr	%tl, tmp					;\
782	sllx	tmp, 32, tmp2					;\
783	rdpr	%tt, tmp					;\
784	or	tmp2, tmp, tmp2					;\
785	mov	uger, tmp					;\
786	LOG_REG(tmp, LOG_TL_OFF, tmp2)				;\
787	set	OPL_SCRATCHPAD_ERRLOG, tmp2			;\
788	ldxa	[tmp2]ASI_SCRATCHPAD, tmp2				;\
789	mov	uger, tmp					;\
790	LOG_REG(tmp, LOG_ASI3_OFF, tmp2)			;\
791	rdpr	%tstate, tmp2					;\
792	mov	uger, tmp					;\
793	LOG_REG(tmp, LOG_TSTATE_OFF, tmp2)			;\
794	rdpr	%tpc, tmp2					;\
795	mov	uger, tmp					;\
796	LOG_REG(tmp, LOG_TPC_OFF, tmp2)				;\
797	UPDATE_LOGADD(uger, tmp, tmp2)
798
799/*
800 * Scrub the STICK_COMPARE register to clear error by updating
801 * it to a reasonable value for interrupt generation.
802 * Ensure that we observe the CPU_ENABLE flag so that we
803 * don't accidentally enable TICK interrupt in STICK_COMPARE
804 * i.e. no clock interrupt will be generated if CPU_ENABLE flag
805 * is off.
806 */
807#define	UPDATE_STICK_COMPARE(tmp1, tmp2)			\
808	CPU_ADDR(tmp1, tmp2)					;\
809	lduh	[tmp1 + CPU_FLAGS], tmp2			;\
810	andcc	tmp2, CPU_ENABLE, %g0 				;\
811	set	OPL_UGER_STICK_DIFF, tmp2			;\
812	rd	STICK, tmp1					;\
813	add	tmp1, tmp2, tmp1				;\
814	mov	1, tmp2						;\
815	sllx	tmp2, TICKINT_DIS_SHFT, tmp2			;\
816	or	tmp1, tmp2, tmp2				;\
817	movnz	%xcc, tmp1, tmp2				;\
818	wr	tmp2, %g0, STICK_COMPARE
819
820/*
821 * Reset registers that may be corrupted by IAUG_CRE error.
822 * To update interrupt handling related registers force the
823 * clock interrupt.
824 */
825#define	IAG_CRE(tmp1, tmp2)					\
826	set	OPL_SCRATCHPAD_ERRLOG, tmp1			;\
827	ldxa	[tmp1]ASI_SCRATCHPAD, tmp1				;\
828	srlx	tmp1, ERRLOG_REG_EIDR_SHIFT, tmp1		;\
829	set	ERRLOG_REG_EIDR_MASK, tmp2			;\
830	and	tmp1, tmp2, tmp1				;\
831	stxa	tmp1, [%g0]ASI_EIDR				;\
832	wr	%g0, 0, SOFTINT					;\
833	sethi	%hi(hres_last_tick), tmp1			;\
834	ldx	[tmp1 + %lo(hres_last_tick)], tmp1		;\
835	set	OPL_UGER_STICK_DIFF, tmp2			;\
836	add	tmp1, tmp2, tmp1				;\
837	wr	tmp1, %g0, STICK				;\
838	UPDATE_STICK_COMPARE(tmp1, tmp2)
839
840
841#define	CLEAR_FPREGS(tmp)					\
842	wr	%g0, FPRS_FEF, %fprs				;\
843	wr	%g0, %g0, %gsr					;\
844	sethi	%hi(opl_clr_freg), tmp				;\
845	or	tmp, %lo(opl_clr_freg), tmp			;\
846	ldx	[tmp], %fsr					;\
847	fzero	 %d0						;\
848	fzero	 %d2						;\
849	fzero	 %d4						;\
850	fzero	 %d6						;\
851	fzero	 %d8						;\
852	fzero	 %d10						;\
853	fzero	 %d12						;\
854	fzero	 %d14						;\
855	fzero	 %d16						;\
856	fzero	 %d18						;\
857	fzero	 %d20						;\
858	fzero	 %d22						;\
859	fzero	 %d24						;\
860	fzero	 %d26						;\
861	fzero	 %d28						;\
862	fzero	 %d30						;\
863	fzero	 %d32						;\
864	fzero	 %d34						;\
865	fzero	 %d36						;\
866	fzero	 %d38						;\
867	fzero	 %d40						;\
868	fzero	 %d42						;\
869	fzero	 %d44						;\
870	fzero	 %d46						;\
871	fzero	 %d48						;\
872	fzero	 %d50						;\
873	fzero	 %d52						;\
874	fzero	 %d54						;\
875	fzero	 %d56						;\
876	fzero	 %d58						;\
877	fzero	 %d60						;\
878	fzero	 %d62						;\
879	wr	%g0, %g0, %fprs
880
881#define	CLEAR_GLOBALS()						\
882	mov	%g0, %g1					;\
883	mov	%g0, %g2					;\
884	mov	%g0, %g3					;\
885	mov	%g0, %g4					;\
886	mov	%g0, %g5					;\
887	mov	%g0, %g6					;\
888	mov	%g0, %g7
889
890/*
891 * We do not clear the alternative globals here because they
892 * are scratch registers, i.e. there is no code that reads from
893 * them without write to them firstly. In other words every
894 * read always follows write that makes extra write to the
895 * alternative globals unnecessary.
896 */
897#define	CLEAR_GEN_REGS(tmp1, label)				\
898	set	TSTATE_KERN, tmp1				;\
899	wrpr	%g0, tmp1, %tstate				;\
900	mov	%g0, %y						;\
901	mov	%g0, %asi					;\
902	mov	%g0, %ccr					;\
903	mov	%g0, %l0					;\
904	mov	%g0, %l1					;\
905	mov	%g0, %l2					;\
906	mov	%g0, %l3					;\
907	mov	%g0, %l4					;\
908	mov	%g0, %l5					;\
909	mov	%g0, %l6					;\
910	mov	%g0, %l7					;\
911	mov	%g0, %i0					;\
912	mov	%g0, %i1					;\
913	mov	%g0, %i2					;\
914	mov	%g0, %i3					;\
915	mov	%g0, %i4					;\
916	mov	%g0, %i5					;\
917	mov	%g0, %i6					;\
918	mov	%g0, %i7					;\
919	mov	%g0, %o1					;\
920	mov	%g0, %o2					;\
921	mov	%g0, %o3					;\
922	mov	%g0, %o4					;\
923	mov	%g0, %o5					;\
924	mov	%g0, %o6					;\
925	mov	%g0, %o7					;\
926	mov	%g0, %o0					;\
927	mov	%g0, %g4					;\
928	mov	%g0, %g5					;\
929	mov	%g0, %g6					;\
930	mov	%g0, %g7					;\
931	rdpr	%tl, tmp1					;\
932	cmp	tmp1, 1						;\
933	be,pt	%xcc, label/**/1				;\
934	 rdpr	%pstate, tmp1					;\
935	wrpr	tmp1, PSTATE_AG|PSTATE_IG, %pstate		;\
936	CLEAR_GLOBALS()						;\
937	rdpr	%pstate, tmp1					;\
938	wrpr	tmp1, PSTATE_IG|PSTATE_MG, %pstate		;\
939	CLEAR_GLOBALS()						;\
940	rdpr	%pstate, tmp1					;\
941	wrpr	tmp1, PSTATE_MG|PSTATE_AG, %pstate		;\
942	ba,pt	%xcc, label/**/2				;\
943	 nop							;\
944label/**/1:							;\
945	wrpr	tmp1, PSTATE_AG, %pstate			;\
946	CLEAR_GLOBALS()						;\
947	rdpr	%pstate, tmp1					;\
948	wrpr	tmp1, PSTATE_AG, %pstate			;\
949label/**/2:
950
951
952/*
953 * Reset all window related registers
954 */
955#define	RESET_WINREG(tmp)					\
956	sethi	%hi(nwin_minus_one), tmp			;\
957	ld	[tmp + %lo(nwin_minus_one)], tmp		;\
958	wrpr	%g0, tmp, %cwp					;\
959	wrpr	%g0, tmp, %cleanwin				;\
960	sub	tmp, 1, tmp					;\
961	wrpr	%g0, tmp, %cansave				;\
962	wrpr	%g0, %g0, %canrestore				;\
963	wrpr	%g0, %g0, %otherwin				;\
964	wrpr	%g0, PIL_MAX, %pil				;\
965	wrpr	%g0, WSTATE_KERN, %wstate
966
967
968#define	RESET_PREV_TSTATE(tmp1, tmp2, label)			\
969	rdpr	%tl, tmp1					;\
970	subcc	tmp1, 1, tmp1					;\
971	bz,pt	%xcc, label/**/1				;\
972	 nop							;\
973	wrpr	tmp1, %g0, %tl					;\
974	set	TSTATE_KERN, tmp2				;\
975	wrpr	tmp2, %g0, %tstate				;\
976	wrpr	%g0, %g0, %tpc					;\
977	wrpr	%g0, %g0, %tnpc					;\
978	add	tmp1, 1, tmp1					;\
979	wrpr	tmp1, %g0, %tl					;\
980label/**/1:
981
982
983/*
984 * %pstate, %pc, %npc are propagated to %tstate, %tpc, %tnpc,
985 * and we reset these regiseter here.
986 */
987#define	RESET_CUR_TSTATE(tmp)					\
988	set	TSTATE_KERN, tmp				;\
989	wrpr	%g0, tmp, %tstate				;\
990	wrpr	%g0, 0, %tpc					;\
991	wrpr	%g0, 0, %tnpc					;\
992	RESET_WINREG(tmp)
993
994/*
995 * In case of urgent errors some MMU registers may be
996 * corrupted, so we set here some reasonable values for
997 * them. Note that resetting MMU registers also reset the context
998 * info, we will need to reset the window registers to prevent
999 * spill/fill that depends on context info for correct behaviour.
1000 * Note that the TLBs must be flushed before programming the context
1001 * registers.
1002 */
1003
1004#if !defined(lint)
1005#define	RESET_MMU_REGS(tmp1, tmp2, tmp3)			\
1006	FLUSH_ALL_TLB(tmp1)					;\
1007	set	MMU_PCONTEXT, tmp1				;\
1008	sethi	%hi(kcontextreg), tmp2				;\
1009	ldx	[tmp2 + %lo(kcontextreg)], tmp2			;\
1010	stxa	tmp2, [tmp1]ASI_DMMU				;\
1011	set	MMU_SCONTEXT, tmp1				;\
1012	stxa	tmp2, [tmp1]ASI_DMMU				;\
1013	sethi	%hi(ktsb_base), tmp1				;\
1014	ldx	[tmp1 + %lo(ktsb_base)], tmp2			;\
1015	mov	MMU_TSB, tmp3					;\
1016	stxa	tmp2, [tmp3]ASI_IMMU				;\
1017	stxa	tmp2, [tmp3]ASI_DMMU				;\
1018	membar	#Sync						;\
1019	RESET_WINREG(tmp1)
1020
1021#define	RESET_TSB_TAGPTR(tmp)					\
1022	set	MMU_TAG_ACCESS, tmp				;\
1023	stxa	%g0, [tmp]ASI_IMMU				;\
1024	stxa	%g0, [tmp]ASI_DMMU				;\
1025	membar	#Sync
1026#endif /* lint */
1027
1028/*
1029 * In case of errors in the MMU_TSB_PREFETCH registers we have to
1030 * reset them. We can use "0" as the reset value, this way we set
1031 * the "V" bit of the registers to 0, which will disable the prefetch
1032 * so the values of the other fields are irrelevant.
1033 */
1034#if !defined(lint)
1035#define	RESET_TSB_PREFETCH(tmp)			\
1036	set	VA_UTSBPREF_8K, tmp 		;\
1037	stxa	%g0, [tmp]ASI_ITSB_PREFETCH	;\
1038	set	VA_UTSBPREF_4M, tmp 		;\
1039	stxa	%g0, [tmp]ASI_ITSB_PREFETCH	;\
1040	set	VA_KTSBPREF_8K, tmp 		;\
1041	stxa	%g0, [tmp]ASI_ITSB_PREFETCH	;\
1042	set	VA_KTSBPREF_4M, tmp 		;\
1043	stxa	%g0, [tmp]ASI_ITSB_PREFETCH	;\
1044	set	VA_UTSBPREF_8K, tmp 		;\
1045	stxa	%g0, [tmp]ASI_DTSB_PREFETCH	;\
1046	set	VA_UTSBPREF_4M, tmp 		;\
1047	stxa	%g0, [tmp]ASI_DTSB_PREFETCH	;\
1048	set	VA_KTSBPREF_8K, tmp 		;\
1049	stxa	%g0, [tmp]ASI_DTSB_PREFETCH	;\
1050	set	VA_KTSBPREF_4M, tmp 		;\
1051	stxa	%g0, [tmp]ASI_DTSB_PREFETCH
1052#endif /* lint */
1053
1054/*
1055 * In case of errors in the MMU_SHARED_CONTEXT register we have to
1056 * reset its value. We can use "0" as the reset value, it will put
1057 * 0 in the IV field disabling the shared context support, and
1058 * making values of all the other fields of the register irrelevant.
1059 */
1060#if !defined(lint)
1061#define	RESET_SHARED_CTXT(tmp)			\
1062	set	MMU_SHARED_CONTEXT, tmp		;\
1063	stxa	%g0, [tmp]ASI_DMMU
1064#endif /* lint */
1065
1066/*
1067 * RESET_TO_PRIV()
1068 *
1069 * In many cases, we need to force the thread into privilege mode because
1070 * privilege mode is only thing in which the system continue to work
1071 * due to undeterminable user mode information that come from register
1072 * corruption.
1073 *
1074 *  - opl_uger_ctxt
1075 *    If the error is secondary TSB related register parity, we have no idea
1076 *    what value is supposed to be for it.
1077 *
1078 *  The below three cases %tstate is not accessible until it is overwritten
1079 *  with some value, so we have no clue if the thread was running on user mode
1080 *  or not
1081 *   - opl_uger_pstate
1082 *     If the error is %pstate parity, it propagates to %tstate.
1083 *   - opl_uger_tstate
1084 *     No need to say the reason
1085 *   - opl_uger_r
1086 *     If the error is %ccr or %asi parity, it propagates to %tstate
1087 *
1088 * For the above four cases, user mode info may not be available for
1089 * sys_trap() and user_trap() to work consistently. So we have to force
1090 * the thread into privilege mode.
1091 *
1092 * Forcing the thread to privilege mode requires forcing
1093 * regular %g7 to be CPU_THREAD. Because if it was running on user mode,
1094 * %g7 will be set in user_trap(). Also since the %sp may be in
1095 * an inconsistent state, we need to do a stack reset and switch to
1096 * something we know i.e. current thread's kernel stack.
1097 * We also reset the window registers and MMU registers just to
1098 * make sure.
1099 *
1100 * To set regular %g7, we need to clear PSTATE_AG bit and need to
1101 * use one local register. Note that we are panicking and will never
1102 * unwind back so it is ok to clobber a local.
1103 *
1104 * If the thread was running in user mode, the %tpc value itself might be
1105 * within the range of OBP addresses. %tpc must be forced to be zero to prevent
1106 * sys_trap() from going to prom_trap()
1107 *
1108 */
1109#define	RESET_TO_PRIV(tmp, tmp1, tmp2, local)			\
1110	RESET_MMU_REGS(tmp, tmp1, tmp2)				;\
1111	CPU_ADDR(tmp, tmp1)					;\
1112	ldx	[tmp + CPU_THREAD], local			;\
1113	ldx	[local + T_STACK], tmp				;\
1114	sub	tmp, STACK_BIAS, %sp				;\
1115	rdpr	%pstate, tmp					;\
1116	wrpr	tmp, PSTATE_AG, %pstate				;\
1117	mov	local, %g7					;\
1118	rdpr	%pstate, local					;\
1119	wrpr	local, PSTATE_AG, %pstate			;\
1120	wrpr	%g0, 1, %tl					;\
1121	set	TSTATE_KERN, tmp				;\
1122	rdpr	%cwp, tmp1					;\
1123	or	tmp, tmp1, tmp					;\
1124	wrpr	tmp, %g0, %tstate				;\
1125	wrpr	%g0, %tpc
1126
1127
1128#if defined(lint)
1129
1130void
1131ce_err(void)
1132{}
1133
1134#else	/* lint */
1135
1136/*
1137 * We normally don't expect CE traps since we disable the
1138 * 0x63 trap reporting at the start of day. There is a
1139 * small window before we disable them, so let check for
1140 * it. Otherwise, panic.
1141 */
1142
1143	.align	128
1144	ENTRY_NP(ce_err)
1145	mov	AFSR_ECR, %g1
1146	ldxa	[%g1]ASI_ECR, %g1
1147	andcc	%g1, ASI_ECR_RTE_UE | ASI_ECR_RTE_CEDG, %g0
1148	bz,pn	%xcc, 1f
1149	 nop
1150	retry
11511:
1152	/*
1153	 * We did disabled the 0x63 trap reporting.
1154	 * This shouldn't happen - panic.
1155	 */
1156	set	trap, %g1
1157	rdpr	%tt, %g3
1158	sethi	%hi(sys_trap), %g5
1159	jmp	%g5 + %lo(sys_trap)
1160	sub	%g0, 1, %g4
1161	SET_SIZE(ce_err)
1162
1163#endif	/* lint */
1164
1165
1166#if defined(lint)
1167
1168void
1169ce_err_tl1(void)
1170{}
1171
1172#else	/* lint */
1173
1174/*
1175 * We don't use trap for CE detection.
1176 */
1177	ENTRY_NP(ce_err_tl1)
1178	set	trap, %g1
1179	rdpr	%tt, %g3
1180	sethi	%hi(sys_trap), %g5
1181	jmp	%g5 + %lo(sys_trap)
1182	sub	%g0, 1, %g4
1183	SET_SIZE(ce_err_tl1)
1184
1185#endif	/* lint */
1186
1187
1188#if defined(lint)
1189
1190void
1191async_err(void)
1192{}
1193
1194#else	/* lint */
1195
1196/*
1197 * async_err is the default handler for IAE/DAE traps.
1198 * For OPL, we patch in the right handler at start of day.
1199 * But if a IAE/DAE trap get generated before the handler
1200 * is patched, panic.
1201 */
1202	ENTRY_NP(async_err)
1203	set	trap, %g1
1204	rdpr	%tt, %g3
1205	sethi	%hi(sys_trap), %g5
1206	jmp	%g5 + %lo(sys_trap)
1207	sub	%g0, 1, %g4
1208	SET_SIZE(async_err)
1209
1210#endif	/* lint */
1211
1212#if defined(lint)
1213void
1214opl_sync_trap(void)
1215{}
1216#else	/* lint */
1217
1218	.seg	".data"
1219	.global	opl_clr_freg
1220	.global opl_cpu0_err_log
1221
1222	.align	16
1223opl_clr_freg:
1224	.word	0
1225	.align	16
1226
1227	.align	MMU_PAGESIZE
1228opl_cpu0_err_log:
1229	.skip	MMU_PAGESIZE
1230
1231/*
1232 * Common synchronous error trap handler (tt=0xA, 0x32)
1233 * All TL=0 and TL>0 0xA and 0x32 traps vector to this handler.
1234 * The error handling can be best summarized as follows:
1235 * 0. Do TRAPTRACE if enabled.
1236 * 1. Save globals %g1, %g2 & %g3 onto the scratchpad regs.
1237 * 2. The SFSR register is read and verified as valid by checking
1238 *    SFSR.FV bit being set. If the SFSR.FV is not set, the
1239 *    error cases cannot be decoded/determined and the SFPAR
1240 *    register that contain the physical faultaddr is also
1241 *    not valid. Also the SPFAR is only valid for UE/TO/BERR error
1242 *    cases. Assuming the SFSR.FV is valid:
1243 *    - BERR(bus error)/TO(timeout)/UE case
1244 *      If any of these error cases are detected, read the SFPAR
1245 *      to get the faultaddress. Generate ereport.
1246 *    - TLB Parity case (only recoverable case)
1247 *      For DAE, read SFAR for the faultaddress. For IAE,
1248 *	use %tpc for faultaddress (SFAR is not valid in IAE)
1249 *	Flush all the tlbs.
1250 *	Subtract one from the recoverable error count stored in
1251 *	the error log scratch register. If the threshold limit
1252 *	is reached (zero) - generate ereport. Else
1253 *	restore globals and retry (no ereport is generated).
1254 *    - TLB Multiple hits
1255 *	For DAE, read SFAR for the faultaddress. For IAE,
1256 *	use %tpc for faultaddress (SFAR is not valid in IAE).
1257 *	Flush all tlbs and generate ereport.
1258 * 3. TL=0 and TL>0 considerations
1259 *    - Since both TL=0 & TL>1 traps are made to vector into
1260 *      the same handler, the underlying assumption/design here is
1261 *      that any nested error condition (if happens) occurs only
1262 *	in the handler and the system is assumed to eventually
1263 *      Red-mode. With this philosophy in mind, the recoverable
1264 *      TLB Parity error case never check the TL level before it
1265 *      retry. Note that this is ok for the TL>1 case (assuming we
1266 *	don't have a nested error) since we always save the globals
1267 *      %g1, %g2 & %g3 whenever we enter this trap handler.
1268 *    - Additional TL=0 vs TL>1 handling includes:
1269 *      - For UE error occuring under TL>1, special handling
1270 *        is added to prevent the unlikely chance of a cpu-lockup
1271 *        when a UE was originally detected in user stack and
1272 *        the spill trap handler taken from sys_trap() so happened
1273 *        to reference the same UE location. Under the above
1274 *        condition (TL>1 and UE error), paranoid code is added
1275 *        to reset window regs so that spill traps can't happen
1276 *        during the unwind back to TL=0 handling.
1277 *        Note that we can do that because we are not returning
1278 *	  back.
1279 * 4. Ereport generation.
1280 *    - Ereport generation is performed when we unwind to the TL=0
1281 *      handling code via sys_trap(). on_trap()/lofault protection
1282 *      will apply there.
1283 *
1284 */
1285	ENTRY_NP(opl_sync_trap)
1286#ifdef	TRAPTRACE
1287	OPL_TRAPTRACE(%g1, %g2, %g3, opl_sync_trap_lb)
1288	rdpr	%tt, %g1
1289#endif	/* TRAPTRACE */
1290	cmp	%g1, T_INSTR_ERROR
1291	bne,pt	%xcc, 0f
1292	 mov	MMU_SFSR, %g3
1293	ldxa	[%g3]ASI_IMMU, %g1	! IAE trap case tt = 0xa
1294	andcc	%g1, SFSR_FV, %g0
1295	bz,a,pn %xcc, 2f		! Branch if SFSR is invalid and
1296	 rdpr	%tpc, %g2		! use %tpc for faultaddr instead
1297
1298	sethi	%hi(SFSR_UE|SFSR_BERR|SFSR_TO), %g3
1299	andcc	%g1, %g3, %g0		! Check for UE/BERR/TO errors
1300	bz,a,pt %xcc, 1f		! Branch if not UE/BERR/TO and
1301	 rdpr	%tpc, %g2		! use %tpc as faultaddr
1302	set	OPL_MMU_SFPAR, %g3	! In the UE/BERR/TO cases, use
1303	ba,pt	%xcc, 2f		! SFPAR as faultaddr
1304	 ldxa	[%g3]ASI_IMMU, %g2
13050:
1306	ldxa	[%g3]ASI_DMMU, %g1	! DAE trap case tt = 0x32
1307	andcc	%g1, SFSR_FV, %g0
1308	bnz,pt  %xcc, 7f		! branch if SFSR.FV is valid
1309	 mov	MMU_SFAR, %g2		! set %g2 to use SFAR
1310	ba,pt	%xcc, 2f		! SFSR.FV is not valid, read SFAR
1311	 ldxa	[%g2]ASI_DMMU, %g2	! for faultaddr
13127:
1313	sethi  %hi(SFSR_UE|SFSR_BERR|SFSR_TO), %g3
1314	andcc	%g1, %g3, %g0		! Check UE/BERR/TO for valid SFPAR
1315	movnz	%xcc, OPL_MMU_SFPAR, %g2 ! Use SFPAR instead of SFAR for
1316	ldxa	[%g2]ASI_DMMU, %g2	! faultaddr
13171:
1318	sethi	%hi(SFSR_TLB_PRT), %g3
1319	andcc	%g1, %g3, %g0
1320	bz,pt	%xcc, 8f		! branch for TLB multi-hit check
1321	 nop
1322	/*
1323	 * This is the TLB parity error case and it is the
1324	 * only retryable error case.
1325	 * Only %g1, %g2 and %g3 are allowed
1326	 */
1327	FLUSH_ALL_TLB(%g3)
1328	set	OPL_SCRATCHPAD_ERRLOG, %g3
1329	ldxa	[%g3]ASI_SCRATCHPAD, %g3		! Read errlog scratchreg
1330	and	%g3, ERRLOG_REG_NUMERR_MASK, %g3! Extract the error count
1331	subcc	%g3, 1, %g0			! Subtract one from the count
1332	bz,pn	%xcc, 2f		! too many TLB parity errs in a certain
1333	 nop				! period, branch to generate ereport
1334	LOG_SYNC_REG(%g1, %g2, %g3)	! Record into the error log
1335	set	OPL_SCRATCHPAD_ERRLOG, %g3
1336	ldxa	[%g3]ASI_SCRATCHPAD, %g2
1337	sub	%g2, 1, %g2		! decrement error counter by 1
1338	stxa	%g2, [%g3]ASI_SCRATCHPAD	! update the errlog scratchreg
1339	OPL_RESTORE_GLOBAL(%g1, %g2, %g3)
1340	retry
13418:
1342	sethi	%hi(SFSR_TLB_MUL), %g3
1343	andcc	%g1, %g3, %g0
1344	bz,pt	%xcc, 2f		! check for the TLB multi-hit errors
1345	 nop
1346	FLUSH_ALL_TLB(%g3)
13472:
1348	/*
1349	 * non-retryable error handling
1350	 * now we can use other registers since
1351	 * we will not be returning back
1352	 */
1353	mov	%g1, %g5		! %g5 = SFSR
1354	mov	%g2, %g6		! %g6 = SFPAR or SFAR/tpc
1355	LOG_SYNC_REG(%g1, %g2, %g3)	! Record into the error log
1356
1357	/*
1358	 * Special case for UE on user stack.
1359	 * There is a possibility that the same error may come back here
1360	 * by touching the same UE in spill trap handler taken from
1361	 * sys_trap(). It ends up with an infinite loop causing a cpu lockup.
1362	 * Conditions for this handling this case are:
1363	 * - SFSR_FV is valid and SFSR_UE is set
1364	 * - we are at TL > 1
1365	 * If the above conditions are true,  we force %cansave to be a
1366	 * big number to prevent spill trap in sys_trap(). Note that
1367	 * we will not be returning back.
1368	 */
1369	rdpr	%tt, %g4		! %g4 == ttype
1370	rdpr	%tl, %g1		! %g1 == tl
1371	cmp	%g1, 1			! Check if TL == 1
1372	be,pt	%xcc, 3f		! branch if we came from TL=0
1373	 nop
1374	andcc	%g5, SFSR_FV, %g0	! see if SFSR.FV is valid
1375	bz,pn	%xcc, 4f		! branch, checking UE is meaningless
1376	sethi	%hi(SFSR_UE), %g2
1377	andcc	%g5, %g2, %g0		! check for UE
1378	bz,pt	%xcc, 4f		! branch if not UE
1379	 nop
1380	RESET_WINREG(%g1)		! reset windows to prevent spills
13814:
1382	RESET_USER_RTT_REGS(%g2, %g3, opl_sync_trap_resetskip)
1383opl_sync_trap_resetskip:
1384	mov	%g5, %g3		! pass SFSR to the 3rd arg
1385	mov	%g6, %g2		! pass SFAR to the 2nd arg
1386	set	opl_cpu_isync_tl1_error, %g1
1387	set	opl_cpu_dsync_tl1_error, %g6
1388	cmp	%g4, T_INSTR_ERROR
1389	movne	%icc, %g6, %g1
1390	ba,pt	%icc, 6f
1391	nop
13923:
1393	mov	%g5, %g3		! pass SFSR to the 3rd arg
1394	mov	%g6, %g2		! pass SFAR to the 2nd arg
1395	set	opl_cpu_isync_tl0_error, %g1
1396	set	opl_cpu_dsync_tl0_error, %g6
1397	cmp	%g4, T_INSTR_ERROR
1398	movne	%icc, %g6, %g1
13996:
1400	sethi	%hi(sys_trap), %g5
1401	jmp	%g5 + %lo(sys_trap)
1402	 mov	PIL_15, %g4
1403	SET_SIZE(opl_sync_trap)
1404#endif	/* lint */
1405
1406#if defined(lint)
1407void
1408opl_uger_trap(void)
1409{}
1410#else	/* lint */
1411/*
1412 * Common Urgent error trap handler (tt=0x40)
1413 * All TL=0 and TL>0 0x40 traps vector to this handler.
1414 * The error handling can be best summarized as follows:
1415 * 1. Read the Urgent error status register (UGERSR)
1416 *    Faultaddress is N/A here and it is not collected.
1417 * 2. Check to see if we have a multiple errors case
1418 *    If so, we enable WEAK_ED (weak error detection) bit
1419 *    to prevent any potential error storms and branch directly
1420 *    to generate ereport. (we don't decode/handle individual
1421 *    error cases when we get a multiple error situation)
1422 * 3. Now look for the recoverable error cases which include
1423 *    IUG_DTLB, IUG_ITLB or COREERR errors. If any of the
1424 *    recoverable errors are detected, do the following:
1425 *    - Flush all tlbs.
1426 *    - Verify that we came from TL=0, if not, generate
1427 *      ereport. Note that the reason we don't recover
1428 *      at TL>0 is because the AGs might be corrupted or
1429 *      inconsistent. We can't save/restore them into
1430 *      the scratchpad regs like we did for opl_sync_trap().
1431 *    - Check the INSTEND[5:4] bits in the UGERSR. If the
1432 *      value is 0x3 (11b), this error is not recoverable.
1433 *      Generate ereport.
1434 *    - Subtract one from the recoverable error count stored in
1435 *      the error log scratch register. If the threshold limit
1436 *      is reached (zero) - generate ereport.
1437 *    - If the count is within the limit, update the count
1438 *      in the error log register (subtract one). Log the error
1439 *      info in the log buffer. Capture traptrace if enabled.
1440 *      Retry (no ereport generated)
1441 * 4. The rest of the error cases are unrecoverable and will
1442 *    be handled according (flushing regs, etc as required).
1443 *    For details on these error cases (UGER_CRE, UGER_CTXT, etc..)
1444 *    consult the OPL cpu/mem philosophy doc.
1445 *    Ereport will be generated for these errors.
1446 * 5. Ereport generation.
1447 *    - Ereport generation for urgent error trap always
1448 *      result in a panic when we unwind to the TL=0 handling
1449 *      code via sys_trap(). on_trap()/lofault protection do
1450 *      not apply there.
1451 */
1452	ENTRY_NP(opl_uger_trap)
1453	set	ASI_UGERSR, %g2
1454	ldxa	[%g2]ASI_AFSR, %g1		! Read the UGERSR reg
1455
1456	set	UGESR_MULTI, %g2
1457	andcc	%g1, %g2, %g0			! Check for Multi-errs
1458	bz,pt	%xcc, opl_uger_is_recover	! branch if not Multi-errs
1459	 nop
1460	set	AFSR_ECR, %g2
1461	ldxa	[%g2]ASI_AFSR, %g3		! Enable Weak error
1462	or	%g3, ASI_ECR_WEAK_ED, %g3	! detect mode to prevent
1463	stxa	%g3, [%g2]ASI_AFSR		! potential error storms
1464	ba	%xcc, opl_uger_panic1
1465	 nop
1466
1467opl_uger_is_recover:
1468	set	UGESR_CAN_RECOVER, %g2		! Check for recoverable
1469	andcc	%g1, %g2, %g0			! errors i.e.IUG_DTLB,
1470	bz,pt	%xcc, opl_uger_cre		! IUG_ITLB or COREERR
1471	 nop
1472
1473	/*
1474	 * Fall thru to handle recoverable case
1475	 * Need to do the following additional checks to determine
1476	 * if this is indeed recoverable.
1477	 * 1. Error trap came from TL=0 and
1478	 * 2. INSTEND[5:4] bits in UGERSR is not 0x3
1479	 * 3. Recoverable error count limit not reached
1480	 *
1481	 */
1482	FLUSH_ALL_TLB(%g3)
1483	rdpr	%tl, %g3		! Read TL
1484	cmp	%g3, 1			! Check if we came from TL=0
1485	bne,pt	%xcc, opl_uger_panic	! branch if came from TL>0
1486	 nop
1487	srlx	%g1, 4, %g2		! shift INSTEND[5:4] -> [1:0]
1488	and	%g2, 3, %g2		! extract the shifted [1:0] bits
1489	cmp	%g2, 3			! check if INSTEND is recoverable
1490	be,pt   %xcc, opl_uger_panic	! panic if ([1:0] = 11b)
1491	 nop
1492	set	OPL_SCRATCHPAD_ERRLOG, %g3
1493	ldxa	[%g3]ASI_SCRATCHPAD, %g2		! Read errlog scratch reg
1494	and	%g2, ERRLOG_REG_NUMERR_MASK, %g3! Extract error count and
1495	subcc	%g3, 1, %g3			! subtract one from it
1496	bz,pt   %xcc, opl_uger_panic	! If count reached zero, too many
1497	 nop				! errors, branch to generate ereport
1498	sub	%g2, 1, %g2			! Subtract one from the count
1499	set	OPL_SCRATCHPAD_ERRLOG, %g3	! and write back the updated
1500	stxa	%g2, [%g3]ASI_SCRATCHPAD		! count into the errlog reg
1501	LOG_UGER_REG(%g1, %g2, %g3)		! Log the error info
1502#ifdef	TRAPTRACE
1503	OPL_TRAPTRACE(%g1, %g2, %g3, opl_uger_trap_lb)
1504#endif	/* TRAPTRACE */
1505	retry					! retry - no ereport
1506
1507	/*
1508	 * Process the rest of the unrecoverable error cases
1509	 * All error cases below ultimately branch to either
1510	 * opl_uger_panic or opl_uger_panic1.
1511	 * opl_uger_panic1 is the same as opl_uger_panic except
1512	 * for the additional execution of the RESET_TO_PRIV()
1513	 * macro that does a heavy handed reset. Read the
1514	 * comments for RESET_TO_PRIV() macro for more info.
1515	 */
1516opl_uger_cre:
1517	set	UGESR_IAUG_CRE, %g2
1518	andcc	%g1, %g2, %g0
1519	bz,pt	%xcc, opl_uger_ctxt
1520	 nop
1521	IAG_CRE(%g2, %g3)
1522	set	AFSR_ECR, %g2
1523	ldxa	[%g2]ASI_AFSR, %g3
1524	or	%g3, ASI_ECR_WEAK_ED, %g3
1525	stxa	%g3, [%g2]ASI_AFSR
1526	ba	%xcc, opl_uger_panic
1527	 nop
1528
1529opl_uger_ctxt:
1530	set	UGESR_IAUG_TSBCTXT, %g2
1531	andcc	%g1, %g2, %g0
1532	bz,pt	%xcc, opl_uger_tsbp
1533	 nop
1534	GET_CPU_IMPL(%g2)
1535	cmp	%g2, JUPITER_IMPL
1536	bne	%xcc, 1f
1537	  nop
1538	RESET_SHARED_CTXT(%g2)
15391:
1540	RESET_MMU_REGS(%g2, %g3, %g4)
1541	ba	%xcc, opl_uger_panic
1542	 nop
1543
1544opl_uger_tsbp:
1545	set	UGESR_IUG_TSBP, %g2
1546	andcc	%g1, %g2, %g0
1547	bz,pt	%xcc, opl_uger_pstate
1548	 nop
1549	GET_CPU_IMPL(%g2)
1550	cmp	%g2, JUPITER_IMPL
1551	bne	%xcc, 1f
1552	  nop
1553	RESET_TSB_PREFETCH(%g2)
15541:
1555	RESET_TSB_TAGPTR(%g2)
1556
1557	/*
1558	 * IUG_TSBP error may corrupt MMU registers
1559	 * Reset them here.
1560	 */
1561	RESET_MMU_REGS(%g2, %g3, %g4)
1562	ba	%xcc, opl_uger_panic
1563	 nop
1564
1565opl_uger_pstate:
1566	set	UGESR_IUG_PSTATE, %g2
1567	andcc	%g1, %g2, %g0
1568	bz,pt	%xcc, opl_uger_tstate
1569	 nop
1570	RESET_CUR_TSTATE(%g2)
1571	ba	%xcc, opl_uger_panic1
1572	 nop
1573
1574opl_uger_tstate:
1575	set	UGESR_IUG_TSTATE, %g2
1576	andcc	%g1, %g2, %g0
1577	bz,pt	%xcc, opl_uger_f
1578	 nop
1579	RESET_PREV_TSTATE(%g2, %g3, opl_uger_tstate_1)
1580	ba	%xcc, opl_uger_panic1
1581	 nop
1582
1583opl_uger_f:
1584	set	UGESR_IUG_F, %g2
1585	andcc	%g1, %g2, %g0
1586	bz,pt	%xcc, opl_uger_r
1587	 nop
1588	CLEAR_FPREGS(%g2)
1589	ba	%xcc, opl_uger_panic
1590	 nop
1591
1592opl_uger_r:
1593	set	UGESR_IUG_R, %g2
1594	andcc	%g1, %g2, %g0
1595	bz,pt	%xcc, opl_uger_panic1
1596	 nop
1597	CLEAR_GEN_REGS(%g2, opl_uger_r_1)
1598	ba	%xcc, opl_uger_panic1
1599	 nop
1600
1601opl_uger_panic:
1602	mov	%g1, %g2			! %g2 = arg #1
1603	LOG_UGER_REG(%g1, %g3, %g4)
1604	ba	%xcc, opl_uger_panic_cmn
1605	 nop
1606
1607opl_uger_panic1:
1608	mov	%g1, %g2			! %g2 = arg #1
1609	LOG_UGER_REG(%g1, %g3, %g4)
1610	RESET_TO_PRIV(%g1, %g3, %g4, %l0)
1611
1612	/*
1613	 * Set up the argument for sys_trap.
1614	 * %g2 = arg #1 already set above
1615	 */
1616opl_uger_panic_cmn:
1617	RESET_USER_RTT_REGS(%g4, %g5, opl_uger_panic_resetskip)
1618opl_uger_panic_resetskip:
1619	rdpr	%tl, %g3			! arg #2
1620	set	opl_cpu_urgent_error, %g1	! pc
1621	sethi	%hi(sys_trap), %g5
1622	jmp	%g5 + %lo(sys_trap)
1623	 mov	PIL_15, %g4
1624	SET_SIZE(opl_uger_trap)
1625#endif	/* lint */
1626
1627#if defined(lint)
1628void
1629opl_ta3_trap(void)
1630{}
1631void
1632opl_cleanw_subr(void)
1633{}
1634#else	/* lint */
1635/*
1636 * OPL ta3 support (note please, that win_reg
1637 * area size for each cpu is 2^7 bytes)
1638 */
1639
1640#define	RESTORE_WREGS(tmp1, tmp2)		\
1641	CPU_INDEX(tmp1, tmp2)			;\
1642	sethi	%hi(opl_ta3_save), tmp2		;\
1643	ldx	[tmp2 +%lo(opl_ta3_save)], tmp2	;\
1644	sllx	tmp1, 7, tmp1			;\
1645	add	tmp2, tmp1, tmp2		;\
1646	ldx	[tmp2 + 0], %l0			;\
1647	ldx	[tmp2 + 8], %l1			;\
1648	ldx	[tmp2 + 16], %l2		;\
1649	ldx	[tmp2 + 24], %l3		;\
1650	ldx	[tmp2 + 32], %l4		;\
1651	ldx	[tmp2 + 40], %l5		;\
1652	ldx	[tmp2 + 48], %l6		;\
1653	ldx	[tmp2 + 56], %l7		;\
1654	ldx	[tmp2 + 64], %i0		;\
1655	ldx	[tmp2 + 72], %i1		;\
1656	ldx	[tmp2 + 80], %i2		;\
1657	ldx	[tmp2 + 88], %i3		;\
1658	ldx	[tmp2 + 96], %i4		;\
1659	ldx	[tmp2 + 104], %i5		;\
1660	ldx	[tmp2 + 112], %i6		;\
1661	ldx	[tmp2 + 120], %i7
1662
1663#define	SAVE_WREGS(tmp1, tmp2)			\
1664	CPU_INDEX(tmp1, tmp2)			;\
1665	sethi	%hi(opl_ta3_save), tmp2		;\
1666	ldx	[tmp2 +%lo(opl_ta3_save)], tmp2	;\
1667	sllx	tmp1, 7, tmp1			;\
1668	add	tmp2, tmp1, tmp2		;\
1669	stx	%l0, [tmp2 + 0] 		;\
1670	stx	%l1, [tmp2 + 8] 		;\
1671	stx	%l2, [tmp2 + 16] 		;\
1672	stx	%l3, [tmp2 + 24]		;\
1673	stx	%l4, [tmp2 + 32]		;\
1674	stx	%l5, [tmp2 + 40]		;\
1675	stx	%l6, [tmp2 + 48] 		;\
1676	stx	%l7, [tmp2 + 56]		;\
1677	stx	%i0, [tmp2 + 64]		;\
1678	stx	%i1, [tmp2 + 72]		;\
1679	stx	%i2, [tmp2 + 80]		;\
1680	stx	%i3, [tmp2 + 88]		;\
1681	stx	%i4, [tmp2 + 96]		;\
1682	stx	%i5, [tmp2 + 104]		;\
1683	stx	%i6, [tmp2 + 112]		;\
1684	stx	%i7, [tmp2 + 120]
1685
1686
1687/*
1688 * The purpose of this function is to make sure that the restore
1689 * instruction after the flushw does not cause a fill trap. The sun4u
1690 * fill trap handler can not handle a tlb fault of an unmapped stack
1691 * except at the restore instruction at user_rtt. On OPL systems the
1692 * stack can get unmapped between the flushw and restore instructions
1693 * since multiple strands share the tlb.
1694 */
1695	ENTRY_NP(opl_ta3_trap)
1696	set	trap, %g1
1697	mov	T_FLUSHW, %g3
1698	sub	%g0, 1, %g4
1699	rdpr	%cwp, %g5
1700	SAVE_WREGS(%g2, %g6)
1701	save
1702	flushw
1703	rdpr	%cwp, %g6
1704	wrpr	%g5, %cwp
1705	RESTORE_WREGS(%g2, %g5)
1706	wrpr	%g6, %cwp
1707	restored
1708	restore
1709
1710	ba,a    fast_trap_done
1711	SET_SIZE(opl_ta3_trap)
1712
1713	ENTRY_NP(opl_cleanw_subr)
1714	set	trap, %g1
1715	mov	T_FLUSHW, %g3
1716	sub	%g0, 1, %g4
1717	rdpr	%cwp, %g5
1718	SAVE_WREGS(%g2, %g6)
1719	save
1720	flushw
1721	rdpr	%cwp, %g6
1722	wrpr	%g5, %cwp
1723	RESTORE_WREGS(%g2, %g5)
1724	wrpr	%g6, %cwp
1725	restored
1726	restore
1727	jmp	%g7
1728	  nop
1729	SET_SIZE(opl_cleanw_subr)
1730#endif	/* lint */
1731
1732#if defined(lint)
1733
1734void
1735opl_serr_instr(void)
1736{}
1737
1738#else	/* lint */
1739/*
1740 * The actual trap handler for tt=0x0a, and tt=0x32
1741 */
1742	ENTRY_NP(opl_serr_instr)
1743	OPL_SAVE_GLOBAL(%g1,%g2,%g3)
1744	sethi   %hi(opl_sync_trap), %g3
1745	jmp	%g3 + %lo(opl_sync_trap)
1746	 rdpr    %tt, %g1
1747	.align  32
1748	SET_SIZE(opl_serr_instr)
1749
1750#endif	/* lint */
1751
1752#if defined(lint)
1753
1754void
1755opl_ugerr_instr(void)
1756{}
1757
1758#else	/* lint */
1759/*
1760 * The actual trap handler for tt=0x40
1761 */
1762	ENTRY_NP(opl_ugerr_instr)
1763	sethi   %hi(opl_uger_trap), %g3
1764	jmp	%g3 + %lo(opl_uger_trap)
1765	 nop
1766	.align  32
1767	SET_SIZE(opl_ugerr_instr)
1768
1769#endif	/* lint */
1770
1771#if defined(lint)
1772
1773void
1774opl_ta3_instr(void)
1775{}
1776
1777#else	/* lint */
1778/*
1779 * The actual trap handler for tt=0x103 (flushw)
1780 */
1781	ENTRY_NP(opl_ta3_instr)
1782	sethi   %hi(opl_ta3_trap), %g3
1783	jmp	%g3 + %lo(opl_ta3_trap)
1784	 nop
1785	.align  32
1786	SET_SIZE(opl_ta3_instr)
1787
1788#endif	/* lint */
1789
1790#if defined(lint)
1791
1792void
1793opl_ta4_instr(void)
1794{}
1795
1796#else	/* lint */
1797/*
1798 * The patch for the .clean_windows code
1799 */
1800	ENTRY_NP(opl_ta4_instr)
1801	sethi   %hi(opl_cleanw_subr), %g3
1802	add	%g3, %lo(opl_cleanw_subr), %g3
1803	jmpl	%g3, %g7
1804	  add	%g7, 8, %g7
1805	nop
1806	nop
1807	nop
1808	SET_SIZE(opl_ta4_instr)
1809
1810#endif	/* lint */
1811
1812#if defined(lint)
1813/*
1814 *  Get timestamp (stick).
1815 */
1816/* ARGSUSED */
1817void
1818stick_timestamp(int64_t *ts)
1819{
1820}
1821
1822#else	/* lint */
1823
1824	ENTRY_NP(stick_timestamp)
1825	rd	STICK, %g1	! read stick reg
1826	sllx	%g1, 1, %g1
1827	srlx	%g1, 1, %g1	! clear npt bit
1828
1829	retl
1830	stx	%g1, [%o0]	! store the timestamp
1831	SET_SIZE(stick_timestamp)
1832
1833#endif	/* lint */
1834
1835
1836#if defined(lint)
1837/*
1838 * Set STICK adjusted by skew.
1839 */
1840/* ARGSUSED */
1841void
1842stick_adj(int64_t skew)
1843{
1844}
1845
1846#else	/* lint */
1847
1848	ENTRY_NP(stick_adj)
1849	rdpr	%pstate, %g1		! save processor state
1850	andn	%g1, PSTATE_IE, %g3
1851	ba	1f			! cache align stick adj
1852	wrpr	%g0, %g3, %pstate	! turn off interrupts
1853
1854	.align	16
18551:	nop
1856
1857	rd	STICK, %g4		! read stick reg
1858	add	%g4, %o0, %o1		! adjust stick with skew
1859	wr	%o1, %g0, STICK		! write stick reg
1860
1861	retl
1862	wrpr	%g1, %pstate		! restore processor state
1863	SET_SIZE(stick_adj)
1864
1865#endif	/* lint */
1866
1867#if defined(lint)
1868/*
1869 * Debugger-specific stick retrieval
1870 */
1871/*ARGSUSED*/
1872int
1873kdi_get_stick(uint64_t *stickp)
1874{
1875	return (0);
1876}
1877
1878#else	/* lint */
1879
1880	ENTRY_NP(kdi_get_stick)
1881	rd	STICK, %g1
1882	stx	%g1, [%o0]
1883	retl
1884	mov	%g0, %o0
1885	SET_SIZE(kdi_get_stick)
1886
1887#endif	/* lint */
1888
1889#if defined(lint)
1890
1891/*ARGSUSED*/
1892int
1893dtrace_blksuword32(uintptr_t addr, uint32_t *data, int tryagain)
1894{ return (0); }
1895
1896#else
1897
1898	ENTRY(dtrace_blksuword32)
1899	save	%sp, -SA(MINFRAME + 4), %sp
1900
1901	rdpr	%pstate, %l1
1902	andn	%l1, PSTATE_IE, %l2		! disable interrupts to
1903	wrpr	%g0, %l2, %pstate		! protect our FPU diddling
1904
1905	rd	%fprs, %l0
1906	andcc	%l0, FPRS_FEF, %g0
1907	bz,a,pt	%xcc, 1f			! if the fpu is disabled
1908	wr	%g0, FPRS_FEF, %fprs		! ... enable the fpu
1909
1910	st	%f0, [%fp + STACK_BIAS - 4]	! save %f0 to the stack
19111:
1912	set	0f, %l5
1913	/*
1914	 * We're about to write a block full or either total garbage
1915	 * (not kernel data, don't worry) or user floating-point data
1916	 * (so it only _looks_ like garbage).
1917	 */
1918	ld	[%i1], %f0			! modify the block
1919	membar	#Sync
1920	stn	%l5, [THREAD_REG + T_LOFAULT]	! set up the lofault handler
1921	stda	%d0, [%i0]ASI_BLK_COMMIT_S	! store the modified block
1922	membar	#Sync
1923	flush	%i0				! flush instruction pipeline
1924	stn	%g0, [THREAD_REG + T_LOFAULT]	! remove the lofault handler
1925
1926	bz,a,pt	%xcc, 1f
1927	wr	%g0, %l0, %fprs			! restore %fprs
1928
1929	ld	[%fp + STACK_BIAS - 4], %f0	! restore %f0
19301:
1931
1932	wrpr	%g0, %l1, %pstate		! restore interrupts
1933
1934	ret
1935	restore	%g0, %g0, %o0
1936
19370:
1938	membar	#Sync
1939	stn	%g0, [THREAD_REG + T_LOFAULT]	! remove the lofault handler
1940
1941	bz,a,pt	%xcc, 1f
1942	wr	%g0, %l0, %fprs			! restore %fprs
1943
1944	ld	[%fp + STACK_BIAS - 4], %f0	! restore %f0
19451:
1946
1947	wrpr	%g0, %l1, %pstate		! restore interrupts
1948
1949	/*
1950	 * If tryagain is set (%i2) we tail-call dtrace_blksuword32_err()
1951	 * which deals with watchpoints. Otherwise, just return -1.
1952	 */
1953	brnz,pt	%i2, 1f
1954	nop
1955	ret
1956	restore	%g0, -1, %o0
19571:
1958	call	dtrace_blksuword32_err
1959	restore
1960
1961	SET_SIZE(dtrace_blksuword32)
1962#endif /* lint */
1963
1964#if defined(lint)
1965/*ARGSUSED*/
1966void
1967ras_cntr_reset(void *arg)
1968{
1969}
1970#else
1971	ENTRY_NP(ras_cntr_reset)
1972	set	OPL_SCRATCHPAD_ERRLOG, %o1
1973	ldxa	[%o1]ASI_SCRATCHPAD, %o0
1974	or	%o0, ERRLOG_REG_NUMERR_MASK, %o0
1975	retl
1976	 stxa	%o0, [%o1]ASI_SCRATCHPAD
1977	SET_SIZE(ras_cntr_reset)
1978#endif /* lint */
1979
1980#if defined(lint)
1981/* ARGSUSED */
1982void
1983opl_error_setup(uint64_t cpu_err_log_pa)
1984{
1985}
1986
1987#else	/* lint */
1988	ENTRY_NP(opl_error_setup)
1989	/*
1990	 * Initialize the error log scratchpad register
1991	 */
1992	ldxa	[%g0]ASI_EIDR, %o2
1993	sethi	%hi(ERRLOG_REG_EIDR_MASK), %o1
1994	or	%o1, %lo(ERRLOG_REG_EIDR_MASK), %o1
1995	and	%o2, %o1, %o3
1996	sllx	%o3, ERRLOG_REG_EIDR_SHIFT, %o2
1997	or	%o2, %o0, %o3
1998	or	%o3, ERRLOG_REG_NUMERR_MASK, %o0
1999	set	OPL_SCRATCHPAD_ERRLOG, %o1
2000	stxa	%o0, [%o1]ASI_SCRATCHPAD
2001	/*
2002	 * Disable all restrainable error traps
2003	 */
2004	mov	AFSR_ECR, %o1
2005	ldxa	[%o1]ASI_AFSR, %o0
2006	andn	%o0, ASI_ECR_RTE_UE|ASI_ECR_RTE_CEDG, %o0
2007	retl
2008	  stxa	%o0, [%o1]ASI_AFSR
2009	SET_SIZE(opl_error_setup)
2010#endif /* lint */
2011
2012#if defined(lint)
2013/* ARGSUSED */
2014void
2015cpu_early_feature_init(void)
2016{
2017}
2018#else	/* lint */
2019	ENTRY_NP(cpu_early_feature_init)
2020	/*
2021	 * Enable MMU translating multiple page sizes for
2022	 * sITLB and sDTLB.
2023	 */
2024        mov	LSU_MCNTL, %o0
2025        ldxa	[%o0] ASI_MCNTL, %o1
2026        or	%o1, MCNTL_MPG_SITLB | MCNTL_MPG_SDTLB, %o1
2027          stxa	%o1, [%o0] ASI_MCNTL
2028	/*
2029	 * Demap all previous entries.
2030	 */
2031	sethi	%hi(FLUSH_ADDR), %o1
2032	set	DEMAP_ALL_TYPE, %o0
2033	stxa	%g0, [%o0]ASI_DTLB_DEMAP
2034	stxa	%g0, [%o0]ASI_ITLB_DEMAP
2035	retl
2036	  flush	%o1
2037	SET_SIZE(cpu_early_feature_init)
2038#endif /* lint */
2039
2040#if	defined(lint)
2041/*
2042 * This function is called for each (enabled) CPU. We use it to
2043 * initialize error handling related registers.
2044 */
2045/*ARGSUSED*/
2046void
2047cpu_feature_init(void)
2048{}
2049#else	/* lint */
2050	ENTRY(cpu_feature_init)
2051	!
2052	! get the device_id and store the device_id
2053	! in the appropriate cpunodes structure
2054	! given the cpus index
2055	!
2056	CPU_INDEX(%o0, %o1)
2057	mulx %o0, CPU_NODE_SIZE, %o0
2058	set  cpunodes + DEVICE_ID, %o1
2059	ldxa [%g0] ASI_DEVICE_SERIAL_ID, %o2
2060	stx  %o2, [%o0 + %o1]
2061	!
2062	! initialize CPU registers
2063	!
2064	ba	opl_cpu_reg_init
2065	nop
2066	SET_SIZE(cpu_feature_init)
2067#endif	/* lint */
2068
2069#if defined(lint)
2070
2071void
2072cpu_cleartickpnt(void)
2073{}
2074
2075#else	/* lint */
2076	/*
2077	 * Clear the NPT (non-privileged trap) bit in the %tick/%stick
2078	 * registers. In an effort to make the change in the
2079	 * tick/stick counter as consistent as possible, we disable
2080	 * all interrupts while we're changing the registers. We also
2081	 * ensure that the read and write instructions are in the same
2082	 * line in the instruction cache.
2083	 */
2084	ENTRY_NP(cpu_clearticknpt)
2085	rdpr	%pstate, %g1		/* save processor state */
2086	andn	%g1, PSTATE_IE, %g3	/* turn off */
2087	wrpr	%g0, %g3, %pstate	/*   interrupts */
2088	rdpr	%tick, %g2		/* get tick register */
2089	brgez,pn %g2, 1f		/* if NPT bit off, we're done */
2090	mov	1, %g3			/* create mask */
2091	sllx	%g3, 63, %g3		/*   for NPT bit */
2092	ba,a,pt	%xcc, 2f
2093	.align	8			/* Ensure rd/wr in same i$ line */
20942:
2095	rdpr	%tick, %g2		/* get tick register */
2096	wrpr	%g3, %g2, %tick		/* write tick register, */
2097					/*   clearing NPT bit   */
20981:
2099	rd	STICK, %g2		/* get stick register */
2100	brgez,pn %g2, 3f		/* if NPT bit off, we're done */
2101	mov	1, %g3			/* create mask */
2102	sllx	%g3, 63, %g3		/*   for NPT bit */
2103	ba,a,pt	%xcc, 4f
2104	.align	8			/* Ensure rd/wr in same i$ line */
21054:
2106	rd	STICK, %g2		/* get stick register */
2107	wr	%g3, %g2, STICK		/* write stick register, */
2108					/*   clearing NPT bit   */
21093:
2110	jmp	%g4 + 4
2111	wrpr	%g0, %g1, %pstate	/* restore processor state */
2112
2113	SET_SIZE(cpu_clearticknpt)
2114
2115#endif	/* lint */
2116
2117#if defined(lint)
2118
2119void
2120cpu_halt_cpu(void)
2121{}
2122
2123void
2124cpu_smt_pause(void)
2125{}
2126
2127#else	/* lint */
2128
2129	/*
2130	 * Halt the current strand with the suspend instruction.
2131	 * The compiler/asm currently does not support this suspend
2132	 * instruction mnemonic, use byte code for now.
2133	 */
2134	ENTRY_NP(cpu_halt_cpu)
2135	.word   0x81b01040
2136	retl
2137	nop
2138	SET_SIZE(cpu_halt_cpu)
2139
2140	/*
2141	 * Pause the current strand with the sleep instruction.
2142	 * The compiler/asm currently does not support this sleep
2143	 * instruction mnemonic, use byte code for now.
2144	 */
2145	ENTRY_NP(cpu_smt_pause)
2146	.word   0x81b01060
2147	retl
2148	nop
2149	SET_SIZE(cpu_smt_pause)
2150
2151#endif	/* lint */
2152