xref: /titanic_41/usr/src/uts/sun4v/ml/mach_interrupt.s (revision c2580b931007758eab8cb5ae8726ebe1588e259b)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#if defined(lint)
29#include <sys/types.h>
30#include <sys/thread.h>
31#else	/* lint */
32#include "assym.h"
33#endif	/* lint */
34
35#include <sys/asm_linkage.h>
36#include <sys/machthread.h>
37#include <sys/machcpuvar.h>
38#include <sys/intreg.h>
39#include <sys/cmn_err.h>
40#include <sys/ftrace.h>
41#include <sys/machasi.h>
42#include <sys/scb.h>
43#include <sys/error.h>
44#define	INTR_REPORT_SIZE	64
45
46#ifdef TRAPTRACE
47#include <sys/traptrace.h>
48#endif /* TRAPTRACE */
49
50#if defined(lint)
51
52void
53cpu_mondo(void)
54{}
55
56#else	/* lint */
57
58
59/*
60 * (TT 0x7c, TL>0) CPU Mondo Queue Handler
61 *	Globals are the Interrupt Globals.
62 */
63	ENTRY_NP(cpu_mondo)
64	!
65	!	Register Usage:-
66	!	%g5	PC for fasttrap TL>0 handler
67	!	%g1	arg 1
68	!	%g2	arg 2
69	!	%g3	queue base VA
70	!	%g4 	queue size mask
71	!	%g6	head ptr
72	!	%g7	tail ptr
73	mov	CPU_MONDO_Q_HD, %g3
74	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
75	mov	CPU_MONDO_Q_TL, %g4
76	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
77	cmp	%g6, %g7
78	be,pn	%xcc, 0f		! head == tail
79	nop
80
81	CPU_ADDR(%g1,%g2)
82	add	%g1, CPU_MCPU, %g2
83	ldx	[%g2 + MCPU_CPU_Q_BASE], %g3	! %g3 = queue base PA
84	ldx	[%g2 + MCPU_CPU_Q_SIZE], %g4	! queue size
85	sub	%g4, 1, %g4		! %g4 = queue size mask
86
87	! Load interrupt receive data registers 1 and 2 to fetch
88	! the arguments for the fast trap handler.
89	!
90	! XXX - Since the data words in the interrupt report are not defined yet
91	! we assume that the consective words contain valid data and preserve
92	! sun4u's xcall mondo arguments.
93	! Register usage:
94	!	%g5	PC for fasttrap TL>0 handler
95	!	%g1	arg 1
96	!	%g2	arg 2
97
98	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get PC from q base + head
99	add	%g6, 0x8, %g6		! inc head
100	ldxa	[%g3 + %g6]ASI_MEM, %g1 ! read data word 1
101	add	%g6, 0x8, %g6		! inc head
102	ldxa	[%g3 + %g6]ASI_MEM, %g2	! read data word 2
103	add	%g6, (INTR_REPORT_SIZE - 16) , %g6 ! inc head to next record
104	and	%g6, %g4, %g6 		! and size mask for wrap around
105	mov	CPU_MONDO_Q_HD, %g3
106	stxa	%g6, [%g3]ASI_QUEUE	! store head pointer
107	membar	#Sync
108
109#ifdef TRAPTRACE
110	TRACE_PTR(%g4, %g6)
111	GET_TRACE_TICK(%g6)
112	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
113	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
114	rdpr	%tt, %g6
115	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
116	rdpr	%tpc, %g6
117	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
118	rdpr	%tstate, %g6
119	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
120	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
121	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! pc of the TL>0 handler
122	stna	%g1, [%g4 + TRAP_ENT_F1]%asi	! arg1
123	stna	%g2, [%g4 + TRAP_ENT_F3]%asi	! arg2
124	mov	CPU_MONDO_Q_HD, %g6
125	ldxa	[%g6]ASI_QUEUE, %g6		! new head offset
126	stna	%g6, [%g4 + TRAP_ENT_F2]%asi
127	stna	%g7, [%g4 + TRAP_ENT_F4]%asi	! tail offset
128	TRACE_NEXT(%g4, %g6, %g3)
129#endif /* TRAPTRACE */
130
131	/*
132	 * For now catch invalid PC being passed via cpu_mondo queue
133	 */
134	set	KERNELBASE, %g4
135	cmp	%g5, %g4
136	bl,a,pn	%xcc, 1f		! branch if bad %pc
137	nop
138
139	jmp	%g5			! jump to traphandler
140	nop
1411:
142	! invalid trap handler, discard it for now
143	set	cpu_mondo_inval, %g4
144	ldx	[%g4], %g5
145	inc	%g5
146	stx	%g5, [%g4]
1470:
148	retry
149	/* Never Reached */
150	SET_SIZE(cpu_mondo)
151
152#endif /* lint */
153
154#if defined(lint)
155
156void
157dev_mondo(void)
158{}
159
160#else	/* lint */
161
162
163/*
164 * (TT 0x7d, TL>0) Dev Mondo Queue Handler
165 *	Globals are the Interrupt Globals.
166 * We only process one interrupt at a time causing us to keep
167 * taking this trap till the queue is empty.
168 * We really should drain the whole queue for better performance
169 * but this will do for now.
170 */
171	ENTRY_NP(dev_mondo)
172	!
173	!	Register Usage:-
174	!	%g5	PC for fasttrap TL>0 handler
175	!	%g1	arg 1
176	!	%g2	arg 2
177	!	%g3	queue base PA
178	!	%g4 	queue size mask
179	!	%g6	head ptr
180	!	%g7	tail ptr
181	mov	DEV_MONDO_Q_HD, %g3
182	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
183	mov	DEV_MONDO_Q_TL, %g4
184	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
185	cmp	%g6, %g7
186	be,pn	%xcc, 0f		! head == tail
187	nop
188
189	CPU_ADDR(%g1,%g2)
190	add	%g1, CPU_MCPU, %g2
191	ldx	[%g2 + MCPU_DEV_Q_BASE], %g3	! %g3 = queue base PA
192
193	! Register usage:
194	!	%g5 - inum
195	!	%g1 - cpu struct pointer used below in TRAPTRACE
196	!
197	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get inum from q base + head
198
199	!
200	! We verify that inum is valid ( < MAXVNUM). If it is greater
201	! than MAXVNUM, we let setvecint_tl1 take care of it.
202	!
203	set	MAXIVNUM, %g4
204	cmp	%g5, %g4
205	bgeu,a,pn	%xcc, 1f
206	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
207
208	!
209	!	Copy 64-byte payload to the *iv_payload if it is not NULL
210	!
211	set	intr_vec_table, %g1		! %g1 = intr_vec_table
212	sll	%g5, CPTRSHIFT, %g7		! %g7 = offset to inum entry
213						!       in the intr_vec_table
214	add	%g1, %g7, %g7			! %g7 = &intr_vec_table[inum]
215	ldn	[%g7], %g1			! %g1 = ptr to intr_vec_t (iv)
216
217	!
218	! Verify the pointer to first intr_vec_t for a given inum and
219	! it should not be NULL. If this pointer is NULL, then it is a
220	! spurious interrupt. In this case, just call setvecint_tl1 and
221	! it will handle this spurious interrupt.
222	!
223	brz,a,pn	%g1, 1f			! if %g1 is NULL
224	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
225
226	ldx	[%g1 + IV_PAYLOAD_BUF], %g1	! %g1 = iv->iv_payload_buf
227	brz,a,pt	%g1, 1f			! if it is NULL
228	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
229
230	!
231	!	Now move 64 byte payload from mondo queue to buf
232	!
233	mov	%g6, %g7			! %g7 = head ptr
234	ldxa	[%g3 + %g7]ASI_MEM, %g4
235	stx	%g4, [%g1 + 0]			! byte 0 - 7
236	add	%g7, 8, %g7
237	ldxa	[%g3 + %g7]ASI_MEM, %g4
238	stx	%g4, [%g1 + 8]			! byte 8 - 15
239	add	%g7, 8, %g7
240	ldxa	[%g3 + %g7]ASI_MEM, %g4
241	stx	%g4, [%g1 + 16]			! byte 16 - 23
242	add	%g7, 8, %g7
243	ldxa	[%g3 + %g7]ASI_MEM, %g4
244	stx	%g4, [%g1 + 24]			! byte 24 - 31
245	add	%g7, 8, %g7
246	ldxa	[%g3 + %g7]ASI_MEM, %g4
247	stx	%g4, [%g1 + 32]			! byte 32 - 39
248	add	%g7, 8, %g7
249	ldxa	[%g3 + %g7]ASI_MEM, %g4
250	stx	%g4, [%g1 + 40]			! byte 40 - 47
251	add	%g7, 8, %g7
252	ldxa	[%g3 + %g7]ASI_MEM, %g4
253	stx	%g4, [%g1 + 48]			! byte 48 - 55
254	add	%g7, 8, %g7
255	ldxa	[%g3 + %g7]ASI_MEM, %g4
256	stx	%g4, [%g1 + 56]			! byte 56 - 63
257	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size
258
2591:	sub	%g4, 1, %g4		! %g4 = queue size mask
260	add	%g6, INTR_REPORT_SIZE , %g6 ! inc head to next record
261	and	%g6, %g4, %g6 		! and mask for wrap around
262	mov	DEV_MONDO_Q_HD, %g3
263	stxa	%g6, [%g3]ASI_QUEUE	! increment head offset
264	membar	#Sync
265
266#ifdef TRAPTRACE
267	TRACE_PTR(%g4, %g6)
268	GET_TRACE_TICK(%g6)
269	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
270	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
271	rdpr	%tt, %g6
272	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
273	rdpr	%tpc, %g6
274	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
275	rdpr	%tstate, %g6
276	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
277	! move head to sp
278	ldx	[%g2 + MCPU_DEV_Q_BASE], %g6
279	stna	%g6, [%g4 + TRAP_ENT_SP]%asi	! Device Queue Base PA
280	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! Inum
281	mov	DEV_MONDO_Q_HD, %g6
282	ldxa	[%g6]ASI_QUEUE, %g6		! New head offset
283	stna	%g6, [%g4 + TRAP_ENT_F1]%asi
284	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g6
285	stna	%g6, [%g4 + TRAP_ENT_F2]%asi	! Q Size
286	stna	%g7, [%g4 + TRAP_ENT_F3]%asi	! tail offset
287	stna	%g0, [%g4 + TRAP_ENT_F4]%asi
288	TRACE_NEXT(%g4, %g6, %g3)
289#endif /* TRAPTRACE */
290
291	!
292	! setvecint_tl1 will do all the work, and finish with a retry
293	!
294	ba,pt	%xcc, setvecint_tl1
295	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
296
2970:	retry
298
299	/* Never Reached */
300	SET_SIZE(dev_mondo)
301#endif /* lint */
302
303#if defined(lint)
304uint64_t cpu_mondo_inval;
305#else /* lint */
306	.seg	".data"
307	.global	cpu_mondo_inval
308	.align	8
309cpu_mondo_inval:
310	.skip	8
311
312	.seg	".text"
313#endif	/* lint */
314
315
316#if defined(lint)
317
318void
319resumable_error(void)
320{}
321
322#else	/* lint */
323
324/*
325 * (TT 0x7e, TL>0) Resumeable Error Queue Handler
326 *	We keep a shadow copy of the queue in kernel buf.
327 *	Read the resumable queue head and tail offset
328 *	If there are entries on the queue, move them to
329 *	the kernel buf, which is next to the resumable
330 *	queue in the memory. Call C routine to process.
331 */
332	ENTRY_NP(resumable_error)
333	mov	CPU_RQ_HD, %g4
334	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
335	mov	CPU_RQ_TL, %g4
336	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
337	mov	%g2, %g6			! save head in %g2
338
339	cmp	%g6, %g3
340	be,pn	%xcc, 0f			! head == tail
341	nop
342
343	CPU_ADDR(%g1, %g4)			! %g1 = cpu struct addr
344
3452:	set	CPU_RQ_BASE_OFF, %g4
346	ldx	[%g1 + %g4], %g4		! %g4 = queue base PA
347	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
348	set	CPU_RQ_SIZE, %g7
349	add	%g4, %g7, %g7			! %g7=PA of ER in kernel buf
350
351	ldxa	[%g7]ASI_MEM, %g5		! %g5=first 8 byte of ER buf
352	cmp	0, %g5
353	bne,pn	%xcc, 1f			! first 8 byte is not 0
354	nop
355
356	/* Now we can move 64 bytes from queue to buf */
357	set	0, %g5
358	ldxa	[%g4 + %g5]ASI_MEM, %g1
359	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
360	add	%g5, 8, %g5
361	ldxa	[%g4 + %g5]ASI_MEM, %g1
362	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
363	add	%g5, 8, %g5
364	ldxa	[%g4 + %g5]ASI_MEM, %g1
365	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
366	add	%g5, 8, %g5
367	ldxa	[%g4 + %g5]ASI_MEM, %g1
368	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
369	add	%g5, 8, %g5
370	ldxa	[%g4 + %g5]ASI_MEM, %g1
371	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
372	add	%g5, 8, %g5
373	ldxa	[%g4 + %g5]ASI_MEM, %g1
374	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
375	add	%g5, 8, %g5
376	ldxa	[%g4 + %g5]ASI_MEM, %g1
377	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
378	add	%g5, 8, %g5
379	ldxa	[%g4 + %g5]ASI_MEM, %g1
380	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
381
382	set	CPU_RQ_SIZE, %g5		! %g5 = queue size
383	sub	%g5, 1, %g5			! %g5 = queu size mask
384
385	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
386	and	%g6, %g5, %g6			! size mask for warp around
387	cmp	%g6, %g3			! head == tail ??
388
389	bne,pn	%xcc, 2b			! still have more to process
390	nop
391
392	/*
393	 * head equals to tail now, we can update the queue head
394	 * and call sys_trap
395	 */
396	mov	CPU_RQ_HD, %g4
397	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
398
399	/*
400	 * Call sys_trap at PIL 14 unless we're already at PIL 15. %g2.l is
401	 * head offset(arg2) and %g3 is tail
402	 * offset(arg3).
403	 */
404	set	process_resumable_error, %g1
405	rdpr	%pil, %g4
406	cmp	%g4, PIL_14
407	ba	sys_trap
408	  movl	%icc, PIL_14, %g4
409
410	/*
411	 * We are here because the C routine is not able to process
412	 * errors in time. So the first 8 bytes of ER in buf has not
413	 * been cleared. We update head to tail and call sys_trap to
414	 * print out an error message
415	 */
416
4171:	mov	CPU_RQ_HD, %g4
418	stxa	%g3, [%g4]ASI_QUEUE		! set head equal to tail
419
420	/*
421	 * Set %g2 to %g6, which is current head offset. %g2
422	 * is arg2 of the C routine. %g3 is the tail offset,
423	 * which is arg3 of the C routine.
424	 * Call rq_overflow at PIL 14 unless we're already at PIL 15.
425	 */
426	mov	%g6, %g2
427	set	rq_overflow, %g1
428	rdpr	%pil, %g4
429	cmp	%g4, PIL_14
430	ba	sys_trap
431	  movl	%icc, PIL_14, %g4
432
4330:	retry
434
435	/*NOTREACHED*/
436	SET_SIZE(resumable_error)
437#endif /* lint */
438
439#if defined(lint)
440
441void
442nonresumable_error(void)
443{}
444
445#else	/* lint */
446
447/*
448 * (TT 0x7f, TL>0) Non-resumeable Error Queue Handler
449 *	We keep a shadow copy of the queue in kernel buf.
450 *	Read non-resumable queue head and tail offset
451 *	If there are entries on the queue, move them to
452 *	the kernel buf, which is next to the non-resumable
453 *	queue in the memory. Call C routine to process.
454 */
455	ENTRY_NP(nonresumable_error)
456	mov	CPU_NRQ_HD, %g4
457	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
458	mov	CPU_NRQ_TL, %g4
459	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
460
461	cmp	%g2, %g3
462	be,pn	%xcc, 0f			! head == tail
463	nop
464
465	/* force %gl to 1 as sys_trap requires */
466	wrpr	%g0, 1, %gl
467	mov	CPU_NRQ_HD, %g4
468	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
469	mov	CPU_NRQ_TL, %g4
470	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
471	mov	%g2, %g6			! save head in %g2
472
473	CPU_PADDR(%g1, %g4)			! %g1 = cpu struct paddr
474
4752:	set	CPU_NRQ_BASE_OFF, %g4
476	ldxa	[%g1 + %g4]ASI_MEM, %g4		! %g4 = queue base PA
477	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
478	set	CPU_NRQ_SIZE, %g7
479	add	%g4, %g7, %g7			! %g7 = PA of ER in kernel buf
480
481	ldxa	[%g7]ASI_MEM, %g5		! %g5 = first 8 byte of ER buf
482	cmp	0, %g5
483	bne,pn	%xcc, 1f			! first 8 byte is not 0
484	nop
485
486	/* Now we can move 64 bytes from queue to buf */
487	set	0, %g5
488	ldxa	[%g4 + %g5]ASI_MEM, %g1
489	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
490	add	%g5, 8, %g5
491	ldxa	[%g4 + %g5]ASI_MEM, %g1
492	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
493	add	%g5, 8, %g5
494	ldxa	[%g4 + %g5]ASI_MEM, %g1
495	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
496	add	%g5, 8, %g5
497	ldxa	[%g4 + %g5]ASI_MEM, %g1
498	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
499	add	%g5, 8, %g5
500	ldxa	[%g4 + %g5]ASI_MEM, %g1
501	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
502	add	%g5, 8, %g5
503	ldxa	[%g4 + %g5]ASI_MEM, %g1
504	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
505	add	%g5, 8, %g5
506	ldxa	[%g4 + %g5]ASI_MEM, %g1
507	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
508	add	%g5, 8, %g5
509	ldxa	[%g4 + %g5]ASI_MEM, %g1
510	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
511
512	set	CPU_NRQ_SIZE, %g5		! %g5 = queue size
513	sub	%g5, 1, %g5			! %g5 = queu size mask
514
515	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
516	and	%g6, %g5, %g6			! size mask for warp around
517	cmp	%g6, %g3			! head == tail ??
518
519	bne,pn	%xcc, 2b			! still have more to process
520	nop
521
522	/*
523	 * head equals to tail now, we can update the queue head
524	 * and call sys_trap
525	 */
526	mov	CPU_NRQ_HD, %g4
527	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
528
529	/*
530	 * Call sys_trap. %g2 is TL(arg2), %g3 is head and tail
531	 * offset(arg3).
532	 * %g3 looks like following:
533	 *	+--------------------+--------------------+
534	 *	|   tail offset      |    head offset     |
535	 *	+--------------------+--------------------+
536	 *	63                 32 31                 0
537	 *
538	 * Run at PIL 14 unless we're already at PIL 15.
539	 */
540	sllx	%g3, 32, %g3			! %g3.h = tail offset
541	or	%g3, %g2, %g3			! %g3.l = head offset
542	rdpr	%tl, %g2			! %g2 = current tl
543
544	/*
545	 * Now check if the first error that sent us here was caused
546	 * in user's SPILL/FILL trap. If it was, we call sys_trap to
547	 * kill the user process. Several considerations:
548	 * - If multiple nonresumable errors happen, we only check the
549	 *   first one. Nonresumable errors cause system either panic
550	 *   or kill the user process. So the system has already
551	 *   panic'ed or killed user process after processing the first
552	 *   error. Therefore, no need to check if other error packet
553	 *   for this type of error.
554	 * - Errors happen in user's SPILL/FILL trap will bring us at
555	 *   TL = 2.
556	 * - We need to lower TL to 1 to get the trap type and tstate.
557	 *   We don't go back to TL = 2 so no need to save states.
558	 */
559	cmp	%g2, 2
560	bne,pt	%xcc, 3f			! if tl != 2
561	nop
562	/* Check to see if the trap pc is in a window spill/fill handling */
563	rdpr	%tpc, %g4
564	/* tpc should be in the trap table */
565	set	trap_table, %g5
566	cmp	%g4, %g5
567	blu,pt	%xcc, 3f
568	nop
569	set	etrap_table, %g5
570	cmp	%g4, %g5
571	bgeu,pt	%xcc, 3f
572	nop
573	/* Set tl to 1 in order to read tt[1] and tstate[1] */
574	wrpr	%g0, 1, %tl
575	rdpr	%tt, %g4			! %g4 = tt[1]
576	/* Check if tt[1] is a window trap */
577	and	%g4, WTRAP_TTMASK, %g4
578	cmp	%g4, WTRAP_TYPE
579	bne,pt	%xcc, 3f
580	nop
581	rdpr	%tstate, %g5			! %g5 = tstate[1]
582	btst	TSTATE_PRIV, %g5
583	bnz	%xcc, 3f			! Is it from user code?
584	nop
585	/*
586	 * Now we know the error happened in user's SPILL/FILL trap.
587	 * Turn on the user spill/fill flag in %g2
588	 */
589	mov	1, %g4
590	sllx	%g4, ERRH_U_SPILL_FILL_SHIFT, %g4
591	or	%g2, %g4, %g2			! turn on flag in %g2
592
5933:	sub	%g2, 1, %g2			! %g2.l = previous tl
594
595	set	process_nonresumable_error, %g1
596	rdpr	%pil, %g4
597	cmp	%g4, PIL_14
598	ba	sys_trap
599	  movl	%icc, PIL_14, %g4
600
601	/*
602	 * We are here because the C routine is not able to process
603	 * errors in time. So the first 8 bytes of ER in buf has not
604	 * been cleared. We call sys_trap to panic.
605	 * Run at PIL 14 unless we're already at PIL 15.
606	 */
6071:	set	nrq_overflow, %g1
608	rdpr	%pil, %g4
609	cmp	%g4, PIL_14
610	ba	sys_trap
611	  movl	%icc, PIL_14, %g4
612
6130:	retry
614
615	/*NOTREACHED*/
616	SET_SIZE(nonresumable_error)
617#endif /* lint */
618