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