carl9170: Update to latest upstream
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / athos / src / xtos / int-medpri-dispatcher.S
1 // Medium-Priority Interrupt Dispatcher Template
2 // $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/int-medpri-dispatcher.S#4 $
3
4 // Copyright (c) 2004-2010 Tensilica Inc.
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included
15 // in all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 //
26 // By default, this file is included by inth-template.S .
27 // The default Makefile defines _INTERRUPT_LEVEL when assembling
28 // inth-template.S for each medium and high priority interrupt level.
29 //
30 // To use this template file, define a macro called _INTERRUPT_LEVEL
31 // to be the interrupt priority level of the vector, then include this file.
32
33
34 #include <xtensa/coreasm.h>
35 #include "xtos-internal.h"
36
37
38 #if XCHAL_HAVE_INTERRUPTS
39
40 #define INTERRUPT_MASK          XCHAL_INTLEVEL_MASK(_INTERRUPT_LEVEL)
41 #define SINGLE_INTERRUPT        ((INTERRUPT_MASK & (INTERRUPT_MASK - 1)) == 0)
42 #define SINGLE_INT_NUM          XCHAL_INTLEVEL_NUM(_INTERRUPT_LEVEL)
43
44
45 //  Strict non-preemptive prioritization
46
47
48         .text
49         .align  4
50         .global LABEL(_Level,FromVector)
51 LABEL(_Level,FromVector):
52
53 /* Allocate an exception stack frame, save a2, a4, and a5, and fix PS as:
54  *
55  *   if not Call0 ABI
56  *      - enable windowing for 'entry' (ps.woe=1, ps.excm=0)
57  *      - setup ps.callinc to simulate call4
58  *   endif
59  *      - preserve user mode
60  *      - mask all interrupts at EXCM_LEVEL and lower
61  *
62  * Then deallocate the stack, 'rsync' for the write to PS, then use
63  * 'entry' to re-allocate the stack frame and rotate the register
64  * window (like a call4, preserving a0..a3). */
65
66 #if HAVE_XSR
67         xsr     a2, EXCSAVE_LEVEL
68 #else
69         rsr     a2, EXCSAVE_LEVEL
70 #endif
71         addi    a1, a1, -ESF_TOTALSIZE
72         s32i    a2, a1, UEXC_a2
73 #ifdef __XTENSA_CALL0_ABI__
74         movi    a2, PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)
75 #else
76         movi    a2, PS_WOE|PS_CALLINC(1)|PS_UM|PS_INTLEVEL(XCHAL_EXCM_LEVEL)
77 #endif
78         s32i    a4, a1, UEXC_a4
79         s32i    a5, a1, UEXC_a5
80         wsr     a2, PS
81         rsync
82
83 #ifdef __XTENSA_CALL0_ABI__
84         s32i    a0, a1, UEXC_a0
85         s32i    a3, a1, UEXC_a3
86         s32i    a6, a1, UEXC_a6
87         s32i    a7, a1, UEXC_a7
88         s32i    a8, a1, UEXC_a8
89         s32i    a9, a1, UEXC_a9
90         s32i    a10, a1, UEXC_a10
91         s32i    a11, a1, UEXC_a11
92         s32i    a12, a1, UEXC_a12
93         s32i    a13, a1, UEXC_a13
94         s32i    a14, a1, UEXC_a14
95         s32i    a15, a1, UEXC_a15
96         movi    a0, 0                   /* terminate stack frames */
97 #  if XTOS_DEBUG_PC
98         // TODO: setup return PC for call traceback through interrupt dispatch
99 #  endif
100 #else
101 #  if XTOS_CNEST
102         l32i    a2, a1, ESF_TOTALSIZE-20        // save nested-C-func call-chain ptr
103 #  endif
104         addi    a1, a1, ESF_TOTALSIZE
105 #  if XTOS_DEBUG_PC
106         rsr     a4, EPC+_INTERRUPT_LEVEL // [for debug] get return PC
107         movi    a5, 0xC0000000          // [for debug] setup call size...
108         or      a4, a5, a4              // [for debug] set upper two bits of return PC
109         addx2   a4, a5, a4              // [for debug] clear upper bit
110 #  else
111         movi    a4, 0                   /* terminate stack frames, overflow check */
112 #  endif
113         _entry  a1, ESF_TOTALSIZE
114 #endif
115
116 /* Reset the interrupt level to mask all interrupts at the current
117  * priority level and lower.  Note the current priority level may be
118  * less than or equal to EXCM_LEVEL. */
119
120         rsil    a15, _INTERRUPT_LEVEL
121
122 #if SINGLE_INTERRUPT  /* if only one interrupt at this priority level... */
123
124 /* Preserve the SAR, loop, and MAC16 regs.  Also, clear the interrupt. */
125
126         rsr     a14, SAR
127         movi    a12, INTERRUPT_MASK
128         s32i    a14, a1, UEXC_sar
129         wsr     a12, INTCLEAR   // clear if edge-trig or s/w or wr/err (else no effect)
130         save_loops_mac16        a1, a13, a14
131
132 /* Load the handler from the table, initialize two args (interrupt
133  * number and exception stack frame), then call the interrupt handler.
134  * Note: The callx12 preserves the original user task's a4..a15.*/
135
136         movi    a12, _xtos_interrupt_table +  MAPINT(SINGLE_INT_NUM)*XIE_SIZE
137         l32i    a13, a12, XIE_HANDLER
138 # ifdef __XTENSA_CALL0_ABI__
139         l32i    a2, a12, XIE_ARG
140         mov     a3, a1
141         callx0  a13
142 # else
143         l32i    a14, a12, XIE_ARG
144         mov     a15, a1
145         callx12 a13
146 # endif
147
148 #else /* > 1 interrupts at this priority level */
149
150 /* Get bit list of pending interrupts at the current interrupt priority level.
151  * If bit list is empty, interrupt is spurious (can happen if a
152  * genuine interrupt brings control this direction, but the interrupt
153  * goes away before we read the INTERRUPT register).  Also save off
154  * sar, loops, and mac16 registers. */
155
156         rsr     a15, INTERRUPT
157         rsr     a12, INTENABLE
158         movi    a13, INTERRUPT_MASK
159         and     a15, a15, a12
160         and     a15, a15, a13
161         rsr     a14, SAR
162         _beqz   a15, LABEL(spurious,int)
163         s32i    a14, a1, UEXC_sar
164         save_loops_mac16        a1, a13, a14
165
166 /* Loop to handle all pending interrupts. */
167
168 LABEL(.L1,_loop0):
169         neg     a12, a15
170         and     a12, a12, a15
171         wsr     a12, INTCLEAR   // clear if edge-trig or s/w or wr/err (else no effect)
172         movi    a13, _xtos_interrupt_table
173         find_ms_setbit  a15, a12, a14, 0
174         mapint  a15
175         addx8   a12, a15, a13
176         l32i    a13, a12, XIE_HANDLER
177 # ifdef __XTENSA_CALL0_ABI__
178         l32i    a2, a12, XIE_ARG
179         mov     a3, a1
180         callx0  a13
181 # else
182         l32i    a14, a12, XIE_ARG
183         mov     a15, a1
184         callx12 a13
185 # endif
186         rsr     a15, INTERRUPT
187         rsr     a12, INTENABLE
188         movi    a13, INTERRUPT_MASK
189         and     a15, a15, a12
190         and     a15, a15, a13
191         _bnez   a15, LABEL(.L1,_loop0)
192
193 #endif /* SINGLE_INTERRUPT */
194
195 /* Restore everything, and return. */
196
197         restore_loops_mac16     a1, a13, a14, a15
198         l32i    a14, a1, UEXC_sar
199 LABEL(spurious,int):
200
201 #ifdef __XTENSA_CALL0_ABI__
202         wsr     a14, SAR
203         l32i    a0, a1, UEXC_a0
204         l32i    a2, a1, UEXC_a2
205         l32i    a3, a1, UEXC_a3
206         l32i    a4, a1, UEXC_a4
207         l32i    a5, a1, UEXC_a5
208         l32i    a6, a1, UEXC_a6
209         l32i    a7, a1, UEXC_a7
210         l32i    a8, a1, UEXC_a8
211         l32i    a9, a1, UEXC_a9
212         l32i    a10, a1, UEXC_a10
213         l32i    a11, a1, UEXC_a11
214         l32i    a12, a1, UEXC_a12
215         l32i    a13, a1, UEXC_a13
216         l32i    a14, a1, UEXC_a14
217         l32i    a15, a1, UEXC_a15
218         addi    a1, a1, ESF_TOTALSIZE   // restore sp
219         rfi     _INTERRUPT_LEVEL
220
221 #else /* windowed ABI: */
222
223         movi    a0, LABEL(return,from_exc)
224         movi    a13, 0xC0000000
225         wsr     a14, SAR
226         or      a0, a0, a13
227         addx2   a0, a13, a0
228 # if _INTERRUPT_LEVEL < XCHAL_EXCM_LEVEL
229 /* Raise the interrupt mask before
230  * returning to avoid a race condition where we deallocate the
231  * exception stack frame but still have more register values to
232  * restore from it. */
233         rsil    a14, XCHAL_EXCM_LEVEL
234 # endif
235         retw
236 LABEL(return,from_exc):
237 # if XTOS_CNEST
238         s32i    a2, a5, ESF_TOTALSIZE-20        // restore nested-C-func call-chain ptr
239 # endif
240         l32i    a2, a5, UEXC_a2
241         l32i    a4, a5, UEXC_a4
242         l32i    a5, a5, UEXC_a5
243         rfi     _INTERRUPT_LEVEL
244 #endif /* windowed ABI */
245
246         .size   LABEL(_Level,FromVector), . - LABEL(_Level,FromVector)
247
248         //  This symbol exists solely for the purpose of being able to pull-in this
249         //  dispatcher using _xtos_dispatch_level<n>() routines with the tiny-rt LSP:
250         .global LABEL(_Level,HandlerLabel)
251         .set LABEL(_Level,HandlerLabel), 0
252
253 #endif /* XCHAL_HAVE_INTERRUPT */
254