aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/sun4v_ivec.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/sun4v_ivec.S')
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S349
1 files changed, 349 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
new file mode 100644
index 000000000000..d9d442017d3d
--- /dev/null
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -0,0 +1,349 @@
1/* sun4v_ivec.S: Sun4v interrupt vector handling.
2 *
3 * Copyright (C) 2006 <davem@davemloft.net>
4 */
5
6#include <asm/cpudata.h>
7#include <asm/intr_queue.h>
8
9 .text
10 .align 32
11
12sun4v_cpu_mondo:
13 /* Head offset in %g2, tail offset in %g4.
14 * If they are the same, no work.
15 */
16 mov INTRQ_CPU_MONDO_HEAD, %g2
17 ldxa [%g2] ASI_QUEUE, %g2
18 mov INTRQ_CPU_MONDO_TAIL, %g4
19 ldxa [%g4] ASI_QUEUE, %g4
20 cmp %g2, %g4
21 be,pn %xcc, sun4v_cpu_mondo_queue_empty
22 nop
23
24 /* Get &trap_block[smp_processor_id()] into %g3. */
25 __GET_CPUID(%g1)
26 sethi %hi(trap_block), %g3
27 sllx %g1, TRAP_BLOCK_SZ_SHIFT, %g7
28 or %g3, %lo(trap_block), %g3
29 add %g3, %g7, %g3
30
31 /* Get CPU mondo queue base phys address into %g7. */
32 ldx [%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
33
34 /* Now get the cross-call arguments and handler PC, same
35 * layout as sun4u:
36 *
37 * 1st 64-bit word: low half is 32-bit PC, put into %g3 and jmpl to it
38 * high half is context arg to MMU flushes, into %g5
39 * 2nd 64-bit word: 64-bit arg, load into %g1
40 * 3rd 64-bit word: 64-bit arg, load into %g7
41 */
42 ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g3
43 add %g2, 0x8, %g2
44 srlx %g3, 32, %g5
45 ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g1
46 add %g2, 0x8, %g2
47 srl %g3, 0, %g3
48 ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g7
49 add %g2, 0x40 - 0x8 - 0x8, %g2
50
51 /* Update queue head pointer. */
52 sethi %hi(8192 - 1), %g4
53 or %g4, %lo(8192 - 1), %g4
54 and %g2, %g4, %g2
55
56 mov INTRQ_CPU_MONDO_HEAD, %g4
57 stxa %g2, [%g4] ASI_QUEUE
58 membar #Sync
59
60 jmpl %g3, %g0
61 nop
62
63sun4v_cpu_mondo_queue_empty:
64 retry
65
66sun4v_dev_mondo:
67 /* Head offset in %g2, tail offset in %g4. */
68 mov INTRQ_DEVICE_MONDO_HEAD, %g2
69 ldxa [%g2] ASI_QUEUE, %g2
70 mov INTRQ_DEVICE_MONDO_TAIL, %g4
71 ldxa [%g4] ASI_QUEUE, %g4
72 cmp %g2, %g4
73 be,pn %xcc, sun4v_dev_mondo_queue_empty
74 nop
75
76 /* Get &trap_block[smp_processor_id()] into %g3. */
77 __GET_CPUID(%g1)
78 sethi %hi(trap_block), %g3
79 sllx %g1, TRAP_BLOCK_SZ_SHIFT, %g7
80 or %g3, %lo(trap_block), %g3
81 add %g3, %g7, %g3
82
83 /* Get DEV mondo queue base phys address into %g5. */
84 ldx [%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5
85
86 /* Load IVEC into %g3. */
87 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
88 add %g2, 0x40, %g2
89
90 /* XXX There can be a full 64-byte block of data here.
91 * XXX This is how we can get at MSI vector data.
92 * XXX Current we do not capture this, but when we do we'll
93 * XXX need to add a 64-byte storage area in the struct ino_bucket
94 * XXX or the struct irq_desc.
95 */
96
97 /* Update queue head pointer, this frees up some registers. */
98 sethi %hi(8192 - 1), %g4
99 or %g4, %lo(8192 - 1), %g4
100 and %g2, %g4, %g2
101
102 mov INTRQ_DEVICE_MONDO_HEAD, %g4
103 stxa %g2, [%g4] ASI_QUEUE
104 membar #Sync
105
106 /* Get &__irq_work[smp_processor_id()] into %g1. */
107 sethi %hi(__irq_work), %g4
108 sllx %g1, 6, %g1
109 or %g4, %lo(__irq_work), %g4
110 add %g4, %g1, %g1
111
112 /* Get &ivector_table[IVEC] into %g4. */
113 sethi %hi(ivector_table), %g4
114 sllx %g3, 5, %g3
115 or %g4, %lo(ivector_table), %g4
116 add %g4, %g3, %g4
117
118 /* Load IRQ %pil into %g5. */
119 ldub [%g4 + 0x04], %g5
120
121 /* Insert ivector_table[] entry into __irq_work[] queue. */
122 sllx %g5, 2, %g3
123 lduw [%g1 + %g3], %g2 /* g2 = irq_work(cpu, pil) */
124 stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */
125 stw %g4, [%g1 + %g3] /* irq_work(cpu, pil) = bucket */
126
127 /* Signal the interrupt by setting (1 << pil) in %softint. */
128 mov 1, %g2
129 sllx %g2, %g5, %g2
130 wr %g2, 0x0, %set_softint
131
132sun4v_dev_mondo_queue_empty:
133 retry
134
135sun4v_res_mondo:
136 /* Head offset in %g2, tail offset in %g4. */
137 mov INTRQ_RESUM_MONDO_HEAD, %g2
138 ldxa [%g2] ASI_QUEUE, %g2
139 mov INTRQ_RESUM_MONDO_TAIL, %g4
140 ldxa [%g4] ASI_QUEUE, %g4
141 cmp %g2, %g4
142 be,pn %xcc, sun4v_res_mondo_queue_empty
143 nop
144
145 /* Get &trap_block[smp_processor_id()] into %g3. */
146 __GET_CPUID(%g1)
147 sethi %hi(trap_block), %g3
148 sllx %g1, TRAP_BLOCK_SZ_SHIFT, %g7
149 or %g3, %lo(trap_block), %g3
150 add %g3, %g7, %g3
151
152 /* Get RES mondo queue base phys address into %g5. */
153 ldx [%g3 + TRAP_PER_CPU_RESUM_MONDO_PA], %g5
154
155 /* Get RES kernel buffer base phys address into %g7. */
156 ldx [%g3 + TRAP_PER_CPU_RESUM_KBUF_PA], %g7
157
158 /* If the first word is non-zero, queue is full. */
159 ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g1
160 brnz,pn %g1, sun4v_res_mondo_queue_full
161 nop
162
163 /* Remember this entry's offset in %g1. */
164 mov %g2, %g1
165
166 /* Copy 64-byte queue entry into kernel buffer. */
167 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
168 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
169 add %g2, 0x08, %g2
170 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
171 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
172 add %g2, 0x08, %g2
173 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
174 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
175 add %g2, 0x08, %g2
176 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
177 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
178 add %g2, 0x08, %g2
179 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
180 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
181 add %g2, 0x08, %g2
182 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
183 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
184 add %g2, 0x08, %g2
185 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
186 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
187 add %g2, 0x08, %g2
188 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
189 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
190 add %g2, 0x08, %g2
191
192 /* Update queue head pointer. */
193 sethi %hi(8192 - 1), %g4
194 or %g4, %lo(8192 - 1), %g4
195 and %g2, %g4, %g2
196
197 mov INTRQ_RESUM_MONDO_HEAD, %g4
198 stxa %g2, [%g4] ASI_QUEUE
199 membar #Sync
200
201 /* Disable interrupts and save register state so we can call
202 * C code. The etrap handling will leave %g4 in %l4 for us
203 * when it's done.
204 */
205 rdpr %pil, %g2
206 wrpr %g0, 15, %pil
207 mov %g1, %g4
208 ba,pt %xcc, etrap_irq
209 rd %pc, %g7
210
211 /* Log the event. */
212 add %sp, PTREGS_OFF, %o0
213 call sun4v_resum_error
214 mov %l4, %o1
215
216 /* Return from trap. */
217 ba,pt %xcc, rtrap_irq
218 nop
219
220sun4v_res_mondo_queue_empty:
221 retry
222
223sun4v_res_mondo_queue_full:
224 /* The queue is full, consolidate our damage by setting
225 * the head equal to the tail. We'll just trap again otherwise.
226 * Call C code to log the event.
227 */
228 mov INTRQ_RESUM_MONDO_HEAD, %g2
229 stxa %g4, [%g2] ASI_QUEUE
230 membar #Sync
231
232 rdpr %pil, %g2
233 wrpr %g0, 15, %pil
234 ba,pt %xcc, etrap_irq
235 rd %pc, %g7
236
237 call sun4v_resum_overflow
238 add %sp, PTREGS_OFF, %o0
239
240 ba,pt %xcc, rtrap_irq
241 nop
242
243sun4v_nonres_mondo:
244 /* Head offset in %g2, tail offset in %g4. */
245 mov INTRQ_NONRESUM_MONDO_HEAD, %g2
246 ldxa [%g2] ASI_QUEUE, %g2
247 mov INTRQ_NONRESUM_MONDO_TAIL, %g4
248 ldxa [%g4] ASI_QUEUE, %g4
249 cmp %g2, %g4
250 be,pn %xcc, sun4v_nonres_mondo_queue_empty
251 nop
252
253 /* Get &trap_block[smp_processor_id()] into %g3. */
254 __GET_CPUID(%g1)
255 sethi %hi(trap_block), %g3
256 sllx %g1, TRAP_BLOCK_SZ_SHIFT, %g7
257 or %g3, %lo(trap_block), %g3
258 add %g3, %g7, %g3
259
260 /* Get RES mondo queue base phys address into %g5. */
261 ldx [%g3 + TRAP_PER_CPU_NONRESUM_MONDO_PA], %g5
262
263 /* Get RES kernel buffer base phys address into %g7. */
264 ldx [%g3 + TRAP_PER_CPU_NONRESUM_KBUF_PA], %g7
265
266 /* If the first word is non-zero, queue is full. */
267 ldxa [%g7 + %g2] ASI_PHYS_USE_EC, %g1
268 brnz,pn %g1, sun4v_nonres_mondo_queue_full
269 nop
270
271 /* Remember this entry's offset in %g1. */
272 mov %g2, %g1
273
274 /* Copy 64-byte queue entry into kernel buffer. */
275 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
276 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
277 add %g2, 0x08, %g2
278 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
279 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
280 add %g2, 0x08, %g2
281 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
282 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
283 add %g2, 0x08, %g2
284 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
285 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
286 add %g2, 0x08, %g2
287 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
288 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
289 add %g2, 0x08, %g2
290 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
291 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
292 add %g2, 0x08, %g2
293 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
294 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
295 add %g2, 0x08, %g2
296 ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
297 stxa %g3, [%g7 + %g2] ASI_PHYS_USE_EC
298 add %g2, 0x08, %g2
299
300 /* Update queue head pointer. */
301 sethi %hi(8192 - 1), %g4
302 or %g4, %lo(8192 - 1), %g4
303 and %g2, %g4, %g2
304
305 mov INTRQ_NONRESUM_MONDO_HEAD, %g4
306 stxa %g2, [%g4] ASI_QUEUE
307 membar #Sync
308
309 /* Disable interrupts and save register state so we can call
310 * C code. The etrap handling will leave %g4 in %l4 for us
311 * when it's done.
312 */
313 rdpr %pil, %g2
314 wrpr %g0, 15, %pil
315 mov %g1, %g4
316 ba,pt %xcc, etrap_irq
317 rd %pc, %g7
318
319 /* Log the event. */
320 add %sp, PTREGS_OFF, %o0
321 call sun4v_nonresum_error
322 mov %l4, %o1
323
324 /* Return from trap. */
325 ba,pt %xcc, rtrap_irq
326 nop
327
328sun4v_nonres_mondo_queue_empty:
329 retry
330
331sun4v_nonres_mondo_queue_full:
332 /* The queue is full, consolidate our damage by setting
333 * the head equal to the tail. We'll just trap again otherwise.
334 * Call C code to log the event.
335 */
336 mov INTRQ_NONRESUM_MONDO_HEAD, %g2
337 stxa %g4, [%g2] ASI_QUEUE
338 membar #Sync
339
340 rdpr %pil, %g2
341 wrpr %g0, 15, %pil
342 ba,pt %xcc, etrap_irq
343 rd %pc, %g7
344
345 call sun4v_nonresum_overflow
346 add %sp, PTREGS_OFF, %o0
347
348 ba,pt %xcc, rtrap_irq
349 nop