Commit | Line | Data |
---|---|---|
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 | */ | |
38 | start_perl | |
39 | # $Id: interrupt0x60_handler.s.pal,v 1.14 2006/12/01 19:20:42 granvold Exp $ | |
40 | print "/* \$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 | ||
51 | start_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 | ||
70 | SECTION .HTRAPS | |
71 | .text | |
72 | .global intr0x60_handler | |
73 | ||
74 | intr0x60_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 */ | |
118 | intr0x60_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 | ||
126 | intr0x60_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 | |
144 | intr0x60_handle_cc_extra_handler: | |
145 | INTR0x60_CC_EXTRA_HANDLER | |
146 | #endif /* INTR0x60_CC_EXTRA_HANDLER */ | |
147 | ||
148 | intr0x60_handle_cc_retry: | |
149 | /* Retry the instruction that was trapped */ | |
150 | retry | |
151 | ||
152 | #ifndef INTR0x60_CC_DEST_ALL | |
153 | intr0x60_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 | |
158 | intr0x60_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 | ||
175 | intr0x60_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} | |
180 | intr0x60_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 | |
193 | 1: | |
194 | #endif /* INTR0x60_NIU_TX_IV_${ivn} */ | |
195 | ||
196 | >} | |
197 | ||
198 | /* If we get here, we have an unknown vector */ | |
199 | intr0x60_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 */ | |
204 | intr0x60_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 | |
226 | intr0x60_handle_niu_tx_extra_handler: | |
227 | INTR0x60_NIU_TX_EXTRA_HANDLER | |
228 | #endif /* INTR0x60_NIU_TX_EXTRA_HANDLER */ | |
229 | ||
230 | intr0x60_handle_niu_tx_retry: | |
231 | /* Retry the instruction that was trapped */ | |
232 | retry | |
233 | ||
234 | intr0x60_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 | ||
244 | intr0x60_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} | |
249 | intr0x60_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 | |
262 | 1: | |
263 | #endif /* INTR0x60_NIU_RX_IV_${ivn} */ | |
264 | ||
265 | >} | |
266 | ||
267 | /* If we get here, we have an unknown vector */ | |
268 | intr0x60_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 */ | |
273 | intr0x60_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 | |
278 | intr0x60_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 | ||
286 | intr0x60_handle_niu_rx_fatal_error: | |
287 | #ifdef INTR0x60_NIU_RX_FATAL_HANDLER | |
288 | INTR0x60_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 | |
295 | intr0x60_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 | |
300 | intr0x60_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 | |
304 | intr0x60_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 | |
311 | intr0x60_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 | |
314 | intr0x60_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 | ||
327 | intr0x60_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 | |
333 | intr0x60_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 | |
338 | intr0x60_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 | |
341 | intr0x60_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 | |
355 | intr0x60_handle_niu_rx_extra_handler: | |
356 | INTR0x60_NIU_RX_EXTRA_HANDLER | |
357 | #endif /* INTR0x60_NIU_RX_EXTRA_HANDLER */ | |
358 | ||
359 | intr0x60_handle_niu_rx_retry: | |
360 | /* Retry the instruction that was trapped */ | |
361 | retry | |
362 | ||
363 | intr0x60_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 | ||
373 | intr0x60_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 | |
405 | intr0x60_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 | |
412 | intr0x60_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 | |
418 | intr0x60_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 */ | |
425 | intr0x60_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} ***********/ | |
436 | intr0x60_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 */ | |
447 | intr0x60_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) | |
480 | intr0x60_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 | |
488 | intr0x60_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 | |
499 | intr0x60_handle_int${lc}_extra_handler: | |
500 | INTR0x60_INT${uc}_EXTRA_HANDLER | |
501 | #endif /* INTR0x60_INT${uc}_EXTRA_HANDLER */ | |
502 | ||
503 | intr0x60_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 */ | |
509 | intr0x60_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} ***********/ | |
521 | intr0x60_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. */ | |
528 | intr0x60_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 | ||
537 | intr0x60_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 | |
546 | intr0x60_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 | ||
556 | intr0x60_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 | |
568 | intr0x60_handle_msi_${idx}_extra_handler_while_busy: | |
569 | INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY | |
570 | #endif /* INTR0x60_MSI_${idx}_EXTRA_HANDLER_WHILE_BUSY */ | |
571 | ||
572 | intr0x60_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 | |
582 | intr0x60_handle_msi_extra_handler_while_eq_disabled_${idx}: | |
583 | INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED | |
584 | #endif /* INTR0x60_MSI_EXTRA_HANDLER_WHILE_EQ_DISABLED */ | |
585 | ||
586 | intr0x60_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 */ | |
606 | intr0x60_handle_msi_extra_handler: | |
607 | #ifdef INTR0x60_MSI_EXTRA_HANDLER | |
608 | INTR0x60_MSI_EXTRA_HANDLER | |
609 | #endif /* INTR0x60_MSI_EXTRA_HANDLER */ | |
610 | ||
611 | intr0x60_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 ***********/ | |
618 | intr0x60_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 | ||
625 | intr0x60_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 | |
634 | intr0x60_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 | ||
644 | intr0x60_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 | ||
650 | intr0x60_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 | |
660 | intr0x60_handle_pm_pme_extra_handler_while_eq_disabled: | |
661 | INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED | |
662 | #endif /* INTR0x60_PM_PME_EXTRA_HANDLER_WHILE_EQ_DISABLED */ | |
663 | ||
664 | intr0x60_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 */ | |
676 | intr0x60_handle_pm_pme_extra_handler: | |
677 | #ifdef INTR0x60_PM_PME_EXTRA_HANDLER | |
678 | INTR0x60_PM_PME_EXTRA_HANDLER | |
679 | #endif /* INTR0x60_PM_PME_EXTRA_HANDLER */ | |
680 | ||
681 | intr0x60_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 ***********/ | |
689 | intr0x60_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 | ||
696 | intr0x60_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 | |
705 | intr0x60_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 | ||
715 | intr0x60_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 | ||
721 | intr0x60_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 | |
731 | intr0x60_handle_pme_to_ack_extra_handler_while_eq_disabled: | |
732 | INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED | |
733 | #endif /* INTR0x60_PME_TO_ACK_EXTRA_HANDLER_WHILE_EQ_DISABLED */ | |
734 | ||
735 | intr0x60_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 */ | |
747 | intr0x60_handle_pme_to_ack_extra_handler: | |
748 | #ifdef INTR0x60_PME_TO_ACK_EXTRA_HANDLER | |
749 | INTR0x60_PME_TO_ACK_EXTRA_HANDLER | |
750 | #endif /* INTR0x60_PME_TO_ACK_EXTRA_HANDLER */ | |
751 | ||
752 | intr0x60_handle_piu_pme_to_ack_retry: | |
753 | /* Retry the instruction that was trapped */ | |
754 | retry | |
755 | #endif /* INTR0x60_PME_TO_ACK_EQN */ | |
756 | ||
757 | ||
758 | intr0x60_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 | ||
768 | intr0x60_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 | |
784 | intr0x60_handle_ssi_err_extra_handler: | |
785 | INTR0x60_SSI_ERR_EXTRA_HANDLER | |
786 | #endif /* INTR0x60_SSI_ERR_EXTRA_HANDLER */ | |
787 | ||
788 | intr0x60_handle_ssi_err_retry: | |
789 | /* Retry the instruction that was trapped */ | |
790 | retry | |
791 | ||
792 | intr0x60_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 | ||
802 | intr0x60_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 | |
818 | intr0x60_handle_ssi_int_extra_handler: | |
819 | INTR0x60_SSI_INT_EXTRA_HANDLER | |
820 | #endif /* INTR0x60_SSI_INT_EXTRA_HANDLER */ | |
821 | ||
822 | intr0x60_handle_ssi_int_retry: | |
823 | /* Retry the instruction that was trapped */ | |
824 | retry | |
825 | ||
826 | intr0x60_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 | |
849 | intr0x60_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 */ | |
896 | define(`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 | >} | |
927 | undefine(`INTR0x60_IVN_TO_IG')dnl |