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