xref: /titanic_41/usr/src/uts/sun4v/ml/mach_interrupt.s (revision 023e71de9e5670cebc23dd51162833661d3d2d3b)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#if defined(lint)
27#include <sys/types.h>
28#include <sys/thread.h>
29#else	/* lint */
30#include "assym.h"
31#endif	/* lint */
32
33#include <sys/asm_linkage.h>
34#include <sys/machthread.h>
35#include <sys/machcpuvar.h>
36#include <sys/intreg.h>
37#include <sys/cmn_err.h>
38#include <sys/ftrace.h>
39#include <sys/machasi.h>
40#include <sys/scb.h>
41#include <sys/error.h>
42#include <sys/mmu.h>
43#include <vm/hat_sfmmu.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, 3f		! 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, %g3)
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,pn	%xcc, 2f		! branch if bad %pc
137	  nop
138
139
140	/*
141	 * If this platform supports shared contexts and we are jumping
142	 * to OBP code, then we need to invalidate both contexts to prevent OBP
143	 * from corrupting the shared context registers.
144	 *
145	 * If shared contexts are not supported then the next two instructions
146	 * will be patched with:
147	 *
148	 * jmp       %g5
149	 * nop
150	 *
151	 */
152	.global sfmmu_shctx_cpu_mondo_patch
153sfmmu_shctx_cpu_mondo_patch:
154	set	OFW_START_ADDR, %g4	! Check if this a call into OBP?
155	cmp	%g5, %g4
156	bl,pt %xcc, 1f
157	  nop
158	set	OFW_END_ADDR, %g4
159	cmp	%g5, %g4
160	bg,pn %xcc, 1f
161	  nop
162	mov	MMU_PCONTEXT, %g3
163	ldxa	[%g3]ASI_MMU_CTX, %g4
164	cmp	%g4, INVALID_CONTEXT	! Check if we are in kernel mode
165	ble,pn %xcc, 1f			! or the primary context is invalid
166	  nop
167	set	INVALID_CONTEXT, %g4	! Invalidate contexts - compatability
168	stxa    %g4, [%g3]ASI_MMU_CTX	! mode ensures shared contexts are also
169	mov     MMU_SCONTEXT, %g3	! invalidated.
170	stxa    %g4, [%g3]ASI_MMU_CTX
171	membar  #Sync
172	mov	%o0, %g3		! save output regs
173	mov	%o1, %g4
174	mov	%o5, %g6
175	clr	%o0			! Invalidate tsbs, set ntsb = 0
176	clr	%o1			! and HV_TSB_INFO_PA = 0
177	mov	MMU_TSB_CTXNON0, %o5
178	ta	FAST_TRAP		! set TSB info for user process
179	brnz,a,pn %o0, ptl1_panic
180	  mov	PTL1_BAD_HCALL, %g1
181	mov	%g3, %o0		! restore output regs
182	mov	%g4, %o1
183	mov	%g6, %o5
1841:
185	jmp	%g5			! jump to traphandler
186	nop
1872:
188	! invalid trap handler, discard it for now
189	set	cpu_mondo_inval, %g4
190	ldx	[%g4], %g5
191	inc	%g5
192	stx	%g5, [%g4]
1933:
194	retry
195	/* Never Reached */
196	SET_SIZE(cpu_mondo)
197
198#endif /* lint */
199
200#if defined(lint)
201
202void
203dev_mondo(void)
204{}
205
206#else	/* lint */
207
208
209/*
210 * (TT 0x7d, TL>0) Dev Mondo Queue Handler
211 *	Globals are the Interrupt Globals.
212 * We only process one interrupt at a time causing us to keep
213 * taking this trap till the queue is empty.
214 * We really should drain the whole queue for better performance
215 * but this will do for now.
216 */
217	ENTRY_NP(dev_mondo)
218	!
219	!	Register Usage:-
220	!	%g5	PC for fasttrap TL>0 handler
221	!	%g1	arg 1
222	!	%g2	arg 2
223	!	%g3	queue base PA
224	!	%g4 	queue size mask
225	!	%g6	head ptr
226	!	%g7	tail ptr
227	mov	DEV_MONDO_Q_HD, %g3
228	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
229	mov	DEV_MONDO_Q_TL, %g4
230	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
231	cmp	%g6, %g7
232	be,pn	%xcc, 0f		! head == tail
233	nop
234
235	CPU_ADDR(%g1,%g2)
236	add	%g1, CPU_MCPU, %g2
237	ldx	[%g2 + MCPU_DEV_Q_BASE], %g3	! %g3 = queue base PA
238
239	! Register usage:
240	!	%g5 - inum
241	!	%g1 - cpu struct pointer used below in TRAPTRACE
242	!
243	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get inum from q base + head
244
245	!
246	! We verify that inum is valid ( < MAXVNUM). If it is greater
247	! than MAXVNUM, we let setvecint_tl1 take care of it.
248	!
249	set	MAXIVNUM, %g4
250	cmp	%g5, %g4
251	bgeu,a,pn	%xcc, 1f
252	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
253
254	!
255	!	Copy 64-byte payload to the *iv_payload if it is not NULL
256	!
257	set	intr_vec_table, %g1		! %g1 = intr_vec_table
258	sll	%g5, CPTRSHIFT, %g7		! %g7 = offset to inum entry
259						!       in the intr_vec_table
260	add	%g1, %g7, %g7			! %g7 = &intr_vec_table[inum]
261	ldn	[%g7], %g1			! %g1 = ptr to intr_vec_t (iv)
262
263	!
264	! Verify the pointer to first intr_vec_t for a given inum and
265	! it should not be NULL. If this pointer is NULL, then it is a
266	! spurious interrupt. In this case, just call setvecint_tl1 and
267	! it will handle this spurious interrupt.
268	!
269	brz,a,pn	%g1, 1f			! if %g1 is NULL
270	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
271
272	ldx	[%g1 + IV_PAYLOAD_BUF], %g1	! %g1 = iv->iv_payload_buf
273	brz,a,pt	%g1, 1f			! if it is NULL
274	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
275
276	!
277	!	Now move 64 byte payload from mondo queue to buf
278	!
279	mov	%g6, %g7			! %g7 = head ptr
280	ldxa	[%g3 + %g7]ASI_MEM, %g4
281	stx	%g4, [%g1 + 0]			! byte 0 - 7
282	add	%g7, 8, %g7
283	ldxa	[%g3 + %g7]ASI_MEM, %g4
284	stx	%g4, [%g1 + 8]			! byte 8 - 15
285	add	%g7, 8, %g7
286	ldxa	[%g3 + %g7]ASI_MEM, %g4
287	stx	%g4, [%g1 + 16]			! byte 16 - 23
288	add	%g7, 8, %g7
289	ldxa	[%g3 + %g7]ASI_MEM, %g4
290	stx	%g4, [%g1 + 24]			! byte 24 - 31
291	add	%g7, 8, %g7
292	ldxa	[%g3 + %g7]ASI_MEM, %g4
293	stx	%g4, [%g1 + 32]			! byte 32 - 39
294	add	%g7, 8, %g7
295	ldxa	[%g3 + %g7]ASI_MEM, %g4
296	stx	%g4, [%g1 + 40]			! byte 40 - 47
297	add	%g7, 8, %g7
298	ldxa	[%g3 + %g7]ASI_MEM, %g4
299	stx	%g4, [%g1 + 48]			! byte 48 - 55
300	add	%g7, 8, %g7
301	ldxa	[%g3 + %g7]ASI_MEM, %g4
302	stx	%g4, [%g1 + 56]			! byte 56 - 63
303	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size
304
3051:	sub	%g4, 1, %g4		! %g4 = queue size mask
306	add	%g6, INTR_REPORT_SIZE , %g6 ! inc head to next record
307	and	%g6, %g4, %g6 		! and mask for wrap around
308	mov	DEV_MONDO_Q_HD, %g3
309	stxa	%g6, [%g3]ASI_QUEUE	! increment head offset
310	membar	#Sync
311
312#ifdef TRAPTRACE
313	TRACE_PTR(%g4, %g6)
314	GET_TRACE_TICK(%g6, %g3)
315	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
316	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
317	rdpr	%tt, %g6
318	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
319	rdpr	%tpc, %g6
320	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
321	rdpr	%tstate, %g6
322	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
323	! move head to sp
324	ldx	[%g2 + MCPU_DEV_Q_BASE], %g6
325	stna	%g6, [%g4 + TRAP_ENT_SP]%asi	! Device Queue Base PA
326	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! Inum
327	mov	DEV_MONDO_Q_HD, %g6
328	ldxa	[%g6]ASI_QUEUE, %g6		! New head offset
329	stna	%g6, [%g4 + TRAP_ENT_F1]%asi
330	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g6
331	stna	%g6, [%g4 + TRAP_ENT_F2]%asi	! Q Size
332	stna	%g7, [%g4 + TRAP_ENT_F3]%asi	! tail offset
333	stna	%g0, [%g4 + TRAP_ENT_F4]%asi
334	TRACE_NEXT(%g4, %g6, %g3)
335#endif /* TRAPTRACE */
336
337	!
338	! setvecint_tl1 will do all the work, and finish with a retry
339	!
340	ba,pt	%xcc, setvecint_tl1
341	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
342
3430:	retry
344
345	/* Never Reached */
346	SET_SIZE(dev_mondo)
347#endif /* lint */
348
349#if defined(lint)
350uint64_t cpu_mondo_inval;
351#else /* lint */
352	.seg	".data"
353	.global	cpu_mondo_inval
354	.align	8
355cpu_mondo_inval:
356	.skip	8
357
358	.seg	".text"
359#endif	/* lint */
360
361
362#if defined(lint)
363
364void
365resumable_error(void)
366{}
367
368#else	/* lint */
369
370/*
371 * (TT 0x7e, TL>0) Resumeable Error Queue Handler
372 *	We keep a shadow copy of the queue in kernel buf.
373 *	Read the resumable queue head and tail offset
374 *	If there are entries on the queue, move them to
375 *	the kernel buf, which is next to the resumable
376 *	queue in the memory. Call C routine to process.
377 */
378	ENTRY_NP(resumable_error)
379	mov	CPU_RQ_HD, %g4
380	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
381	mov	CPU_RQ_TL, %g4
382	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
383	mov	%g2, %g6			! save head in %g2
384
385	cmp	%g6, %g3
386	be,pn	%xcc, 0f			! head == tail
387	nop
388
389	CPU_ADDR(%g1, %g4)			! %g1 = cpu struct addr
390
3912:	set	CPU_RQ_BASE_OFF, %g4
392	ldx	[%g1 + %g4], %g4		! %g4 = queue base PA
393	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
394	set	CPU_RQ_SIZE, %g7
395	add	%g4, %g7, %g7			! %g7=PA of ER in kernel buf
396
397	ldxa	[%g7]ASI_MEM, %g5		! %g5=first 8 byte of ER buf
398	cmp	0, %g5
399	bne,pn	%xcc, 1f			! first 8 byte is not 0
400	nop
401
402	/* Now we can move 64 bytes from queue to buf */
403	set	0, %g5
404	ldxa	[%g4 + %g5]ASI_MEM, %g1
405	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
406	add	%g5, 8, %g5
407	ldxa	[%g4 + %g5]ASI_MEM, %g1
408	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
409	add	%g5, 8, %g5
410	ldxa	[%g4 + %g5]ASI_MEM, %g1
411	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
412	add	%g5, 8, %g5
413	ldxa	[%g4 + %g5]ASI_MEM, %g1
414	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
415	add	%g5, 8, %g5
416	ldxa	[%g4 + %g5]ASI_MEM, %g1
417	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
418	add	%g5, 8, %g5
419	ldxa	[%g4 + %g5]ASI_MEM, %g1
420	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
421	add	%g5, 8, %g5
422	ldxa	[%g4 + %g5]ASI_MEM, %g1
423	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
424	add	%g5, 8, %g5
425	ldxa	[%g4 + %g5]ASI_MEM, %g1
426	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
427
428	set	CPU_RQ_SIZE, %g5		! %g5 = queue size
429	sub	%g5, 1, %g5			! %g5 = queu size mask
430
431	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
432	and	%g6, %g5, %g6			! size mask for warp around
433	cmp	%g6, %g3			! head == tail ??
434
435	bne,pn	%xcc, 2b			! still have more to process
436	nop
437
438	/*
439	 * head equals to tail now, we can update the queue head
440	 * and call sys_trap
441	 */
442	mov	CPU_RQ_HD, %g4
443	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
444	membar	#Sync
445
446	/*
447	 * Call sys_trap at PIL 14 unless we're already at PIL 15. %g2.l is
448	 * head offset(arg2) and %g3 is tail
449	 * offset(arg3).
450	 */
451	set	process_resumable_error, %g1
452	rdpr	%pil, %g4
453	cmp	%g4, PIL_14
454	ba	sys_trap
455	  movl	%icc, PIL_14, %g4
456
457	/*
458	 * We are here because the C routine is not able to process
459	 * errors in time. So the first 8 bytes of ER in buf has not
460	 * been cleared. We update head to tail and call sys_trap to
461	 * print out an error message
462	 */
463
4641:	mov	CPU_RQ_HD, %g4
465	stxa	%g3, [%g4]ASI_QUEUE		! set head equal to tail
466	membar	#Sync
467
468	/*
469	 * Set %g2 to %g6, which is current head offset. %g2
470	 * is arg2 of the C routine. %g3 is the tail offset,
471	 * which is arg3 of the C routine.
472	 * Call rq_overflow at PIL 14 unless we're already at PIL 15.
473	 */
474	mov	%g6, %g2
475	set	rq_overflow, %g1
476	rdpr	%pil, %g4
477	cmp	%g4, PIL_14
478	ba	sys_trap
479	  movl	%icc, PIL_14, %g4
480
4810:	retry
482
483	/*NOTREACHED*/
484	SET_SIZE(resumable_error)
485#endif /* lint */
486
487#if defined(lint)
488
489void
490nonresumable_error(void)
491{}
492
493#else	/* lint */
494
495/*
496 * (TT 0x7f, TL>0) Non-resumeable Error Queue Handler
497 *	We keep a shadow copy of the queue in kernel buf.
498 *	Read non-resumable queue head and tail offset
499 *	If there are entries on the queue, move them to
500 *	the kernel buf, which is next to the non-resumable
501 *	queue in the memory. Call C routine to process.
502 */
503	ENTRY_NP(nonresumable_error)
504	mov	CPU_NRQ_HD, %g4
505	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
506	mov	CPU_NRQ_TL, %g4
507	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
508
509	cmp	%g2, %g3
510	be,pn	%xcc, 0f			! head == tail
511	nop
512
513	/* force %gl to 1 as sys_trap requires */
514	wrpr	%g0, 1, %gl
515	mov	CPU_NRQ_HD, %g4
516	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
517	mov	CPU_NRQ_TL, %g4
518	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
519	mov	%g2, %g6			! save head in %g2
520
521	CPU_PADDR(%g1, %g4)			! %g1 = cpu struct paddr
522
5232:	set	CPU_NRQ_BASE_OFF, %g4
524	ldxa	[%g1 + %g4]ASI_MEM, %g4		! %g4 = queue base PA
525	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
526	set	CPU_NRQ_SIZE, %g7
527	add	%g4, %g7, %g7			! %g7 = PA of ER in kernel buf
528
529	ldxa	[%g7]ASI_MEM, %g5		! %g5 = first 8 byte of ER buf
530	cmp	0, %g5
531	bne,pn	%xcc, 1f			! first 8 byte is not 0
532	nop
533
534	/* Now we can move 64 bytes from queue to buf */
535	set	0, %g5
536	ldxa	[%g4 + %g5]ASI_MEM, %g1
537	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
538	add	%g5, 8, %g5
539	ldxa	[%g4 + %g5]ASI_MEM, %g1
540	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
541	add	%g5, 8, %g5
542	ldxa	[%g4 + %g5]ASI_MEM, %g1
543	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
544	add	%g5, 8, %g5
545	ldxa	[%g4 + %g5]ASI_MEM, %g1
546	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
547	add	%g5, 8, %g5
548	ldxa	[%g4 + %g5]ASI_MEM, %g1
549	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
550	add	%g5, 8, %g5
551	ldxa	[%g4 + %g5]ASI_MEM, %g1
552	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
553	add	%g5, 8, %g5
554	ldxa	[%g4 + %g5]ASI_MEM, %g1
555	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
556	add	%g5, 8, %g5
557	ldxa	[%g4 + %g5]ASI_MEM, %g1
558	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
559
560	set	CPU_NRQ_SIZE, %g5		! %g5 = queue size
561	sub	%g5, 1, %g5			! %g5 = queu size mask
562
563	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
564	and	%g6, %g5, %g6			! size mask for warp around
565	cmp	%g6, %g3			! head == tail ??
566
567	bne,pn	%xcc, 2b			! still have more to process
568	nop
569
570	/*
571	 * head equals to tail now, we can update the queue head
572	 * and call sys_trap
573	 */
574	mov	CPU_NRQ_HD, %g4
575	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
576	membar	#Sync
577
578	/*
579	 * Call sys_trap. %g2 is TL(arg2), %g3 is head and tail
580	 * offset(arg3).
581	 * %g3 looks like following:
582	 *	+--------------------+--------------------+
583	 *	|   tail offset      |    head offset     |
584	 *	+--------------------+--------------------+
585	 *	63                 32 31                 0
586	 *
587	 * Run at PIL 14 unless we're already at PIL 15.
588	 */
589	sllx	%g3, 32, %g3			! %g3.h = tail offset
590	or	%g3, %g2, %g3			! %g3.l = head offset
591	rdpr	%tl, %g2			! %g2 = current tl
592
593	/*
594	 * Now check if the first error that sent us here was caused
595	 * in user's SPILL/FILL trap. If it was, we call sys_trap to
596	 * kill the user process. Several considerations:
597	 * - If multiple nonresumable errors happen, we only check the
598	 *   first one. Nonresumable errors cause system either panic
599	 *   or kill the user process. So the system has already
600	 *   panic'ed or killed user process after processing the first
601	 *   error. Therefore, no need to check if other error packet
602	 *   for this type of error.
603	 * - Errors happen in user's SPILL/FILL trap will bring us at
604	 *   TL = 2.
605	 * - We need to lower TL to 1 to get the trap type and tstate.
606	 *   We don't go back to TL = 2 so no need to save states.
607	 */
608	cmp	%g2, 2
609	bne,pt	%xcc, 3f			! if tl != 2
610	nop
611	/* Check to see if the trap pc is in a window spill/fill handling */
612	rdpr	%tpc, %g4
613	/* tpc should be in the trap table */
614	set	trap_table, %g5
615	cmp	%g4, %g5
616	blu,pt	%xcc, 3f
617	nop
618	set	etrap_table, %g5
619	cmp	%g4, %g5
620	bgeu,pt	%xcc, 3f
621	nop
622	/* Set tl to 1 in order to read tt[1] and tstate[1] */
623	wrpr	%g0, 1, %tl
624	rdpr	%tt, %g4			! %g4 = tt[1]
625	/* Check if tt[1] is a window trap */
626	and	%g4, WTRAP_TTMASK, %g4
627	cmp	%g4, WTRAP_TYPE
628	bne,pt	%xcc, 3f
629	nop
630	rdpr	%tstate, %g5			! %g5 = tstate[1]
631	btst	TSTATE_PRIV, %g5
632	bnz	%xcc, 3f			! Is it from user code?
633	nop
634	/*
635	 * Now we know the error happened in user's SPILL/FILL trap.
636	 * Turn on the user spill/fill flag in %g2
637	 */
638	mov	1, %g4
639	sllx	%g4, ERRH_U_SPILL_FILL_SHIFT, %g4
640	or	%g2, %g4, %g2			! turn on flag in %g2
641
6423:	sub	%g2, 1, %g2			! %g2.l = previous tl
643
644	set	process_nonresumable_error, %g1
645	rdpr	%pil, %g4
646	cmp	%g4, PIL_14
647	ba	sys_trap
648	  movl	%icc, PIL_14, %g4
649
650	/*
651	 * We are here because the C routine is not able to process
652	 * errors in time. So the first 8 bytes of ER in buf has not
653	 * been cleared. We call sys_trap to panic.
654	 * Run at PIL 14 unless we're already at PIL 15.
655	 */
6561:	set	nrq_overflow, %g1
657	rdpr	%pil, %g4
658	cmp	%g4, PIL_14
659	ba	sys_trap
660	  movl	%icc, PIL_14, %g4
661
6620:	retry
663
664	/*NOTREACHED*/
665	SET_SIZE(nonresumable_error)
666#endif /* lint */
667