[SPARC64]: Sun4v interrupt handling.
[linux-2.6/openmoko-kernel/knife-kernel.git] / arch / sparc64 / kernel / sun4v_ivec.S
blobd9d442017d3dc70e60048a560a86bd927f46ee0c
1 /* sun4v_ivec.S: Sun4v interrupt vector handling.
2  *
3  * Copyright (C) 2006 <davem@davemloft.net>
4  */
6 #include <asm/cpudata.h>
7 #include <asm/intr_queue.h>
9         .text
10         .align  32
12 sun4v_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
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
31         /* Get CPU mondo queue base phys address into %g7.  */
32         ldx     [%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
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
51         /* Update queue head pointer.  */
52         sethi   %hi(8192 - 1), %g4
53         or      %g4, %lo(8192 - 1), %g4
54         and     %g2, %g4, %g2
56         mov     INTRQ_CPU_MONDO_HEAD, %g4
57         stxa    %g2, [%g4] ASI_QUEUE
58         membar  #Sync
60         jmpl    %g3, %g0
61          nop
63 sun4v_cpu_mondo_queue_empty:
64         retry
66 sun4v_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
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
83         /* Get DEV mondo queue base phys address into %g5.  */
84         ldx     [%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5
86         /* Load IVEC into %g3.  */
87         ldxa    [%g5 + %g2] ASI_PHYS_USE_EC, %g3
88         add     %g2, 0x40, %g2
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          */
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
102         mov     INTRQ_DEVICE_MONDO_HEAD, %g4
103         stxa    %g2, [%g4] ASI_QUEUE
104         membar  #Sync
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
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
118         /* Load IRQ %pil into %g5.  */
119         ldub    [%g4 + 0x04], %g5
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 */
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
132 sun4v_dev_mondo_queue_empty:
133         retry
135 sun4v_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
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
152         /* Get RES mondo queue base phys address into %g5.  */
153         ldx     [%g3 + TRAP_PER_CPU_RESUM_MONDO_PA], %g5
155         /* Get RES kernel buffer base phys address into %g7.  */
156         ldx     [%g3 + TRAP_PER_CPU_RESUM_KBUF_PA], %g7
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
163         /* Remember this entry's offset in %g1.  */
164         mov     %g2, %g1
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
192         /* Update queue head pointer.  */
193         sethi   %hi(8192 - 1), %g4
194         or      %g4, %lo(8192 - 1), %g4
195         and     %g2, %g4, %g2
197         mov     INTRQ_RESUM_MONDO_HEAD, %g4
198         stxa    %g2, [%g4] ASI_QUEUE
199         membar  #Sync
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
211         /* Log the event.  */
212         add     %sp, PTREGS_OFF, %o0
213         call    sun4v_resum_error
214          mov    %l4, %o1
216         /* Return from trap.  */
217         ba,pt   %xcc, rtrap_irq
218          nop
220 sun4v_res_mondo_queue_empty:
221         retry
223 sun4v_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
232         rdpr    %pil, %g2
233         wrpr    %g0, 15, %pil
234         ba,pt   %xcc, etrap_irq
235          rd     %pc, %g7
237         call    sun4v_resum_overflow
238          add    %sp, PTREGS_OFF, %o0
240         ba,pt   %xcc, rtrap_irq
241          nop
243 sun4v_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
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
260         /* Get RES mondo queue base phys address into %g5.  */
261         ldx     [%g3 + TRAP_PER_CPU_NONRESUM_MONDO_PA], %g5
263         /* Get RES kernel buffer base phys address into %g7.  */
264         ldx     [%g3 + TRAP_PER_CPU_NONRESUM_KBUF_PA], %g7
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
271         /* Remember this entry's offset in %g1.  */
272         mov     %g2, %g1
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
300         /* Update queue head pointer.  */
301         sethi   %hi(8192 - 1), %g4
302         or      %g4, %lo(8192 - 1), %g4
303         and     %g2, %g4, %g2
305         mov     INTRQ_NONRESUM_MONDO_HEAD, %g4
306         stxa    %g2, [%g4] ASI_QUEUE
307         membar  #Sync
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
319         /* Log the event.  */
320         add     %sp, PTREGS_OFF, %o0
321         call    sun4v_nonresum_error
322          mov    %l4, %o1
324         /* Return from trap.  */
325         ba,pt   %xcc, rtrap_irq
326          nop
328 sun4v_nonres_mondo_queue_empty:
329         retry
331 sun4v_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
340         rdpr    %pil, %g2
341         wrpr    %g0, 15, %pil
342         ba,pt   %xcc, etrap_irq
343          rd     %pc, %g7
345         call    sun4v_nonresum_overflow
346          add    %sp, PTREGS_OFF, %o0
348         ba,pt   %xcc, rtrap_irq
349          nop