Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / diag / assembly / include / interrupt0x60_handler.s.pal
CommitLineData
86530b38
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: interrupt0x60_handler.s.pal
5* Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
6* 4150 Network Circle, Santa Clara, California 95054, U.S.A.
7*
8* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9*
10* This program is free software; you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by
12* the Free Software Foundation; version 2 of the License.
13*
14* This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details.
18*
19* You should have received a copy of the GNU General Public License
20* along with this program; if not, write to the Free Software
21* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22*
23* For the avoidance of doubt, and except that if any non-GPL license
24* choice is available it will apply instead, Sun elects to use only
25* the General Public License version 2 (GPLv2) at this time for any
26* software where a choice of GPL license versions is made
27* available with the language indicating that GPLv2 or any later version
28* may be used, or where a choice of which version of the GPL is applied is
29* otherwise unspecified.
30*
31* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
32* CA 95054 USA or visit www.sun.com if you need additional information or
33* have any questions.
34*
35*
36* ========== Copyright Header End ============================================
37*/
38start_perl
39# $Id: interrupt0x60_handler.s.pal,v 1.14 2006/12/01 19:20:42 granvold Exp $
40print "/* \$Id\$ */\n";
41
42# Hardware constraints:
43$hw_num_ivs = 64; $hw_max_ivn = $hw_num_ivs - 1;
44$hw_num_threads = 64; $hw_max_thread_num = $hw_num_threads - 1;
45
46# interrupt0x60 constraints:
47$max_cc_ivns = 48; $max_cc_ivns_m1 = $max_cc_ivns - 1;
48$max_niu_ivns = 16; $max_niu_ivns_m1 = $max_niu_ivns - 1;
49$max_msi_idx = 8; $max_msi_idx_m1 = $max_msi_idx - 1;
50
51start_text(>)
52/* Shared trap handler for interrupts (TT=0x60) */
53
54/*>>>>>> ONLY EDIT THE .pal VERSION OF THIS FILE <<<<<<<<*/
55
56/*
57 * This is tightly linked with interrupt0x60_defines.h and
58 * interrupt0x60_sys_init.s
59 *
60 * There are several different consumers of interrupt information:
61 * 1. random test generators which stimulate interrupts
62 * 2. boot code that initializes interrupt-related registers
63 * 3. the shared interrupt trap handler
64 */
65
66#ifdef USE_BOBO
67#include "bobo_defines.h"
68#endif /* USE_BOBO */
69
70SECTION .HTRAPS
71.text
72.global intr0x60_handler
73
74intr0x60_handler:
75 mov %g7, %o7 ! Restore %o7
76 ldxa [%g0] ASI_INTR_ID, %g1 ! Get the thread number
77
78 ldxa [%g0] ASI_INTR_R, %g2 ! Get the interrupt vector number
79
80 setx intr0x60_ivn_to_ig, %g4, %g3
81 ldub [%g3+%g2], %g4
82
83 cmp %g4, INTR0x60_IG_CC
84 be intr0x60_handle_cc
85 nop
86
87#ifdef INTR0x60_NIU_TX_IV_0
88 cmp %g4, INTR0x60_IG_NIU_TX
89 be intr0x60_handle_niu_tx
90 nop
91#endif /* INTR0x60_NIU_TX_IV_0 */
92
93#ifdef INTR0x60_NIU_RX_IV_0
94 cmp %g4, INTR0x60_IG_NIU_RX
95 be intr0x60_handle_niu_rx
96 nop
97#endif /* INTR0x60_NIU_RX_IV_0 */
98
99#ifdef INTR0x60_MONDO_IV
100 cmp %g4, INTR0x60_IG_PIU
101 be intr0x60_handle_piu
102 nop
103#endif /* INTR0x60_MONDO_IV */
104
105#if (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV)
106 cmp %g4, INTR0x60_IG_SSI_ERR
107 be intr0x60_handle_ssi_err
108 nop
109#endif /* (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV) */
110
111#if (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV)
112 cmp %g4, INTR0x60_IG_SSI_INT
113 be intr0x60_handle_ssi_int
114 nop
115#endif /* (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV) */
116
117/* If we get here, we got an unexpected vector number */
118intr0x60_bad_ivn:
119 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_bad_ivn)) -> printf("ERROR: Bad interrupt vector number",*,1)
120 EXIT_BAD
121
122
123/************************************************************************/
124/* Handle cross-call interrupts */
125
126intr0x60_handle_cc:
127 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_cc)) -> printf("INFO: Cross-call interrupt received",*,1)
128#ifndef INTR0x60_CC_DEST_ALL
129 /* Make sure that this thread is allowed to receive cross-calls */
130 setx intr0x60_handle_cc_thread_table, %g5, %g4
131#ifdef PORTABLE_CORE
132 and %g1, 0x7, %g5
133 ldub [%g4+%g5], %g4
134#else
135 ldub [%g4+%g1], %g4
136#endif
137 brz %g4, intr0x60_handle_cc_bad_thread
138 nop
139#endif /* INTR0x60_CC_DEST_ALL */
140
141 /* Include any extra cross-call handler from the user */
142 /* The code can assume that %g1 is the thread and %g2 is the vector */
143#ifdef INTR0x60_CC_EXTRA_HANDLER
144intr0x60_handle_cc_extra_handler:
145INTR0x60_CC_EXTRA_HANDLER
146#endif /* INTR0x60_CC_EXTRA_HANDLER */
147
148intr0x60_handle_cc_retry:
149 /* Retry the instruction that was trapped */
150 retry
151
152#ifndef INTR0x60_CC_DEST_ALL
153intr0x60_handle_cc_bad_thread:
154 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_cc_bad_thread)) -> printf("ERROR: Cross-call received on unexpected thread",*,1)
155 EXIT_BAD
156
157.data
158intr0x60_handle_cc_thread_table:
159>for ($thread = 0; $thread < $hw_num_threads; $thread++) {
160#if defined(INTR0x60_CC_DEST_${thread})
161 .byte 1
162#else
163 .byte 0
164#endif
165>}
166
167.text
168#endif /* INTR0x60_CC_DEST_ALL */
169
170
171#ifdef INTR0x60_NIU_TX_IV_0
172/************************************************************************/
173/* Handle NIU TX interrupts */
174
175intr0x60_handle_niu_tx:
176 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_tx)) -> printf("INFO: NIU TX interrupt received",*,1)
177 /* Make sure that this thread is the right one for this NIU interrupt */
178>for ($ivn = 0; $ivn < $max_niu_ivns; $ivn++) {
179#ifdef INTR0x60_NIU_TX_IV_${ivn}
180intr0x60_handle_niu_tx_check_thread_${ivn}:
181 cmp %g2, INTR0x60_NIU_TX_IV_${ivn}
182 bnz 1f
183#ifdef PORTABLE_CORE
184 and %g1, 0x7, %g7
185 cmp %g7, INTR0x60_NIU_TX_THREAD_${ivn}
186#else
187 cmp %g1, INTR0x60_NIU_TX_THREAD_${ivn}
188#endif
189 bnz intr0x60_handle_niu_tx_bad_thread
190 best_set_reg(INTR0x60_NIU_TX_DMA_${ivn}, %g7, %g3)
191 ba intr0x60_handle_niu_tx_good_thread
192 nop
1931:
194#endif /* INTR0x60_NIU_TX_IV_${ivn} */
195
196>}
197
198 /* If we get here, we have an unknown vector */
199intr0x60_handle_niu_tx_bad_vector:
200 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_tx_bad_vector)) -> printf("interrupt0x60_handler.s ERROR: intr0x60_iv_to_ig said this is an NIU TX interrupt, but it is not defined in INTR0x60_NIU_TX_IV_x",*,1)
201 EXIT_BAD
202
203 /* If we get here, we know we have the right thread for this vector */
204intr0x60_handle_niu_tx_good_thread:
205 /* Clear the source of the interrupt */
206 ! Re-enable the interrupt in the transmit DMA channel
207 best_set_reg(TX_CS, %g7, %g4) ! TX_CS
208 best_set_reg(TDMC_STEP, %g7, %g5)
209 mulx %g5, %g3, %g5 ! %g3 is the DMA TX channel
210 add %g4, %g5, %g4
211 ldxa [%g4]ASI_PRIMARY_LITTLE, %g0 ! Reset MK
212
213 ! Re-enable the interrupt in the NIU
214 best_set_reg(LDGIMGN, %g7, %g4) ! LDGIMGN
215 best_set_reg(LDGIMGN_STEP, %g7, %g5)
216 mulx %g5, %g2, %g5
217 add %g4, %g5, %g4
218 best_set_reg(0x80000001, %g7, %g5)
219 stxa %g5, [%g4]ASI_PRIMARY_LITTLE
220 nop
221
222 /* Include any extra NIU handler from the user */
223 /* The code can assume that %g1 is the thread, %g2 is the vector,
224 * and %g3 is the TX DMA channel */
225#ifdef INTR0x60_NIU_TX_EXTRA_HANDLER
226intr0x60_handle_niu_tx_extra_handler:
227INTR0x60_NIU_TX_EXTRA_HANDLER
228#endif /* INTR0x60_NIU_TX_EXTRA_HANDLER */
229
230intr0x60_handle_niu_tx_retry:
231 /* Retry the instruction that was trapped */
232 retry
233
234intr0x60_handle_niu_tx_bad_thread:
235 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_tx_bad_thread)) -> printf("ERROR: NIU TX interrupt received on unexpected thread",*,1)
236 EXIT_BAD
237#endif /* INTR0x60_NIU_TX_IV_0 */
238
239
240#ifdef INTR0x60_NIU_RX_IV_0
241/************************************************************************/
242/* Handle NIU RX interrupts */
243
244intr0x60_handle_niu_rx:
245 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx)) -> printf("INFO: NIU RX interrupt received",*,1)
246 /* Make sure that this thread is the right one for this NIU interrupt */
247>for ($ivn = 0; $ivn < $max_niu_ivns; $ivn++) {
248#ifdef INTR0x60_NIU_RX_IV_${ivn}
249intr0x60_handle_niu_rx_check_thread_${ivn}:
250 cmp %g2, INTR0x60_NIU_RX_IV_${ivn}
251 bnz 1f
252#ifdef PORTABLE_CORE
253 and %g1, 0x7, %g7
254 cmp %g7, INTR0x60_NIU_RX_THREAD_${ivn}
255#else
256 cmp %g1, INTR0x60_NIU_RX_THREAD_${ivn}
257#endif
258 bnz intr0x60_handle_niu_rx_bad_thread
259 best_set_reg(INTR0x60_NIU_RX_DMA_${ivn}, %g7, %g3)
260 ba intr0x60_handle_niu_rx_good_thread
261 nop
2621:
263#endif /* INTR0x60_NIU_RX_IV_${ivn} */
264
265>}
266
267 /* If we get here, we have an unknown vector */
268intr0x60_handle_niu_rx_bad_vector:
269 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_bad_vector)) -> printf("interrupt0x60_handler.s ERROR: intr0x60_iv_to_ig said this is an NIU RX interrupt, but it is not defined in INTR0x60_NIU_RX_IV_x",*,1)
270 EXIT_BAD
271
272 /* If we get here, we know we have the right thread for this vector */
273intr0x60_handle_niu_rx_good_thread:
274 /* Clear the source of the interrupt */
275 best_set_reg(RX_DMA_CTL_STAT, %g7, %g4)
276 mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
277 add %g4, %g7, %g4 ! Addr of RX DMA Ctl/stat for this channel
278intr0x60_handle_niu_rx_get_rx_dma_ctl_stat:
279 ldxa [%g4]ASI_PRIMARY_LITTLE, %g5 ! Get status
280 mov 0x7, %g7
281 sllx %g7, 32, %g7 ! Mask for clear-on-reset error bits
282 and %g5, %g7, %g7
283 brz %g7, intr0x60_handle_niu_rx_nonfatal
284 nop
285
286intr0x60_handle_niu_rx_fatal_error:
287#ifdef INTR0x60_NIU_RX_FATAL_HANDLER
288INTR0x60_NIU_RX_FATAL_HANDLER
289#else /* INTR0x60_NIU_RX_FATAL_HANDLER */
290#ifdef INTR0x60_NIU_RX_CLEAR_FATAL_FOR_TSOTOOL
291/* This code does what is needed for tsotool NIU RX fatal error interrupts */
292 best_set_reg(RXDMA_CFIG1, %g7, %g4)
293 mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
294 add %g4, %g7, %g4
295intr0x60_handle_niu_rx_fatal_error_disable_dma_channel:
296 stxa %g0, [%g4]ASI_PRIMARY_LITTLE
297 membar #Sync
298 mov 1, %g7
299 sllx %g7, 30, %g7 ! RST bit in RXDMA_CFIG1
300intr0x60_handle_niu_rx_fatal_error_reset_dma_channel:
301 stxa %g7, [%g4]ASI_PRIMARY_LITTLE
302 srlx %g7, 1, %g7 ! QST bit in RXDMA_CFIG1
303 mov 10, %g6 ! Timeout
304intr0x60_handle_niu_rx_fatal_error_wait_for_dma_channel:
305 ldxa [%g4]ASI_PRIMARY_LITTLE, %g5 ! Get the status
306 cmp %g5, %g7
307 beq intr0x60_handle_niu_rx_fatal_error_enable_intr_for_dma_channel
308 dec %g6
309 brnz %g6, intr0x60_handle_niu_rx_fatal_error_wait_for_dma_channel
310 nop
311intr0x60_handle_niu_rx_fatal_error_timeout_wait_for_dma_channel:
312 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_fatal_error_timeout_wait_for_dma_channel)) -> printf("ERROR: NIU RX interrupt received for fatal error and DMA channel reset never completed",*,1)
313 EXIT_BAD
314intr0x60_handle_niu_rx_fatal_error_enable_intr_for_dma_channel:
315 best_set_reg(RX_DMA_ENT_MSK, %g7, %g5)
316 mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
317 add %g5, %g7, %g5
318 stxa %g0, [%g5]ASI_PRIMARY_LITTLE
319 ba intr0x60_handle_niu_rx_reenable_ldg
320 membar #Sync
321#else /* INTR0x60_NIU_RX_CLEAR_FATAL_FOR_TSOTOOL */
322 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_fatal_error)) -> printf("ERROR: NIU RX interrupt received for fatal error",*,1)
323 EXIT_BAD
324#endif /* INTR0x60_NIU_RX_CLEAR_FATAL_FOR_TSOTOOL */
325#endif /* INTR0x60_NIU_RX_FATAL_HANDLER */
326
327intr0x60_handle_niu_rx_nonfatal:
328 best_set_reg(0xffffffffffff0000, %g7, %g6)
329 and %g5, %g6, %g5 ! Only preserve error bits, for RW1C
330 best_set_reg(RCR_STAT_A, %g7, %g6)
331 mulx %g3, RX_DMA_CTL_STAT_STEP, %g7 ! %g3 is the DMA RX channel
332 add %g6, %g7, %g6
333intr0x60_handle_niu_rx_get_rcr_stat_a:
334 ldxa [%g6]ASI_PRIMARY_LITTLE, %g6 ! Get the number of pkts received
335 or %g6, %g5, %g6
336 best_set_reg(THRES_INT, %g7, %g5) ! Bit to enable mailbox (MEX in PRM)
337 or %g6, %g5, %g6
338intr0x60_handle_niu_rx_reset_rx_dma_ctl_stat:
339 stxa %g6, [%g4]ASI_PRIMARY_LITTLE ! RW1C on RCRTHRES, RCRTO, etc., plus
340 ! set MEX, decrement QLEN by pkt read
341intr0x60_handle_niu_rx_reenable_ldg:
342 ! Re-enable the interrupt in the NIU LDG
343 best_set_reg(LDGIMGN, %g7, %g4) ! LDGIMGN
344 best_set_reg(LDGIMGN_STEP, %g7, %g5)
345 mulx %g5, %g2, %g5
346 add %g4, %g5, %g4
347 best_set_reg(0x80000001, %g7, %g5)
348 stxa %g5, [%g4]ASI_PRIMARY_LITTLE ! Arm LDGI, set timer to 1
349 nop
350
351 /* Include any extra NIU handler from the user */
352 /* The code can assume that %g1 is the thread, %g2 is the vector,
353 * and %g3 is the RX DMA channel */
354#ifdef INTR0x60_NIU_RX_EXTRA_HANDLER
355intr0x60_handle_niu_rx_extra_handler:
356INTR0x60_NIU_RX_EXTRA_HANDLER
357#endif /* INTR0x60_NIU_RX_EXTRA_HANDLER */
358
359intr0x60_handle_niu_rx_retry:
360 /* Retry the instruction that was trapped */
361 retry
362
363intr0x60_handle_niu_rx_bad_thread:
364 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_niu_rx_bad_thread)) -> printf("ERROR: NIU RX interrupt received on unexpected thread",*,1)
365 EXIT_BAD
366#endif /* INTR0x60_NIU_RX_IV_0 */
367
368
369#ifdef INTR0x60_MONDO_IV
370/************************************************************************/
371/* Handle PIU interrupts */
372
373intr0x60_handle_piu:
374 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu)) -> printf("INFO: PIU interrupt received",*,1)
375#ifndef INTR0x60_DO_NOT_READ_ADATA1
376 /* To reach coverage goals, do a dummy read from ADATA1 */
377 best_set_reg(MONDO_INT_ADATA1, %g4, %g3)
378 ldx [%g3], %g3
379#endif /* INTR0x60_DO_NOT_READ_ADATA1 */
380 best_set_reg(MONDO_INT_ADATA0, %g4, %g3)
381 ldx [%g3], %g3
382 and %g3, 0x3f, %g3 /* WIP: Mask to get INO */
383#if INTR0x60_MONDO_20_V
384 cmp %g3, 20
385 be intr0x60_handle_piu_inta
386 nop
387#endif /* INTR0x60_MONDO_20_V */
388#if INTR0x60_MONDO_21_V
389 cmp %g3, 21
390 be intr0x60_handle_piu_intb
391 nop
392#endif /* INTR0x60_MONDO_21_V */
393#if INTR0x60_MONDO_22_V
394 cmp %g3, 22
395 be intr0x60_handle_piu_intc
396 nop
397#endif /* INTR0x60_MONDO_22_V */
398#if INTR0x60_MONDO_23_V
399 cmp %g3, 23
400 be intr0x60_handle_piu_intd
401 nop
402#endif /* INTR0x60_MONDO_23_V */
403>for $idx (0 .. $max_msi_idx_m1) {
404#ifdef INTR0x60_MSI_${idx}_NUM
405intr0x60_handle_piu_check_msi_${idx}:
406 cmp %g3, mpeval(INTR0x60_MSI_${idx}_EQN+24)
407 be intr0x60_handle_piu_msi_${idx}
408 mov ${idx}, %g4
409#endif /* INTR0x60_MSI_${idx}_NUM */
410>}
411#ifdef INTR0x60_PM_PME_EQN
412intr0x60_handle_piu_check_pm_pme:
413 cmp %g3, mpeval(INTR0x60_PM_PME_EQN+24)
414 be intr0x60_handle_piu_pm_pme
415 nop
416#endif /* INTR0x60_PM_PME_EQN */
417#ifdef INTR0x60_PME_TO_ACK_EQN
418intr0x60_handle_piu_check_pme_to_ack:
419 cmp %g3, mpeval(INTR0x60_PME_TO_ACK_EQN+24)
420 be intr0x60_handle_piu_pme_to_ack
421 nop
422#endif /* INTR0x60_PME_TO_ACK_EQN */
423
424 /* If we get here, we got an unexpected INO */
425intr0x60_bad_mondo_INO:
426 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_bad_mondo_INO)) -> printf("ERROR: Bad mondo INO",*,1)
427 EXIT_BAD
428
429>@intx_letters = ("A", "B", "C", "D");
430>for ($intx = 0; $intx < 4; $intx++) {
431> $ino = 20 + $intx;
432> $uc = $intx_letters[$intx];
433> $lc = lc $uc;
434#if INTR0x60_MONDO_${ino}_V
435 /************ Handle INT${uc} ***********/
436intr0x60_handle_piu_int${lc}:
437 /* Check whether this thread matches this INO */
438#ifdef PORTABLE_CORE
439 and %g1, 0x7, %g7
440 cmp %g7/*tid*/, INTR0x60_MONDO_${ino}_THREAD
441#else
442 cmp %g1/*tid*/, INTR0x60_MONDO_${ino}_THREAD
443#endif
444 bne intr0x60_handle_piu_bad_thread
445 nop
446 /* Clear the interrupt */
447intr0x60_handle_piu_int${lc}_deassert:
448#ifdef FC_NO_PEU_VERA
449#ifdef USE_BOBO
450 ! Offset accesses by PCIE_MEM64_OFFSET since
451 ! BAR is set that way. Physical addresses generated via TSB
452 ! have this offset so mimic that when accessing directly, as here.
453 best_set_reg(mpeval(N2_PCIE_BASE_ADDR
454 + MEM64_OFFSET_BASE_REG_DATA
455 + PCIE_MEM64_OFFSET
456 + BOBO_INTR_VECT_STATUS_OFFSET), %g7, %g4)
457 ! Interrupt type
458 mov eval(1 << $intx), %g5
459#else /* USE_BOBO */
460 ! Offset accesses by PCIE_MEM64_OFFSET since
461 ! BAR is set that way. Physical addresses generated via TSB
462 ! have this offset so mimic that when accessing directly, as here.
463 best_set_reg(mpeval(N2_PCIE_BASE_ADDR
464 + MEM64_OFFSET_BASE_REG_DATA
465 + PCIE_MEM64_OFFSET
466 + (INTR0x60_MONDO_${ino}_DMAEPT_ENGINE << 8)
467 + DMAEPT_INTERRUPT_ACK), %g7, %g4)
468 ! Interrupt type
469 best_set_reg(DMAEPT_INTERRUPT_ACK_INT${uc}, %g7, %g5)
470#endif /* USE_BOBO */
471 stwa %g5, [%g4] ASI_NL
472#else /* FC_NO_PEU_VERA */
473 ! \$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu_int${lc}_deassert)) -> EnablePCIeIgCmd ("INT${uc}", 0, 0, "DEASSERT", 1, *, 1 )
474#endif /* FC_NO_PEU_VERA */
475
476 /* Loop on the INTX Status Register until the deassert message
477 * has arrived and been processed. */
478 best_set_reg(PCI_E_INTX_STATUS_ADDR, %g5, %g4)
479 best_set_reg(INTR0x60_INTX_DEASSERT_TIMEOUT, %g5, %g6)
480intr0x60_handle_piu_int${lc}_deassert_loop:
481 brz %g6, intr0x60_handle_piu_int${lc}_deassert_timeout
482 dec %g6
483 ldx [%g4], %g3
484>$bit = 1 << (3-$intx);
485 and %g3, ${bit}, %g3 ! ${bit} == bit for INT${uc}
486 brnz %g3, intr0x60_handle_piu_int${lc}_deassert_loop
487 set 1, %g3
488intr0x60_handle_piu_int${lc}_clear:
489 best_set_reg(PCI_E_INT_${uc}_CLEAR_ADDR, %g5, %g4)
490 stx %g3, [%g4]
491 best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR+${intx}*PCI_E_INT_CLEAR_STEP), %g5, %g4)
492 stx %g0, [%g4]
493 best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
494 stx %g0, [%g4]
495
496 /* Include any extra INT${uc} handler from the user */
497 /* The code can assume that %g1 is the thread and %g2 is the vector */
498#ifdef INTR0x60_INT${uc}_EXTRA_HANDLER
499intr0x60_handle_int${lc}_extra_handler:
500INTR0x60_INT${uc}_EXTRA_HANDLER
501#endif /* INTR0x60_INT${uc}_EXTRA_HANDLER */
502
503intr0x60_handle_piu_int${lc}_retry:
504 /* Retry the instruction that was trapped */
505 retry
506#endif /* INTR0x60_MONDO_${ino}_V */
507
508 /* If we get here, the interrupt status bit didn't deassert */
509intr0x60_handle_piu_int${lc}_deassert_timeout:
510 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu_int${lc}_deassert_timeout)) -> printf("ERROR: INT${uc} status bit did not deassert within INTR0x60_INTX_DEASSERT_TIMEOUT iterations",*,1)
511 EXIT_BAD
512
513
514>}
515
516
517
518>for $idx (0 .. $max_msi_idx_m1) {
519#ifdef INTR0x60_MSI_${idx}_NUM
520 /************ Handle MSI ${idx} ***********/
521intr0x60_handle_piu_msi_${idx}:
522!WIP: /* Check whether this thread matches this INO */
523!WIP: cmp %g1/*tid*/, INTR0x60_MONDO_XXX_THREAD
524!WIP: bne intr0x60_handle_piu_bad_thread
525!WIP: nop
526 /* Clear the interrupt */
527 /* MSI Clear reg. */
528intr0x60_handle_piu_msi_${idx}_clear_eqwr:
529 set 1, %g4
530 sllx %g4, 62, %g4 ! EQWR_N is bit 62
531 best_set_reg(mpeval(PCI_E_MSI_CLEAR_ADDR
532 +PCI_E_MSI_CLEAR_STEP*INTR0x60_MSI_${idx}_NUM),
533 %g7, %g5)
534 stx %g4, [%g5] ! clear EQWR in MSI map reg.
535 membar #Sync
536
537intr0x60_handle_piu_msi_${idx}_disable_eq:
538 set 1, %g4
539 sllx %g4, 44, %g4 ! DIS is bit 44
540 best_set_reg(mpeval(PCI_E_EV_QUE_CTL_CLEAR_ADDR
541 +PCI_E_EV_QUE_CTL_CLEAR_STEP*INTR0x60_MSI_${idx}_EQN),
542 %g7, %g5)
543 stx %g4, [%g5]
544
545 ! Set Event Queue Head = Event Queue Tail
546intr0x60_handle_piu_msi_${idx}_reset_eq_head:
547 best_set_reg(mpeval(PCI_E_EV_QUE_TAIL_ADDR
548 +PCI_E_EV_QUE_TAIL_STEP*INTR0x60_MSI_${idx}_EQN),
549 %g7, %g5)
550 ldx [%g5], %g6
551 best_set_reg(mpeval(PCI_E_EV_QUE_HEAD_ADDR
552 +PCI_E_EV_QUE_HEAD_STEP*INTR0x60_MSI_${idx}_EQN),
553 %g7, %g5)
554 stx %g6, [%g5]
555
556intr0x60_handle_piu_msi_${idx}_clear_int:
557 best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR
558 +(4+INTR0x60_MSI_${idx}_EQN)*PCI_E_INT_CLEAR_STEP),
559 %g5, %g4)
560 stx %g0, [%g4]
561
562 /* Include any extra MSI handler from the user that needs to be
563 * executed while the mondo busy flag is still asserted. */
564 /* The code can assume that %g1 is the thread,
565 * %g2 is the vector, and
566 * %g3 is the INO */
567#ifdef INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY
568intr0x60_handle_msi_${idx}_extra_handler_while_busy:
569INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY
570#endif /* INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY */
571
572intr0x60_handle_piu_msi_${idx}_clear_mondo_busy:
573 best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
574 stx %g0, [%g4]
575
576 /* Include any extra MSI handler from the user that needs to be
577 * executed while the event queue is disabled. */
578 /* The code can assume that %g1 is the thread,
579 * %g2 is the vector, and
580 * %g3 is the INO */
581#ifdef INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED
582intr0x60_handle_msi_extra_handler_while_eq_disabled_${idx}:
583INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED
584#endif /* INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED */
585
586intr0x60_handle_piu_msi_${idx}_enable_eq:
587 set 1, %g4
588 sllx %g4, 44, %g4 ! EN is bit 44
589 best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_ADDR
590 +PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_MSI_${idx}_EQN),
591 %g7, %g5)
592 stx %g4, [%g5]
593
594 ba intr0x60_handle_msi_extra_handler
595 nop
596#endif /* INTR0x60_MSI_${idx}_NUM */
597
598
599>}
600
601
602 /* Include any extra MSI handler from the user */
603 /* The code can assume that %g1 is the thread,
604 * %g2 is the vector, and
605 * %g3 is the INO */
606intr0x60_handle_msi_extra_handler:
607#ifdef INTR0x60_MSI_EXTRA_HANDLER
608INTR0x60_MSI_EXTRA_HANDLER
609#endif /* INTR0x60_MSI_EXTRA_HANDLER */
610
611intr0x60_handle_piu_msi_retry:
612 /* Retry the instruction that was trapped */
613 retry
614
615
616#ifdef INTR0x60_PM_PME_EQN
617 /************ Handle PM_PME ***********/
618intr0x60_handle_piu_pm_pme:
619!WIP: /* Check whether this thread matches this INO */
620!WIP: cmp %g1/*tid*/, INTR0x60_MONDO_XXX_THREAD
621!WIP: bne intr0x60_handle_piu_bad_thread
622!WIP: nop
623 /* Clear the interrupt */
624
625intr0x60_handle_piu_pm_pme_disable_eq:
626 set 1, %g4
627 sllx %g4, 44, %g4 ! DIS is bit 44
628 best_set_reg(mpeval(PCI_E_EV_QUE_CTL_CLEAR_ADDR
629 +PCI_E_EV_QUE_CTL_CLEAR_STEP*INTR0x60_PM_PME_EQN),
630 %g7, %g5)
631 stx %g4, [%g5]
632
633 ! Set Event Queue Head = Event Queue Tail
634intr0x60_handle_piu_pm_pme_reset_eq_head:
635 best_set_reg(mpeval(PCI_E_EV_QUE_TAIL_ADDR
636 +PCI_E_EV_QUE_TAIL_STEP*INTR0x60_PM_PME_EQN),
637 %g7, %g5)
638 ldx [%g5], %g6
639 best_set_reg(mpeval(PCI_E_EV_QUE_HEAD_ADDR
640 +PCI_E_EV_QUE_HEAD_STEP*INTR0x60_PM_PME_EQN),
641 %g7, %g5)
642 stx %g6, [%g5]
643
644intr0x60_handle_piu_pm_pme_clear_int:
645 best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR
646 +(4+INTR0x60_PM_PME_EQN)*PCI_E_INT_CLEAR_STEP),
647 %g5, %g4)
648 stx %g0, [%g4]
649
650intr0x60_handle_piu_pm_pme_clear_mondo_busy:
651 best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
652 stx %g0, [%g4]
653
654 /* Include any extra PM_PME handler from the user that needs to be
655 * executed while the event queue is disabled. */
656 /* The code can assume that %g1 is the thread,
657 * %g2 is the vector, and
658 * %g3 is the INO */
659#ifdef INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED
660intr0x60_handle_pm_pme_extra_handler_while_eq_disabled:
661INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED
662#endif /* INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED */
663
664intr0x60_handle_piu_pm_pme_enable_eq:
665 set 1, %g4
666 sllx %g4, 44, %g4 ! EN is bit 44
667 best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_ADDR
668 +PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_PM_PME_EQN),
669 %g7, %g5)
670 stx %g4, [%g5]
671
672 /* Include any extra PM_PME handler from the user */
673 /* The code can assume that %g1 is the thread,
674 * %g2 is the vector, and
675 * %g3 is the INO */
676intr0x60_handle_pm_pme_extra_handler:
677#ifdef INTR0x60_PM_PME_EXTRA_HANDLER
678INTR0x60_PM_PME_EXTRA_HANDLER
679#endif /* INTR0x60_PM_PME_EXTRA_HANDLER */
680
681intr0x60_handle_piu_pm_pme_retry:
682 /* Retry the instruction that was trapped */
683 retry
684#endif /* INTR0x60_PM_PME_EQN */
685
686
687#ifdef INTR0x60_PME_TO_ACK_EQN
688 /************ Handle PME_TO_ACK ***********/
689intr0x60_handle_piu_pme_to_ack:
690!WIP: /* Check whether this thread matches this INO */
691!WIP: cmp %g1/*tid*/, INTR0x60_MONDO_XXX_THREAD
692!WIP: bne intr0x60_handle_piu_bad_thread
693!WIP: nop
694 /* Clear the interrupt */
695
696intr0x60_handle_piu_pme_to_ack_disable_eq:
697 set 1, %g4
698 sllx %g4, 44, %g4 ! DIS is bit 44
699 best_set_reg(mpeval(PCI_E_EV_QUE_CTL_CLEAR_ADDR
700 +PCI_E_EV_QUE_CTL_CLEAR_STEP*INTR0x60_PME_TO_ACK_EQN),
701 %g7, %g5)
702 stx %g4, [%g5]
703
704 ! Set Event Queue Head = Event Queue Tail
705intr0x60_handle_piu_pme_to_ack_reset_eq_head:
706 best_set_reg(mpeval(PCI_E_EV_QUE_TAIL_ADDR
707 +PCI_E_EV_QUE_TAIL_STEP*INTR0x60_PME_TO_ACK_EQN),
708 %g7, %g5)
709 ldx [%g5], %g6
710 best_set_reg(mpeval(PCI_E_EV_QUE_HEAD_ADDR
711 +PCI_E_EV_QUE_HEAD_STEP*INTR0x60_PME_TO_ACK_EQN),
712 %g7, %g5)
713 stx %g6, [%g5]
714
715intr0x60_handle_piu_pme_to_ack_clear_int:
716 best_set_reg(mpeval(PCI_E_INT_CLEAR_ADDR
717 +(4+INTR0x60_PME_TO_ACK_EQN)*PCI_E_INT_CLEAR_STEP),
718 %g5, %g4)
719 stx %g0, [%g4]
720
721intr0x60_handle_piu_pme_to_ack_clear_mondo_busy:
722 best_set_reg(MONDO_INT_ABUSY, %g5, %g4)
723 stx %g0, [%g4]
724
725 /* Include any extra PME_TO_ACK handler from the user that needs to be
726 * executed while the event queue is disabled. */
727 /* The code can assume that %g1 is the thread,
728 * %g2 is the vector, and
729 * %g3 is the INO */
730#ifdef INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED
731intr0x60_handle_pme_to_ack_extra_handler_while_eq_disabled:
732INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED
733#endif /* INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED */
734
735intr0x60_handle_piu_pme_to_ack_enable_eq:
736 set 1, %g4
737 sllx %g4, 44, %g4 ! EN is bit 44
738 best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_ADDR
739 +PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_PME_TO_ACK_EQN),
740 %g7, %g5)
741 stx %g4, [%g5]
742
743 /* Include any extra PME_TO_ACK handler from the user */
744 /* The code can assume that %g1 is the thread,
745 * %g2 is the vector, and
746 * %g3 is the INO */
747intr0x60_handle_pme_to_ack_extra_handler:
748#ifdef INTR0x60_PME_TO_ACK_EXTRA_HANDLER
749INTR0x60_PME_TO_ACK_EXTRA_HANDLER
750#endif /* INTR0x60_PME_TO_ACK_EXTRA_HANDLER */
751
752intr0x60_handle_piu_pme_to_ack_retry:
753 /* Retry the instruction that was trapped */
754 retry
755#endif /* INTR0x60_PME_TO_ACK_EQN */
756
757
758intr0x60_handle_piu_bad_thread:
759 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_piu_bad_thread)) -> printf("ERROR: Mondo delivered to wrong thread",*,1)
760 EXIT_BAD
761#endif /* INTR0x60_MONDO_IV */
762
763
764#if (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV)
765/************************************************************************/
766/* Handle SSI parity error interrupts */
767
768intr0x60_handle_ssi_err:
769 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_err)) -> printf("INFO: SSI parity error interrupt received",*,1)
770 /* Make sure that this thread is the right one */
771 best_set_reg(INTR0x60_SSI_ERR_THREAD, %g7, %g4)
772#ifdef PORTABLE_CORE
773 and %g1, 0x7, %g7
774 cmp %g7, %g4
775#else
776 cmp %g1, %g4
777#endif
778 bne intr0x60_handle_ssi_err_bad_thread
779 nop
780
781 /* Include any extra SSI parity error handler from the user */
782 /* The code can assume that %g1 is the thread and %g2 is the vector */
783#ifdef INTR0x60_SSI_ERR_EXTRA_HANDLER
784intr0x60_handle_ssi_err_extra_handler:
785INTR0x60_SSI_ERR_EXTRA_HANDLER
786#endif /* INTR0x60_SSI_ERR_EXTRA_HANDLER */
787
788intr0x60_handle_ssi_err_retry:
789 /* Retry the instruction that was trapped */
790 retry
791
792intr0x60_handle_ssi_err_bad_thread:
793 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_err_bad_thread)) -> printf("ERROR: SSI parity error interrupt received on unexpected thread",*,1)
794 EXIT_BAD
795#endif /* (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV) */
796
797
798#if (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV)
799/************************************************************************/
800/* Handle SSI_EXT_INT_L interrupts */
801
802intr0x60_handle_ssi_int:
803 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_int)) -> printf("INFO: SSI_EXT_INT_L interrupt received",*,1)
804 /* Make sure that this thread is the right one */
805 best_set_reg(INTR0x60_SSI_INT_THREAD, %g7, %g4)
806#ifdef PORTABLE_CORE
807 and %g1, 0x7, %g7
808 cmp %g7, %g4
809#else
810 cmp %g1, %g4
811#endif
812 bne intr0x60_handle_ssi_int_bad_thread
813 nop
814
815 /* Include any extra SSI_EXT_INT_L handler from the user */
816 /* The code can assume that %g1 is the thread and %g2 is the vector */
817#ifdef INTR0x60_SSI_INT_EXTRA_HANDLER
818intr0x60_handle_ssi_int_extra_handler:
819INTR0x60_SSI_INT_EXTRA_HANDLER
820#endif /* INTR0x60_SSI_INT_EXTRA_HANDLER */
821
822intr0x60_handle_ssi_int_retry:
823 /* Retry the instruction that was trapped */
824 retry
825
826intr0x60_handle_ssi_int_bad_thread:
827 !\$EV trig_pc_d(1, \@VA(.HTRAPS.intr0x60_handle_ssi_int_bad_thread)) -> printf("ERROR: SSI_EXT_INT_L interrupt received on unexpected thread",*,1)
828 EXIT_BAD
829#endif /* (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV) */
830
831
832
833
834/*
835 * Need to have some tables to identify the source of the interrupt
836 * and whether it is expected for this thread.
837 *
838 * intr0x60_ivn_to_ig has one byte per interrupt vector number (0-63),
839 * which indicates the interrupt group, encoded as
840 * 0 - unused (error)
841 * 1 - cross-call
842 * 2 - SSI error
843 * 3 - SSI_EXT_INT_L
844 * 4 - NIU
845 * 5 - PIU mondo
846 */
847
848.data
849intr0x60_ivn_to_ig:
850>for ($count = 0; $count < $max_cc_ivns; $count++) {
851
852#ifdef INTR0x60_CC_IV_${count}
853#define INTR0x60_CC_IV_${count}_CHECK (INTR0x60_CC_IV_${count} == `\$1')
854#else
855#define INTR0x60_CC_IV_${count}_CHECK (0)
856#endif
857>}
858>for ($count = 0; $count < $max_niu_ivns; $count++) {
859
860#ifdef INTR0x60_NIU_RX_IV_${count}
861#define INTR0x60_NIU_RX_IV_${count}_CHECK (INTR0x60_NIU_RX_IV_${count} == `\$1')
862#else
863#define INTR0x60_NIU_RX_IV_${count}_CHECK (0)
864#endif
865>}
866>for ($count = 0; $count < $max_niu_ivns; $count++) {
867
868#ifdef INTR0x60_NIU_TX_IV_${count}
869#define INTR0x60_NIU_TX_IV_${count}_CHECK (INTR0x60_NIU_TX_IV_${count} == `\$1')
870#else
871#define INTR0x60_NIU_TX_IV_${count}_CHECK (0)
872#endif
873>}
874
875#if (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV)
876#define INTR0x60_SSI_ERR_IV_CHECK (INTR0x60_SSI_ERR_IV == `\$1')
877#else
878#define INTR0x60_SSI_ERR_IV_CHECK (0)
879#endif
880
881#if (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV)
882#define INTR0x60_SSI_INT_IV_CHECK (INTR0x60_SSI_INT_IV == `\$1')
883#else
884#define INTR0x60_SSI_INT_IV_CHECK (0)
885#endif
886
887#ifdef INTR0x60_MONDO_IV
888#define INTR0x60_MONDO_IV_CHECK (INTR0x60_MONDO_IV == `\$1')
889#else
890#define INTR0x60_MONDO_IV_CHECK (0)
891#endif
892
893/* Note: Need to put INTR0x60_IG_* names on a separate line
894 * because the *_CHECK macros may contain a half-quote which
895 * would prevent cpp from doing the macro replacement */
896define(`INTR0x60_IVN_TO_IG',
897 `ifelse(eval( INTR0x60_CC_IV_0_CHECK
898>for ($count = 1; $count < $max_cc_ivns-1; $count++) {
899 || INTR0x60_CC_IV_${count}_CHECK
900>}
901 || INTR0x60_CC_IV_${count}_CHECK), 1,
902 INTR0x60_IG_CC,
903 eval( INTR0x60_SSI_ERR_IV_CHECK ), 1,
904 INTR0x60_IG_SSI_ERR,
905 eval( INTR0x60_SSI_INT_IV_CHECK ), 1,
906 INTR0x60_IG_SSI_INT,
907 eval( INTR0x60_MONDO_IV_CHECK ), 1,
908 INTR0x60_IG_PIU,
909 eval( INTR0x60_NIU_RX_IV_0_CHECK
910>for ($count = 1; $count < $max_niu_ivns-1; $count++) {
911 || INTR0x60_NIU_RX_IV_${count}_CHECK
912>}
913 || INTR0x60_NIU_RX_IV_${count}_CHECK), 1,
914 INTR0x60_IG_NIU_RX,
915 eval( INTR0x60_NIU_TX_IV_0_CHECK
916>for ($count = 1; $count < $max_niu_ivns-1; $count++) {
917 || INTR0x60_NIU_TX_IV_${count}_CHECK
918>}
919 || INTR0x60_NIU_TX_IV_${count}_CHECK), 1,
920 INTR0x60_IG_NIU_TX,
921 INTR0x60_IG_UNUSED)'
922 )dnl
923
924>for ($ivn = 0; $ivn < $hw_num_ivs; $ivn++) {
925 .byte INTR0x60_IVN_TO_IG(${ivn})
926>}
927undefine(`INTR0x60_IVN_TO_IG')dnl