root/arch/arm/kernel/iwmmxt.S

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

/* [<][>][^][v][top][bottom][index][help] */