Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: interrupt0x60_sys_init.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_sys_init.s.pal,v 1.9 2006/12/01 19:22:18 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 | /* Initialize system-wide interrupt-related registers (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_handler.s | |
59 | * | |
60 | * The primary goal of this file is to take the -midas_args=-DINTR0x60_<xx> | |
61 | * options (or #defines) and do the corresponding initialization | |
62 | * of N2 registers. These macros are defined in interrupt0x60_defines.h | |
63 | */ | |
64 | ||
65 | ||
66 | !! DO NOT MODIFY G1 !!! | |
67 | ||
68 | /* We need some cpp macros for NCU register addresses */ | |
69 | #include "ncu_defines.h" | |
70 | ||
71 | #if defined(INTR0x60_NIU_RX_IV_0) || defined(INTR0x60_NIU_TX_IV_0) | |
72 | #include "niu_defines.h" | |
73 | #include "niu_macros.h" | |
74 | #endif /*defined(INTR0x60_NIU_RX_IV_0) || defined(INTR0x60_NIU_TX_IV_0)*/ | |
75 | ||
76 | ||
77 | intr0x60_sys_init: | |
78 | ||
79 | #ifdef PORTABLE_CORE | |
80 | ldxa [%g0] ASI_INTR_ID, %l7 | |
81 | and %l7, 0x38, %l7 ! %l7 = core ID, not thread ID | |
82 | #endif | |
83 | ||
84 | #if defined(INTR0x60_INITIALIZE_INT_MAN) || (INTR0x60_SSI_ERR_IV != INTR0x60_BAD_IV) || (INTR0x60_SSI_INT_IV != INTR0x60_BAD_IV) | |
85 | ! Initialize the Interrupt Management Registers | |
86 | intr0x60_sys_init_int_man: | |
87 | best_set_reg(INT_MAN, %l1, %l2) ! %l2 = INT_MAN reg. addr. | |
88 | ||
89 | intr0x60_sys_init_int_man_0: | |
90 | best_set_reg(mpeval((INTR0x60_BAD_THREAD<<8)+INTR0x60_BAD_IV), %l0, %l1) | |
91 | #ifdef PORTABLE_CORE | |
92 | setx 0x3800, %l0, %l6 | |
93 | andn %l1, %l6, %l1 | |
94 | sllx %l7, 8, %l6 | |
95 | or %l1, %l6, %l1 ! Use core ID of core running on | |
96 | #endif | |
97 | stx %l1, [%l2] | |
98 | ||
99 | intr0x60_sys_init_int_man_ssi_err: | |
100 | add %l2, INT_MAN_STEP, %l2 | |
101 | best_set_reg(mpeval((INTR0x60_SSI_ERR_THREAD<<8)+INTR0x60_SSI_ERR_IV), | |
102 | %l0, %l1) | |
103 | #ifdef PORTABLE_CORE | |
104 | setx 0x3800, %l0, %l6 | |
105 | andn %l1, %l6, %l1 | |
106 | sllx %l7, 8, %l6 | |
107 | or %l1, %l6, %l1 ! Use core ID of core running on | |
108 | #endif | |
109 | stx %l1, [%l2] | |
110 | intr0x60_sys_init_enable_ssi_error_interrupts: | |
111 | #include "ssi_defines.h" | |
112 | best_set_reg(SSI_TIMEOUT_ADDR, %l0, %l3) | |
113 | best_set_reg(SSI_TIMEOUT_ERREN_MASK, %l0, %l1) | |
114 | ldx [%l3],%l0 | |
115 | or %l0, %l1, %l1 | |
116 | stx %l1, [%l3] | |
117 | ||
118 | intr0x60_sys_init_int_man_ssi_int: | |
119 | add %l2, INT_MAN_STEP, %l2 | |
120 | best_set_reg(mpeval((INTR0x60_SSI_INT_THREAD<<8)+INTR0x60_SSI_INT_IV), | |
121 | %l0, %l1) | |
122 | #ifdef PORTABLE_CORE | |
123 | setx 0x3800, %l0, %l6 | |
124 | andn %l1, %l6, %l1 | |
125 | sllx %l7, 8, %l6 | |
126 | or %l1, %l6, %l1 ! Use core ID of core running on | |
127 | #endif | |
128 | stx %l1, [%l2] | |
129 | #endif /* INTR0x60_INITIALIZE_INT_MAN or SSI_ERR or SSI_INT */ | |
130 | ||
131 | ||
132 | >for ($ivn = 0; $ivn < $max_niu_ivns; $ivn++) { | |
133 | ||
134 | #ifdef INTR0x60_NIU_RX_IV_${ivn} | |
135 | intr0x60_sys_init_int_man_niu_rx_${ivn}: | |
136 | best_set_reg(mpeval(INT_MAN+(64+INTR0x60_NIU_RX_IV_${ivn})*INT_MAN_STEP), %l1, %l2) | |
137 | best_set_reg(mpeval((INTR0x60_NIU_RX_THREAD_${ivn}<<8)+INTR0x60_NIU_RX_IV_${ivn}), | |
138 | %l0, %l1) | |
139 | stx %l1, [%l2] | |
140 | #ifndef INTR0x60_NIU_RX_NO_SYS_INIT | |
141 | ! Initialize the NIU for RX DMA interrupt. | |
142 | NIU_RX_LD_IM0_INTR_ON_MARK( INTR0x60_NIU_RX_DMA_${ivn}, | |
143 | %l1, %l2, %l3, %l4, | |
144 | INTR0x60_NIU_RX_IV_${ivn}, | |
145 | eval(64 + INTR0x60_NIU_RX_IV_${ivn}), %l5 ) | |
146 | #endif | |
147 | #endif /* INTR0x60_NIU_RX_IV_${ivn} */ | |
148 | >} | |
149 | ||
150 | ||
151 | >for ($ivn = 0; $ivn < $max_niu_ivns; $ivn++) { | |
152 | ||
153 | #ifdef INTR0x60_NIU_TX_IV_${ivn} | |
154 | intr0x60_sys_init_int_man_niu_tx_${ivn}: | |
155 | best_set_reg(mpeval(INT_MAN+(64+INTR0x60_NIU_TX_IV_${ivn})*INT_MAN_STEP), %l1, %l2) | |
156 | best_set_reg(mpeval((INTR0x60_NIU_TX_THREAD_${ivn}<<8)+INTR0x60_NIU_TX_IV_${ivn}), | |
157 | %l0, %l1) | |
158 | stx %l1, [%l2] | |
159 | #ifndef INTR0x60_NIU_TX_NO_SYS_INIT | |
160 | ! Initialize the NIU for TX DMA interrupt. | |
161 | NIU_TX_LD_IM0_INTR_ON_MARK( INTR0x60_NIU_TX_DMA_${ivn}, | |
162 | %l1, %l2, %l3, %l4, | |
163 | INTR0x60_NIU_TX_IV_${ivn}, | |
164 | eval(64 + INTR0x60_NIU_TX_IV_${ivn}) ) | |
165 | #endif /* INTR0x60_NIU_TX_NO_SYS_INIT */ | |
166 | #endif /* INTR0x60_NIU_TX_IV_${ivn} */ | |
167 | >} | |
168 | ||
169 | ||
170 | ||
171 | ! Initialize Mondo Interrupt Vector Register | |
172 | intr0x60_sys_init_mondo_int_vec: | |
173 | #ifdef INTR0x60_MONDO_IV | |
174 | best_set_reg(INTR0x60_MONDO_IV, %l2, %l1) | |
175 | #else | |
176 | best_set_reg(INTR0x60_BAD_IV, %l2, %l1) | |
177 | #endif /* INTR0x60_MONDO_IV */ | |
178 | best_set_reg(MONDO_INT_VEC, %l2, %l3) | |
179 | stx %l1, [%l3] | |
180 | ||
181 | #ifdef INTR0x60_MONDO_IV | |
182 | /* Mondos come from PIU, so do the appropriate initialization */ | |
183 | /* Need some cpp macros for PIU registers */ | |
184 | #include "peu_defines.h" | |
185 | ||
186 | ||
187 | intr0x60_sys_init_clear_intx: | |
188 | set 1, %l3 | |
189 | >for $intx ("A", "B", "C", "D") { | |
190 | best_set_reg(PCI_E_INT_${intx}_CLEAR_ADDR, %l1, %l2) | |
191 | stx %l3, [%l2] | |
192 | >} | |
193 | ||
194 | ||
195 | /* Clear the MSI registers, if any MSIs are being used */ | |
196 | #ifdef INTR0x60_MSI_0_NUM | |
197 | intr0x60_sys_init_clear_msi: | |
198 | set 1, %l3 | |
199 | sllx %l3, 62, %l3 ! EQWR_N is bit 62 | |
200 | best_set_reg(PCI_E_MSI_CLEAR_ADDR, %l1, %l2) | |
201 | >for $idx (0 .. $max_msi_idx_m1) { | |
202 | #ifdef INTR0x60_MSI_${idx}_NUM | |
203 | intr0x60_sys_init_clear_msi_${idx}: | |
204 | best_set_reg(mpeval(PCI_E_MSI_CLEAR_STEP*INTR0x60_MSI_${idx}_NUM), | |
205 | %l1, %l4) | |
206 | stx %l3, [%l2+%l4] | |
207 | #endif /* INTR0x60_MSI_${idx}_NUM */ | |
208 | >} | |
209 | #endif /* INTR0x60_MSI_0_NUM */ | |
210 | ||
211 | ||
212 | ! Also clear in Interrupt Clear reg. | |
213 | intr0x60_sys_init_piu_intr_clear: | |
214 | best_set_reg(PCI_E_INT_CLEAR_ADDR, %l1, %l2) | |
215 | mov PCI_E_INT_CLEAR_COUNT, %l3 | |
216 | intr0x60_sys_init_piu_intr_clear_loop_top: | |
217 | stx %g0, [%l2] | |
218 | dec %l3 | |
219 | brnz %l3,intr0x60_sys_init_piu_intr_clear_loop_top | |
220 | add PCI_E_INT_CLEAR_STEP, %l2, %l2 | |
221 | ||
222 | /* WIP: Clear INO 62 and 63 */ | |
223 | ||
224 | ||
225 | /* Set up the Event Queues in PIU, if any are being used */ | |
226 | #ifdef INTR0x60_EVENT_QUEUE_BASE | |
227 | intr0x60_sys_init_piu_eq_base_addr: | |
228 | ! First the Event Queue Base Address reg. | |
229 | ! Formatted for a bypass address. | |
230 | best_set_reg(PCI_E_EV_QUE_BASE_ADDRESS_ADDR, %l1, %l2) | |
231 | setx @PA(INTR0x60_EVENT_QUEUE_BASE), %l1, %l3 | |
232 | best_set_reg(0xfffc000000000000, %l1, %l6) | |
233 | or %l3, %l6, %l3 | |
234 | stx %l3, [%l2] | |
235 | ||
236 | ! Event Queue Control Set reg. | |
237 | intr0x60_sys_init_piu_eq_ctl_set_en: | |
238 | set 1, %l3 | |
239 | sllx %l3, 44, %l3 ! EN is bit 44 | |
240 | best_set_reg(PCI_E_EV_QUE_CTL_SET_ADDR, %l1, %l2) | |
241 | >for $idx (0 .. $max_msi_idx_m1) { | |
242 | #ifdef INTR0x60_MSI_${idx}_NUM | |
243 | intr0x60_sys_init_piu_eq_ctl_set_en_${idx}: | |
244 | best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_MSI_${idx}_EQN), | |
245 | %l1, %l4) | |
246 | stx %l3, [%l2+%l4] | |
247 | #endif /* INTR0x60_MSI_${idx}_NUM */ | |
248 | >} | |
249 | #ifdef INTR0x60_PM_PME_EQN | |
250 | intr0x60_sys_init_piu_eq_ctl_set_en_pm_pme: | |
251 | best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_PM_PME_EQN), | |
252 | %l1, %l4) | |
253 | stx %l3, [%l2+%l4] | |
254 | #endif /* INTR0x60_PM_PME_EQN */ | |
255 | #ifdef INTR0x60_PME_TO_ACK_EQN | |
256 | intr0x60_sys_init_piu_eq_ctl_set_en_pme_to_ack: | |
257 | best_set_reg(mpeval(PCI_E_EV_QUE_CTL_SET_STEP*INTR0x60_PME_TO_ACK_EQN), | |
258 | %l1, %l4) | |
259 | stx %l3, [%l2+%l4] | |
260 | #endif /* INTR0x60_PME_TO_ACK_EQN */ | |
261 | ||
262 | #endif /* INTR0x60_EVENT_QUEUE_BASE */ | |
263 | ||
264 | ||
265 | #ifdef INTR0x60_MSI_START_ADDRESS | |
266 | ! Set up the MSI address | |
267 | intr0x60_sys_init_piu_msi_addr: | |
268 | best_set_reg(INTR0x60_MSI_START_ADDRESS, %l1, %l3) | |
269 | best_set_reg(PCI_E_MSI_32_ADDRESS_ADDR, %l1, %l2) | |
270 | stx %l3, [%l2] | |
271 | best_set_reg(PCI_E_MSI_64_ADDRESS_ADDR, %l1, %l2) | |
272 | stx %l3, [%l2] | |
273 | ||
274 | ! MSI-to-Event Queue Mapping registers | |
275 | intr0x60_sys_init_piu_msi_mapping: | |
276 | set 1, %l3 | |
277 | sllx %l3, 63, %l3 ! V is bit 63 | |
278 | best_set_reg(PCI_E_MSI_MAP_ADDR, %l1, %l2) | |
279 | >for $idx (0 .. $max_msi_idx_m1) { | |
280 | #ifdef INTR0x60_MSI_${idx}_NUM | |
281 | intr0x60_sys_init_piu_msi_mapping_${idx}: | |
282 | best_set_reg(mpeval(PCI_E_MSI_MAP_STEP*INTR0x60_MSI_${idx}_NUM), | |
283 | %l1, %l4) | |
284 | best_set_reg(INTR0x60_MSI_${idx}_EQN, %l1, %l5) | |
285 | add %l3, %l5, %l5 | |
286 | stx %l5, [%l2+%l4] | |
287 | #endif /* INTR0x60_MSI_${idx}_NUM */ | |
288 | >} | |
289 | #endif /* INTR0x60_MSI_START_ADDRESS */ | |
290 | ||
291 | #ifdef INTR0x60_PM_PME_EQN | |
292 | ! PM_PME-to-Event Queue Mapping registers | |
293 | intr0x60_sys_init_piu_pm_pme_mapping: | |
294 | set 1, %l3 | |
295 | sllx %l3, 63, %l3 ! V is bit 63 | |
296 | best_set_reg(PCI_E_PM_PME_MAP_ADDR, %l1, %l2) | |
297 | best_set_reg(INTR0x60_PM_PME_EQN, %l1, %l5) | |
298 | add %l3, %l5, %l5 | |
299 | stx %l5, [%l2] | |
300 | #endif /* INTR0x60_PM_PME_EQN */ | |
301 | ||
302 | #ifdef INTR0x60_PME_TO_ACK_EQN | |
303 | ! PME_TO_ACK-to-Event Queue Mapping registers | |
304 | intr0x60_sys_init_piu_pme_to_ack_mapping: | |
305 | set 1, %l3 | |
306 | sllx %l3, 63, %l3 ! V is bit 63 | |
307 | best_set_reg(PCI_E_PME_ACK_MAP_ADDR, %l1, %l2) | |
308 | best_set_reg(INTR0x60_PME_TO_ACK_EQN, %l1, %l5) | |
309 | add %l3, %l5, %l5 | |
310 | stx %l5, [%l2] | |
311 | #endif /* INTR0x60_PME_TO_ACK_EQN */ | |
312 | ||
313 | ||
314 | >for $mondo_num (20 .. 59, 62, 63) { | |
315 | ||
316 | #if INTR0x60_MONDO_${mondo_num}_V || INTR0x60_INIT_ALL_PIU_INT_MAP | |
317 | intr0x60_sys_init_piu_int_map_mondo_${mondo_num}: | |
318 | best_set_reg(mpeval(PCI_E_INT_MAP_ADDR+PCI_E_INT_MAP_STEP*(${mondo_num}-20)), | |
319 | %l1, %l3) | |
320 | best_set_reg(mpeval((INTR0x60_MONDO_${mondo_num}_MODE << PCI_E_INT_MAP_MDO_MODE_SHIFT)+ | |
321 | (INTR0x60_MONDO_${mondo_num}_V << PCI_E_INT_MAP_V_SHIFT)+ | |
322 | (INTR0x60_MONDO_${mondo_num}_THREAD << PCI_E_INT_MAP_THREADID_SHIFT)+ | |
323 | (1 << (INTR0x60_MONDO_${mondo_num}_CNTRL+PCI_E_INT_MAP_INT_CNTRL_NUM_SHIFT))), | |
324 | %l1, %l2) | |
325 | #ifdef PORTABLE_CORE | |
326 | set 0x38, %l1 | |
327 | sllx %l1, PCI_E_INT_MAP_THREADID_SHIFT, %l1 | |
328 | andn %l2, %l1, %l2 | |
329 | sllx %l7, PCI_E_INT_MAP_THREADID_SHIFT, %l1 | |
330 | or %l1, %l2, %l2 ! Use core ID of core running on | |
331 | #endif | |
332 | stx %l2, [%l3] | |
333 | #endif /* INTR0x60_MONDO_${mondo_num}_V || INTR0x60_INIT_ALL_PIU_INT_MAP */ | |
334 | >} | |
335 | ||
336 | #endif /* INTR0x60_MONDO_IV */ |