Merge tag 'tag-chrome-platform-for-v5.12' of git://git.kernel.org/pub/scm/linux/kerne...
[linux-2.6-microblaze.git] / arch / xtensa / kernel / coprocessor.S
1 /*
2  * arch/xtensa/kernel/coprocessor.S
3  *
4  * Xtensa processor configuration-specific table of coprocessor and
5  * other custom register layout information.
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  *
11  * Copyright (C) 2003 - 2007 Tensilica Inc.
12  */
13
14
15 #include <linux/linkage.h>
16 #include <asm/asm-offsets.h>
17 #include <asm/asmmacro.h>
18 #include <asm/coprocessor.h>
19 #include <asm/current.h>
20 #include <asm/regs.h>
21
22 #if XTENSA_HAVE_COPROCESSORS
23
24 /*
25  * Macros for lazy context switch. 
26  */
27
28 #define SAVE_CP_REGS(x)                                                 \
29         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
30                 .align 4;                                               \
31         .Lsave_cp_regs_cp##x:                                           \
32                 xchal_cp##x##_store a2 a4 a5 a6 a7;                     \
33                 jx      a0;                                             \
34         .endif
35
36 #define SAVE_CP_REGS_TAB(x)                                             \
37         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
38                 .long .Lsave_cp_regs_cp##x;                             \
39         .else;                                                          \
40                 .long 0;                                                \
41         .endif;                                                         \
42         .long THREAD_XTREGS_CP##x
43
44
45 #define LOAD_CP_REGS(x)                                                 \
46         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
47                 .align 4;                                               \
48         .Lload_cp_regs_cp##x:                                           \
49                 xchal_cp##x##_load a2 a4 a5 a6 a7;                      \
50                 jx      a0;                                             \
51         .endif
52
53 #define LOAD_CP_REGS_TAB(x)                                             \
54         .if XTENSA_HAVE_COPROCESSOR(x);                                 \
55                 .long .Lload_cp_regs_cp##x;                             \
56         .else;                                                          \
57                 .long 0;                                                \
58         .endif;                                                         \
59         .long THREAD_XTREGS_CP##x
60
61         __XTENSA_HANDLER
62
63         SAVE_CP_REGS(0)
64         SAVE_CP_REGS(1)
65         SAVE_CP_REGS(2)
66         SAVE_CP_REGS(3)
67         SAVE_CP_REGS(4)
68         SAVE_CP_REGS(5)
69         SAVE_CP_REGS(6)
70         SAVE_CP_REGS(7)
71
72         LOAD_CP_REGS(0)
73         LOAD_CP_REGS(1)
74         LOAD_CP_REGS(2)
75         LOAD_CP_REGS(3)
76         LOAD_CP_REGS(4)
77         LOAD_CP_REGS(5)
78         LOAD_CP_REGS(6)
79         LOAD_CP_REGS(7)
80
81         .align 4
82 .Lsave_cp_regs_jump_table:
83         SAVE_CP_REGS_TAB(0)
84         SAVE_CP_REGS_TAB(1)
85         SAVE_CP_REGS_TAB(2)
86         SAVE_CP_REGS_TAB(3)
87         SAVE_CP_REGS_TAB(4)
88         SAVE_CP_REGS_TAB(5)
89         SAVE_CP_REGS_TAB(6)
90         SAVE_CP_REGS_TAB(7)
91
92 .Lload_cp_regs_jump_table:
93         LOAD_CP_REGS_TAB(0)
94         LOAD_CP_REGS_TAB(1)
95         LOAD_CP_REGS_TAB(2)
96         LOAD_CP_REGS_TAB(3)
97         LOAD_CP_REGS_TAB(4)
98         LOAD_CP_REGS_TAB(5)
99         LOAD_CP_REGS_TAB(6)
100         LOAD_CP_REGS_TAB(7)
101
102 /*
103  * coprocessor_flush(struct thread_info*, index)
104  *                             a2        a3
105  *
106  * Save coprocessor registers for coprocessor 'index'.
107  * The register values are saved to or loaded from the coprocessor area 
108  * inside the task_info structure.
109  *
110  * Note that this function doesn't update the coprocessor_owner information!
111  *
112  */
113
114 ENTRY(coprocessor_flush)
115
116         /* reserve 4 bytes on stack to save a0 */
117         abi_entry(4)
118
119         s32i    a0, a1, 0
120         movi    a0, .Lsave_cp_regs_jump_table
121         addx8   a3, a3, a0
122         l32i    a4, a3, 4
123         l32i    a3, a3, 0
124         add     a2, a2, a4
125         beqz    a3, 1f
126         callx0  a3
127 1:      l32i    a0, a1, 0
128
129         abi_ret(4)
130
131 ENDPROC(coprocessor_flush)
132
133 /*
134  * Entry condition:
135  *
136  *   a0:        trashed, original value saved on stack (PT_AREG0)
137  *   a1:        a1
138  *   a2:        new stack pointer, original in DEPC
139  *   a3:        a3
140  *   depc:      a2, original value saved on stack (PT_DEPC)
141  *   excsave_1: dispatch table
142  *
143  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
144  *           <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
145  */
146
147 ENTRY(fast_coprocessor)
148
149         /* Save remaining registers a1-a3 and SAR */
150
151         s32i    a3, a2, PT_AREG3
152         rsr     a3, sar
153         s32i    a1, a2, PT_AREG1
154         s32i    a3, a2, PT_SAR
155         mov     a1, a2
156         rsr     a2, depc
157         s32i    a2, a1, PT_AREG2
158
159         /*
160          * The hal macros require up to 4 temporary registers. We use a3..a6.
161          */
162
163         s32i    a4, a1, PT_AREG4
164         s32i    a5, a1, PT_AREG5
165         s32i    a6, a1, PT_AREG6
166
167         /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
168
169         rsr     a3, exccause
170         addi    a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
171
172         /* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/
173
174         ssl     a3                      # SAR: 32 - coprocessor_number
175         movi    a2, 1
176         rsr     a0, cpenable
177         sll     a2, a2
178         or      a0, a0, a2
179         wsr     a0, cpenable
180         rsync
181
182         /* Retrieve previous owner. (a3 still holds CP number) */
183
184         movi    a0, coprocessor_owner   # list of owners
185         addx4   a0, a3, a0              # entry for CP
186         l32i    a4, a0, 0
187
188         beqz    a4, 1f                  # skip 'save' if no previous owner
189
190         /* Disable coprocessor for previous owner. (a2 = 1 << CP number) */
191
192         l32i    a5, a4, THREAD_CPENABLE
193         xor     a5, a5, a2              # (1 << cp-id) still in a2
194         s32i    a5, a4, THREAD_CPENABLE
195
196         /*
197          * Get context save area and 'call' save routine. 
198          * (a4 still holds previous owner (thread_info), a3 CP number)
199          */
200
201         movi    a5, .Lsave_cp_regs_jump_table
202         movi    a0, 2f                  # a0: 'return' address
203         addx8   a3, a3, a5              # a3: coprocessor number
204         l32i    a2, a3, 4               # a2: xtregs offset
205         l32i    a3, a3, 0               # a3: jump address
206         add     a2, a2, a4
207         jx      a3
208
209         /* Note that only a0 and a1 were preserved. */
210
211 2:      rsr     a3, exccause
212         addi    a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
213         movi    a0, coprocessor_owner
214         addx4   a0, a3, a0
215
216         /* Set new 'owner' (a0 points to the CP owner, a3 contains the CP nr) */
217
218 1:      GET_THREAD_INFO (a4, a1)
219         s32i    a4, a0, 0
220
221         /* Get context save area and 'call' load routine. */
222
223         movi    a5, .Lload_cp_regs_jump_table
224         movi    a0, 1f
225         addx8   a3, a3, a5
226         l32i    a2, a3, 4               # a2: xtregs offset
227         l32i    a3, a3, 0               # a3: jump address
228         add     a2, a2, a4
229         jx      a3
230
231         /* Restore all registers and return from exception handler. */
232
233 1:      l32i    a6, a1, PT_AREG6
234         l32i    a5, a1, PT_AREG5
235         l32i    a4, a1, PT_AREG4
236
237         l32i    a0, a1, PT_SAR
238         l32i    a3, a1, PT_AREG3
239         l32i    a2, a1, PT_AREG2
240         wsr     a0, sar
241         l32i    a0, a1, PT_AREG0
242         l32i    a1, a1, PT_AREG1
243
244         rfe
245
246 ENDPROC(fast_coprocessor)
247
248         .data
249
250 ENTRY(coprocessor_owner)
251
252         .fill XCHAL_CP_MAX, 4, 0
253
254 END(coprocessor_owner)
255
256 #endif /* XTENSA_HAVE_COPROCESSORS */