1/* 2 * linux/arch/arm/kernel/iwmmxt.S 3 * 4 * XScale iWMMXt (Concan) context switching and handling 5 * 6 * Initial code: 7 * Copyright (c) 2003, Intel Corporation 8 * 9 * Full lazy switching support, optimizations and more, by Nicolas Pitre 10* Copyright (c) 2003-2004, MontaVista Software, Inc. 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License version 2 as 14 * published by the Free Software Foundation. 15 */ 16 17#include <linux/linkage.h> 18#include <asm/ptrace.h> 19#include <asm/thread_info.h> 20#include <asm/asm-offsets.h> 21 22#if defined(CONFIG_CPU_PJ4) || defined(CONFIG_CPU_PJ4B) 23#define PJ4(code...) code 24#define XSC(code...) 25#elif defined(CONFIG_CPU_MOHAWK) || \ 26 defined(CONFIG_CPU_XSC3) || \ 27 defined(CONFIG_CPU_XSCALE) 28#define PJ4(code...) 29#define XSC(code...) code 30#else 31#error "Unsupported iWMMXt architecture" 32#endif 33 34#define MMX_WR0 (0x00) 35#define MMX_WR1 (0x08) 36#define MMX_WR2 (0x10) 37#define MMX_WR3 (0x18) 38#define MMX_WR4 (0x20) 39#define MMX_WR5 (0x28) 40#define MMX_WR6 (0x30) 41#define MMX_WR7 (0x38) 42#define MMX_WR8 (0x40) 43#define MMX_WR9 (0x48) 44#define MMX_WR10 (0x50) 45#define MMX_WR11 (0x58) 46#define MMX_WR12 (0x60) 47#define MMX_WR13 (0x68) 48#define MMX_WR14 (0x70) 49#define MMX_WR15 (0x78) 50#define MMX_WCSSF (0x80) 51#define MMX_WCASF (0x84) 52#define MMX_WCGR0 (0x88) 53#define MMX_WCGR1 (0x8C) 54#define MMX_WCGR2 (0x90) 55#define MMX_WCGR3 (0x94) 56 57#define MMX_SIZE (0x98) 58 59 .text 60 61/* 62 * Lazy switching of Concan coprocessor context 63 * 64 * r10 = struct thread_info pointer 65 * r9 = ret_from_exception 66 * lr = undefined instr exit 67 * 68 * called from prefetch exception handler with interrupts disabled 69 */ 70 71ENTRY(iwmmxt_task_enable) 72 73 XSC(mrc p15, 0, r2, c15, c1, 0) 74 PJ4(mrc p15, 0, r2, c1, c0, 2) 75 @ CP0 and CP1 accessible? 76 XSC(tst r2, #0x3) 77 PJ4(tst r2, #0xf) 78 movne pc, lr @ if so no business here 79 @ enable access to CP0 and CP1 80 XSC(orr r2, r2, #0x3) 81 XSC(mcr p15, 0, r2, c15, c1, 0) 82 PJ4(orr r2, r2, #0xf) 83 PJ4(mcr p15, 0, r2, c1, c0, 2) 84 85 ldr r3, =concan_owner 86 add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area 87 ldr r2, [sp, #60] @ current task pc value 88 ldr r1, [r3] @ get current Concan owner 89 str r0, [r3] @ this task now owns Concan regs 90 sub r2, r2, #4 @ adjust pc back 91 str r2, [sp, #60] 92 93 mrc p15, 0, r2, c2, c0, 0 94 mov r2, r2 @ cpwait 95 96 teq r1, #0 @ test for last ownership 97 mov lr, r9 @ normal exit from exception 98 beq concan_load @ no owner, skip save 99 100concan_save: 101 102 tmrc r2, wCon 103 104 @ CUP? wCx 105 tst r2, #0x1 106 beq 1f 107 108concan_dump: 109 110 wstrw wCSSF, [r1, #MMX_WCSSF] 111 wstrw wCASF, [r1, #MMX_WCASF] 112 wstrw wCGR0, [r1, #MMX_WCGR0] 113 wstrw wCGR1, [r1, #MMX_WCGR1] 114 wstrw wCGR2, [r1, #MMX_WCGR2] 115 wstrw wCGR3, [r1, #MMX_WCGR3] 116 1171: @ MUP? wRn 118 tst r2, #0x2 119 beq 2f 120 121 wstrd wR0, [r1, #MMX_WR0] 122 wstrd wR1, [r1, #MMX_WR1] 123 wstrd wR2, [r1, #MMX_WR2] 124 wstrd wR3, [r1, #MMX_WR3] 125 wstrd wR4, [r1, #MMX_WR4] 126 wstrd wR5, [r1, #MMX_WR5] 127 wstrd wR6, [r1, #MMX_WR6] 128 wstrd wR7, [r1, #MMX_WR7] 129 wstrd wR8, [r1, #MMX_WR8] 130 wstrd wR9, [r1, #MMX_WR9] 131 wstrd wR10, [r1, #MMX_WR10] 132 wstrd wR11, [r1, #MMX_WR11] 133 wstrd wR12, [r1, #MMX_WR12] 134 wstrd wR13, [r1, #MMX_WR13] 135 wstrd wR14, [r1, #MMX_WR14] 136 wstrd wR15, [r1, #MMX_WR15] 137 1382: teq r0, #0 @ anything to load? 139 moveq pc, lr 140 141concan_load: 142 143 @ Load wRn 144 wldrd wR0, [r0, #MMX_WR0] 145 wldrd wR1, [r0, #MMX_WR1] 146 wldrd wR2, [r0, #MMX_WR2] 147 wldrd wR3, [r0, #MMX_WR3] 148 wldrd wR4, [r0, #MMX_WR4] 149 wldrd wR5, [r0, #MMX_WR5] 150 wldrd wR6, [r0, #MMX_WR6] 151 wldrd wR7, [r0, #MMX_WR7] 152 wldrd wR8, [r0, #MMX_WR8] 153 wldrd wR9, [r0, #MMX_WR9] 154 wldrd wR10, [r0, #MMX_WR10] 155 wldrd wR11, [r0, #MMX_WR11] 156 wldrd wR12, [r0, #MMX_WR12] 157 wldrd wR13, [r0, #MMX_WR13] 158 wldrd wR14, [r0, #MMX_WR14] 159 wldrd wR15, [r0, #MMX_WR15] 160 161 @ Load wCx 162 wldrw wCSSF, [r0, #MMX_WCSSF] 163 wldrw wCASF, [r0, #MMX_WCASF] 164 wldrw wCGR0, [r0, #MMX_WCGR0] 165 wldrw wCGR1, [r0, #MMX_WCGR1] 166 wldrw wCGR2, [r0, #MMX_WCGR2] 167 wldrw wCGR3, [r0, #MMX_WCGR3] 168 169 @ clear CUP/MUP (only if r1 != 0) 170 teq r1, #0 171 mov r2, #0 172 moveq pc, lr 173 tmcr wCon, r2 174 mov pc, lr 175 176/* 177 * Back up Concan regs to save area and disable access to them 178 * (mainly for gdb or sleep mode usage) 179 * 180 * r0 = struct thread_info pointer of target task or NULL for any 181 */ 182 183ENTRY(iwmmxt_task_disable) 184 185 stmfd sp!, {r4, lr} 186 187 mrs ip, cpsr 188 orr r2, ip, #PSR_I_BIT @ disable interrupts 189 msr cpsr_c, r2 190 191 ldr r3, =concan_owner 192 add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area 193 ldr r1, [r3] @ get current Concan owner 194 teq r1, #0 @ any current owner? 195 beq 1f @ no: quit 196 teq r0, #0 @ any owner? 197 teqne r1, r2 @ or specified one? 198 bne 1f @ no: quit 199 200 @ enable access to CP0 and CP1 201 XSC(mrc p15, 0, r4, c15, c1, 0) 202 XSC(orr r4, r4, #0x3) 203 XSC(mcr p15, 0, r4, c15, c1, 0) 204 PJ4(mrc p15, 0, r4, c1, c0, 2) 205 PJ4(orr r4, r4, #0xf) 206 PJ4(mcr p15, 0, r4, c1, c0, 2) 207 208 mov r0, #0 @ nothing to load 209 str r0, [r3] @ no more current owner 210 mrc p15, 0, r2, c2, c0, 0 211 mov r2, r2 @ cpwait 212 bl concan_save 213 214 @ disable access to CP0 and CP1 215 XSC(bic r4, r4, #0x3) 216 XSC(mcr p15, 0, r4, c15, c1, 0) 217 PJ4(bic r4, r4, #0xf) 218 PJ4(mcr p15, 0, r4, c1, c0, 2) 219 220 mrc p15, 0, r2, c2, c0, 0 221 mov r2, r2 @ cpwait 222 2231: msr cpsr_c, ip @ restore interrupt mode 224 ldmfd sp!, {r4, pc} 225 226/* 227 * Copy Concan state to given memory address 228 * 229 * r0 = struct thread_info pointer of target task 230 * r1 = memory address where to store Concan state 231 * 232 * this is called mainly in the creation of signal stack frames 233 */ 234 235ENTRY(iwmmxt_task_copy) 236 237 mrs ip, cpsr 238 orr r2, ip, #PSR_I_BIT @ disable interrupts 239 msr cpsr_c, r2 240 241 ldr r3, =concan_owner 242 add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area 243 ldr r3, [r3] @ get current Concan owner 244 teq r2, r3 @ does this task own it... 245 beq 1f 246 247 @ current Concan values are in the task save area 248 msr cpsr_c, ip @ restore interrupt mode 249 mov r0, r1 250 mov r1, r2 251 mov r2, #MMX_SIZE 252 b memcpy 253 2541: @ this task owns Concan regs -- grab a copy from there 255 mov r0, #0 @ nothing to load 256 mov r2, #3 @ save all regs 257 mov r3, lr @ preserve return address 258 bl concan_dump 259 msr cpsr_c, ip @ restore interrupt mode 260 mov pc, r3 261 262/* 263 * Restore Concan state from given memory address 264 * 265 * r0 = struct thread_info pointer of target task 266 * r1 = memory address where to get Concan state from 267 * 268 * this is used to restore Concan state when unwinding a signal stack frame 269 */ 270 271ENTRY(iwmmxt_task_restore) 272 273 mrs ip, cpsr 274 orr r2, ip, #PSR_I_BIT @ disable interrupts 275 msr cpsr_c, r2 276 277 ldr r3, =concan_owner 278 add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area 279 ldr r3, [r3] @ get current Concan owner 280 bic r2, r2, #0x7 @ 64-bit alignment 281 teq r2, r3 @ does this task own it... 282 beq 1f 283 284 @ this task doesn't own Concan regs -- use its save area 285 msr cpsr_c, ip @ restore interrupt mode 286 mov r0, r2 287 mov r2, #MMX_SIZE 288 b memcpy 289 2901: @ this task owns Concan regs -- load them directly 291 mov r0, r1 292 mov r1, #0 @ don't clear CUP/MUP 293 mov r3, lr @ preserve return address 294 bl concan_load 295 msr cpsr_c, ip @ restore interrupt mode 296 mov pc, r3 297 298/* 299 * Concan handling on task switch 300 * 301 * r0 = next thread_info pointer 302 * 303 * Called only from the iwmmxt notifier with task preemption disabled. 304 */ 305ENTRY(iwmmxt_task_switch) 306 307 XSC(mrc p15, 0, r1, c15, c1, 0) 308 PJ4(mrc p15, 0, r1, c1, c0, 2) 309 @ CP0 and CP1 accessible? 310 XSC(tst r1, #0x3) 311 PJ4(tst r1, #0xf) 312 bne 1f @ yes: block them for next task 313 314 ldr r2, =concan_owner 315 add r3, r0, #TI_IWMMXT_STATE @ get next task Concan save area 316 ldr r2, [r2] @ get current Concan owner 317 teq r2, r3 @ next task owns it? 318 movne pc, lr @ no: leave Concan disabled 319 3201: @ flip Concan access 321 XSC(eor r1, r1, #0x3) 322 XSC(mcr p15, 0, r1, c15, c1, 0) 323 PJ4(eor r1, r1, #0xf) 324 PJ4(mcr p15, 0, r1, c1, c0, 2) 325 326 mrc p15, 0, r1, c2, c0, 0 327 sub pc, lr, r1, lsr #32 @ cpwait and return 328 329/* 330 * Remove Concan ownership of given task 331 * 332 * r0 = struct thread_info pointer 333 */ 334ENTRY(iwmmxt_task_release) 335 336 mrs r2, cpsr 337 orr ip, r2, #PSR_I_BIT @ disable interrupts 338 msr cpsr_c, ip 339 ldr r3, =concan_owner 340 add r0, r0, #TI_IWMMXT_STATE @ get task Concan save area 341 ldr r1, [r3] @ get current Concan owner 342 eors r0, r0, r1 @ if equal... 343 streq r0, [r3] @ then clear ownership 344 msr cpsr_c, r2 @ restore interrupts 345 mov pc, lr 346 347 .data 348concan_owner: 349 .word 0 350 351