xref: /titanic_50/usr/src/uts/sun4v/ml/mach_interrupt.s (revision 3eae19d9cf3390cf5b75e10c9c1945fd36ad856a)
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 2007 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#include <sys/mmu.h>
45#include <vm/hat_sfmmu.h>
46#define	INTR_REPORT_SIZE	64
47
48#ifdef TRAPTRACE
49#include <sys/traptrace.h>
50#endif /* TRAPTRACE */
51
52#if defined(lint)
53
54void
55cpu_mondo(void)
56{}
57
58#else	/* lint */
59
60
61/*
62 * (TT 0x7c, TL>0) CPU Mondo Queue Handler
63 *	Globals are the Interrupt Globals.
64 */
65	ENTRY_NP(cpu_mondo)
66	!
67	!	Register Usage:-
68	!	%g5	PC for fasttrap TL>0 handler
69	!	%g1	arg 1
70	!	%g2	arg 2
71	!	%g3	queue base VA
72	!	%g4 	queue size mask
73	!	%g6	head ptr
74	!	%g7	tail ptr
75	mov	CPU_MONDO_Q_HD, %g3
76	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
77	mov	CPU_MONDO_Q_TL, %g4
78	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
79	cmp	%g6, %g7
80	be,pn	%xcc, 3f		! head == tail
81	nop
82
83	CPU_ADDR(%g1,%g2)
84	add	%g1, CPU_MCPU, %g2
85	ldx	[%g2 + MCPU_CPU_Q_BASE], %g3	! %g3 = queue base PA
86	ldx	[%g2 + MCPU_CPU_Q_SIZE], %g4	! queue size
87	sub	%g4, 1, %g4		! %g4 = queue size mask
88
89	! Load interrupt receive data registers 1 and 2 to fetch
90	! the arguments for the fast trap handler.
91	!
92	! XXX - Since the data words in the interrupt report are not defined yet
93	! we assume that the consective words contain valid data and preserve
94	! sun4u's xcall mondo arguments.
95	! Register usage:
96	!	%g5	PC for fasttrap TL>0 handler
97	!	%g1	arg 1
98	!	%g2	arg 2
99
100	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get PC from q base + head
101	add	%g6, 0x8, %g6		! inc head
102	ldxa	[%g3 + %g6]ASI_MEM, %g1 ! read data word 1
103	add	%g6, 0x8, %g6		! inc head
104	ldxa	[%g3 + %g6]ASI_MEM, %g2	! read data word 2
105	add	%g6, (INTR_REPORT_SIZE - 16) , %g6 ! inc head to next record
106	and	%g6, %g4, %g6 		! and size mask for wrap around
107	mov	CPU_MONDO_Q_HD, %g3
108	stxa	%g6, [%g3]ASI_QUEUE	! store head pointer
109	membar	#Sync
110
111#ifdef TRAPTRACE
112	TRACE_PTR(%g4, %g6)
113	GET_TRACE_TICK(%g6)
114	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
115	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
116	rdpr	%tt, %g6
117	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
118	rdpr	%tpc, %g6
119	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
120	rdpr	%tstate, %g6
121	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
122	stna	%sp, [%g4 + TRAP_ENT_SP]%asi
123	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! pc of the TL>0 handler
124	stna	%g1, [%g4 + TRAP_ENT_F1]%asi	! arg1
125	stna	%g2, [%g4 + TRAP_ENT_F3]%asi	! arg2
126	mov	CPU_MONDO_Q_HD, %g6
127	ldxa	[%g6]ASI_QUEUE, %g6		! new head offset
128	stna	%g6, [%g4 + TRAP_ENT_F2]%asi
129	stna	%g7, [%g4 + TRAP_ENT_F4]%asi	! tail offset
130	TRACE_NEXT(%g4, %g6, %g3)
131#endif /* TRAPTRACE */
132
133	/*
134	 * For now catch invalid PC being passed via cpu_mondo queue
135	 */
136	set	KERNELBASE, %g4
137	cmp	%g5, %g4
138	bl,pn	%xcc, 2f		! branch if bad %pc
139	  nop
140
141
142	/*
143	 * If this platform supports shared contexts and we are jumping
144	 * to OBP code, then we need to invalidate both contexts to prevent OBP
145	 * from corrupting the shared context registers.
146	 *
147	 * If shared contexts are not supported then the next two instructions
148	 * will be patched with:
149	 *
150	 * jmp       %g5
151	 * nop
152	 *
153	 */
154	.global sfmmu_shctx_cpu_mondo_patch
155sfmmu_shctx_cpu_mondo_patch:
156	set	OFW_START_ADDR, %g4	! Check if this a call into OBP?
157	cmp	%g5, %g4
158	bl,pt %xcc, 1f
159	  nop
160	set	OFW_END_ADDR, %g4
161	cmp	%g5, %g4
162	bg,pn %xcc, 1f
163	  nop
164	mov	MMU_PCONTEXT, %g3
165	ldxa	[%g3]ASI_MMU_CTX, %g4
166	cmp	%g4, INVALID_CONTEXT	! Check if we are in kernel mode
167	ble,pn %xcc, 1f			! or the primary context is invalid
168	  nop
169	set	INVALID_CONTEXT, %g4	! Invalidate contexts - compatability
170	stxa    %g4, [%g3]ASI_MMU_CTX	! mode ensures shared contexts are also
171	mov     MMU_SCONTEXT, %g3	! invalidated.
172	stxa    %g4, [%g3]ASI_MMU_CTX
173	membar  #Sync
174	mov	%o0, %g3		! save output regs
175	mov	%o1, %g4
176	mov	%o5, %g6
177	clr	%o0			! Invalidate tsbs, set ntsb = 0
178	clr	%o1			! and HV_TSB_INFO_PA = 0
179	mov	MMU_TSB_CTXNON0, %o5
180	ta	FAST_TRAP		! set TSB info for user process
181	brnz,a,pn %o0, ptl1_panic
182	  mov	PTL1_BAD_HCALL, %g1
183	mov	%g3, %o0		! restore output regs
184	mov	%g4, %o1
185	mov	%g6, %o5
1861:
187	jmp	%g5			! jump to traphandler
188	nop
1892:
190	! invalid trap handler, discard it for now
191	set	cpu_mondo_inval, %g4
192	ldx	[%g4], %g5
193	inc	%g5
194	stx	%g5, [%g4]
1953:
196	retry
197	/* Never Reached */
198	SET_SIZE(cpu_mondo)
199
200#endif /* lint */
201
202#if defined(lint)
203
204void
205dev_mondo(void)
206{}
207
208#else	/* lint */
209
210
211/*
212 * (TT 0x7d, TL>0) Dev Mondo Queue Handler
213 *	Globals are the Interrupt Globals.
214 * We only process one interrupt at a time causing us to keep
215 * taking this trap till the queue is empty.
216 * We really should drain the whole queue for better performance
217 * but this will do for now.
218 */
219	ENTRY_NP(dev_mondo)
220	!
221	!	Register Usage:-
222	!	%g5	PC for fasttrap TL>0 handler
223	!	%g1	arg 1
224	!	%g2	arg 2
225	!	%g3	queue base PA
226	!	%g4 	queue size mask
227	!	%g6	head ptr
228	!	%g7	tail ptr
229	mov	DEV_MONDO_Q_HD, %g3
230	ldxa	[%g3]ASI_QUEUE, %g6	! %g6 = head ptr
231	mov	DEV_MONDO_Q_TL, %g4
232	ldxa	[%g4]ASI_QUEUE, %g7	! %g7 = tail ptr
233	cmp	%g6, %g7
234	be,pn	%xcc, 0f		! head == tail
235	nop
236
237	CPU_ADDR(%g1,%g2)
238	add	%g1, CPU_MCPU, %g2
239	ldx	[%g2 + MCPU_DEV_Q_BASE], %g3	! %g3 = queue base PA
240
241	! Register usage:
242	!	%g5 - inum
243	!	%g1 - cpu struct pointer used below in TRAPTRACE
244	!
245	ldxa	[%g3 + %g6]ASI_MEM, %g5	! get inum from q base + head
246
247	!
248	! We verify that inum is valid ( < MAXVNUM). If it is greater
249	! than MAXVNUM, we let setvecint_tl1 take care of it.
250	!
251	set	MAXIVNUM, %g4
252	cmp	%g5, %g4
253	bgeu,a,pn	%xcc, 1f
254	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
255
256	!
257	!	Copy 64-byte payload to the *iv_payload if it is not NULL
258	!
259	set	intr_vec_table, %g1		! %g1 = intr_vec_table
260	sll	%g5, CPTRSHIFT, %g7		! %g7 = offset to inum entry
261						!       in the intr_vec_table
262	add	%g1, %g7, %g7			! %g7 = &intr_vec_table[inum]
263	ldn	[%g7], %g1			! %g1 = ptr to intr_vec_t (iv)
264
265	!
266	! Verify the pointer to first intr_vec_t for a given inum and
267	! it should not be NULL. If this pointer is NULL, then it is a
268	! spurious interrupt. In this case, just call setvecint_tl1 and
269	! it will handle this spurious interrupt.
270	!
271	brz,a,pn	%g1, 1f			! if %g1 is NULL
272	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
273
274	ldx	[%g1 + IV_PAYLOAD_BUF], %g1	! %g1 = iv->iv_payload_buf
275	brz,a,pt	%g1, 1f			! if it is NULL
276	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size - delay slot
277
278	!
279	!	Now move 64 byte payload from mondo queue to buf
280	!
281	mov	%g6, %g7			! %g7 = head ptr
282	ldxa	[%g3 + %g7]ASI_MEM, %g4
283	stx	%g4, [%g1 + 0]			! byte 0 - 7
284	add	%g7, 8, %g7
285	ldxa	[%g3 + %g7]ASI_MEM, %g4
286	stx	%g4, [%g1 + 8]			! byte 8 - 15
287	add	%g7, 8, %g7
288	ldxa	[%g3 + %g7]ASI_MEM, %g4
289	stx	%g4, [%g1 + 16]			! byte 16 - 23
290	add	%g7, 8, %g7
291	ldxa	[%g3 + %g7]ASI_MEM, %g4
292	stx	%g4, [%g1 + 24]			! byte 24 - 31
293	add	%g7, 8, %g7
294	ldxa	[%g3 + %g7]ASI_MEM, %g4
295	stx	%g4, [%g1 + 32]			! byte 32 - 39
296	add	%g7, 8, %g7
297	ldxa	[%g3 + %g7]ASI_MEM, %g4
298	stx	%g4, [%g1 + 40]			! byte 40 - 47
299	add	%g7, 8, %g7
300	ldxa	[%g3 + %g7]ASI_MEM, %g4
301	stx	%g4, [%g1 + 48]			! byte 48 - 55
302	add	%g7, 8, %g7
303	ldxa	[%g3 + %g7]ASI_MEM, %g4
304	stx	%g4, [%g1 + 56]			! byte 56 - 63
305	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g4	! queue size
306
3071:	sub	%g4, 1, %g4		! %g4 = queue size mask
308	add	%g6, INTR_REPORT_SIZE , %g6 ! inc head to next record
309	and	%g6, %g4, %g6 		! and mask for wrap around
310	mov	DEV_MONDO_Q_HD, %g3
311	stxa	%g6, [%g3]ASI_QUEUE	! increment head offset
312	membar	#Sync
313
314#ifdef TRAPTRACE
315	TRACE_PTR(%g4, %g6)
316	GET_TRACE_TICK(%g6)
317	stxa	%g6, [%g4 + TRAP_ENT_TICK]%asi
318	TRACE_SAVE_TL_GL_REGS(%g4, %g6)
319	rdpr	%tt, %g6
320	stha	%g6, [%g4 + TRAP_ENT_TT]%asi
321	rdpr	%tpc, %g6
322	stna	%g6, [%g4 + TRAP_ENT_TPC]%asi
323	rdpr	%tstate, %g6
324	stxa	%g6, [%g4 + TRAP_ENT_TSTATE]%asi
325	! move head to sp
326	ldx	[%g2 + MCPU_DEV_Q_BASE], %g6
327	stna	%g6, [%g4 + TRAP_ENT_SP]%asi	! Device Queue Base PA
328	stna	%g5, [%g4 + TRAP_ENT_TR]%asi	! Inum
329	mov	DEV_MONDO_Q_HD, %g6
330	ldxa	[%g6]ASI_QUEUE, %g6		! New head offset
331	stna	%g6, [%g4 + TRAP_ENT_F1]%asi
332	ldx	[%g2 + MCPU_DEV_Q_SIZE], %g6
333	stna	%g6, [%g4 + TRAP_ENT_F2]%asi	! Q Size
334	stna	%g7, [%g4 + TRAP_ENT_F3]%asi	! tail offset
335	stna	%g0, [%g4 + TRAP_ENT_F4]%asi
336	TRACE_NEXT(%g4, %g6, %g3)
337#endif /* TRAPTRACE */
338
339	!
340	! setvecint_tl1 will do all the work, and finish with a retry
341	!
342	ba,pt	%xcc, setvecint_tl1
343	mov	%g5, %g1		! setvecint_tl1 expects inum in %g1
344
3450:	retry
346
347	/* Never Reached */
348	SET_SIZE(dev_mondo)
349#endif /* lint */
350
351#if defined(lint)
352uint64_t cpu_mondo_inval;
353#else /* lint */
354	.seg	".data"
355	.global	cpu_mondo_inval
356	.align	8
357cpu_mondo_inval:
358	.skip	8
359
360	.seg	".text"
361#endif	/* lint */
362
363
364#if defined(lint)
365
366void
367resumable_error(void)
368{}
369
370#else	/* lint */
371
372/*
373 * (TT 0x7e, TL>0) Resumeable Error Queue Handler
374 *	We keep a shadow copy of the queue in kernel buf.
375 *	Read the resumable queue head and tail offset
376 *	If there are entries on the queue, move them to
377 *	the kernel buf, which is next to the resumable
378 *	queue in the memory. Call C routine to process.
379 */
380	ENTRY_NP(resumable_error)
381	mov	CPU_RQ_HD, %g4
382	ldxa	[%g4]ASI_QUEUE, %g2		! %g2 = Q head offset
383	mov	CPU_RQ_TL, %g4
384	ldxa	[%g4]ASI_QUEUE, %g3		! %g3 = Q tail offset
385	mov	%g2, %g6			! save head in %g2
386
387	cmp	%g6, %g3
388	be,pn	%xcc, 0f			! head == tail
389	nop
390
391	CPU_ADDR(%g1, %g4)			! %g1 = cpu struct addr
392
3932:	set	CPU_RQ_BASE_OFF, %g4
394	ldx	[%g1 + %g4], %g4		! %g4 = queue base PA
395	add	%g6, %g4, %g4			! %g4 = PA of ER in Q
396	set	CPU_RQ_SIZE, %g7
397	add	%g4, %g7, %g7			! %g7=PA of ER in kernel buf
398
399	ldxa	[%g7]ASI_MEM, %g5		! %g5=first 8 byte of ER buf
400	cmp	0, %g5
401	bne,pn	%xcc, 1f			! first 8 byte is not 0
402	nop
403
404	/* Now we can move 64 bytes from queue to buf */
405	set	0, %g5
406	ldxa	[%g4 + %g5]ASI_MEM, %g1
407	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 0 - 7
408	add	%g5, 8, %g5
409	ldxa	[%g4 + %g5]ASI_MEM, %g1
410	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 8 - 15
411	add	%g5, 8, %g5
412	ldxa	[%g4 + %g5]ASI_MEM, %g1
413	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 16 - 23
414	add	%g5, 8, %g5
415	ldxa	[%g4 + %g5]ASI_MEM, %g1
416	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 24 - 31
417	add	%g5, 8, %g5
418	ldxa	[%g4 + %g5]ASI_MEM, %g1
419	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 32 - 39
420	add	%g5, 8, %g5
421	ldxa	[%g4 + %g5]ASI_MEM, %g1
422	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 40 - 47
423	add	%g5, 8, %g5
424	ldxa	[%g4 + %g5]ASI_MEM, %g1
425	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 48 - 55
426	add	%g5, 8, %g5
427	ldxa	[%g4 + %g5]ASI_MEM, %g1
428	stxa	%g1, [%g7 + %g5]ASI_MEM		! byte 56 - 63
429
430	set	CPU_RQ_SIZE, %g5		! %g5 = queue size
431	sub	%g5, 1, %g5			! %g5 = queu size mask
432
433	add	%g6, Q_ENTRY_SIZE, %g6		! increment q head to next
434	and	%g6, %g5, %g6			! size mask for warp around
435	cmp	%g6, %g3			! head == tail ??
436
437	bne,pn	%xcc, 2b			! still have more to process
438	nop
439
440	/*
441	 * head equals to tail now, we can update the queue head
442	 * and call sys_trap
443	 */
444	mov	CPU_RQ_HD, %g4
445	stxa	%g6, [%g4]ASI_QUEUE		! update head offset
446
447	/*
448	 * Call sys_trap at PIL 14 unless we're already at PIL 15. %g2.l is
449	 * head offset(arg2) and %g3 is tail
450	 * offset(arg3).
451	 */
452	set	process_resumable_error, %g1
453	rdpr	%pil, %g4
454	cmp	%g4, PIL_14
455	ba	sys_trap
456	  movl	%icc, PIL_14, %g4
457
458	/*
459	 * We are here because the C routine is not able to process
460	 * errors in time. So the first 8 bytes of ER in buf has not
461	 * been cleared. We update head to tail and call sys_trap to
462	 * print out an error message
463	 */
464
4651:	mov	CPU_RQ_HD, %g4
466	stxa	%g3, [%g4]ASI_QUEUE		! set head equal to tail
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
577	/*
578	 * Call sys_trap. %g2 is TL(arg2), %g3 is head and tail
579	 * offset(arg3).
580	 * %g3 looks like following:
581	 *	+--------------------+--------------------+
582	 *	|   tail offset      |    head offset     |
583	 *	+--------------------+--------------------+
584	 *	63                 32 31                 0
585	 *
586	 * Run at PIL 14 unless we're already at PIL 15.
587	 */
588	sllx	%g3, 32, %g3			! %g3.h = tail offset
589	or	%g3, %g2, %g3			! %g3.l = head offset
590	rdpr	%tl, %g2			! %g2 = current tl
591
592	/*
593	 * Now check if the first error that sent us here was caused
594	 * in user's SPILL/FILL trap. If it was, we call sys_trap to
595	 * kill the user process. Several considerations:
596	 * - If multiple nonresumable errors happen, we only check the
597	 *   first one. Nonresumable errors cause system either panic
598	 *   or kill the user process. So the system has already
599	 *   panic'ed or killed user process after processing the first
600	 *   error. Therefore, no need to check if other error packet
601	 *   for this type of error.
602	 * - Errors happen in user's SPILL/FILL trap will bring us at
603	 *   TL = 2.
604	 * - We need to lower TL to 1 to get the trap type and tstate.
605	 *   We don't go back to TL = 2 so no need to save states.
606	 */
607	cmp	%g2, 2
608	bne,pt	%xcc, 3f			! if tl != 2
609	nop
610	/* Check to see if the trap pc is in a window spill/fill handling */
611	rdpr	%tpc, %g4
612	/* tpc should be in the trap table */
613	set	trap_table, %g5
614	cmp	%g4, %g5
615	blu,pt	%xcc, 3f
616	nop
617	set	etrap_table, %g5
618	cmp	%g4, %g5
619	bgeu,pt	%xcc, 3f
620	nop
621	/* Set tl to 1 in order to read tt[1] and tstate[1] */
622	wrpr	%g0, 1, %tl
623	rdpr	%tt, %g4			! %g4 = tt[1]
624	/* Check if tt[1] is a window trap */
625	and	%g4, WTRAP_TTMASK, %g4
626	cmp	%g4, WTRAP_TYPE
627	bne,pt	%xcc, 3f
628	nop
629	rdpr	%tstate, %g5			! %g5 = tstate[1]
630	btst	TSTATE_PRIV, %g5
631	bnz	%xcc, 3f			! Is it from user code?
632	nop
633	/*
634	 * Now we know the error happened in user's SPILL/FILL trap.
635	 * Turn on the user spill/fill flag in %g2
636	 */
637	mov	1, %g4
638	sllx	%g4, ERRH_U_SPILL_FILL_SHIFT, %g4
639	or	%g2, %g4, %g2			! turn on flag in %g2
640
6413:	sub	%g2, 1, %g2			! %g2.l = previous tl
642
643	set	process_nonresumable_error, %g1
644	rdpr	%pil, %g4
645	cmp	%g4, PIL_14
646	ba	sys_trap
647	  movl	%icc, PIL_14, %g4
648
649	/*
650	 * We are here because the C routine is not able to process
651	 * errors in time. So the first 8 bytes of ER in buf has not
652	 * been cleared. We call sys_trap to panic.
653	 * Run at PIL 14 unless we're already at PIL 15.
654	 */
6551:	set	nrq_overflow, %g1
656	rdpr	%pil, %g4
657	cmp	%g4, PIL_14
658	ba	sys_trap
659	  movl	%icc, PIL_14, %g4
660
6610:	retry
662
663	/*NOTREACHED*/
664	SET_SIZE(nonresumable_error)
665#endif /* lint */
666