/*1* linux/arch/arm/kernel/iwmmxt.S2*3* XScale iWMMXt (Concan) context switching and handling4*5* Initial code:6* Copyright (c) 2003, Intel Corporation7*8* Full lazy switching support, optimizations and more, by Nicolas Pitre9* Copyright (c) 2003-2004, MontaVista Software, Inc.10*11* This program is free software; you can redistribute it and/or modify12* it under the terms of the GNU General Public License version 2 as13* published by the Free Software Foundation.14*/1516#include <linux/linkage.h>17#include <asm/ptrace.h>18#include <asm/thread_info.h>19#include <asm/asm-offsets.h>2021#if defined(CONFIG_CPU_PJ4)22#define PJ4(code...) code23#define XSC(code...)24#else25#define PJ4(code...)26#define XSC(code...) code27#endif2829#define MMX_WR0 (0x00)30#define MMX_WR1 (0x08)31#define MMX_WR2 (0x10)32#define MMX_WR3 (0x18)33#define MMX_WR4 (0x20)34#define MMX_WR5 (0x28)35#define MMX_WR6 (0x30)36#define MMX_WR7 (0x38)37#define MMX_WR8 (0x40)38#define MMX_WR9 (0x48)39#define MMX_WR10 (0x50)40#define MMX_WR11 (0x58)41#define MMX_WR12 (0x60)42#define MMX_WR13 (0x68)43#define MMX_WR14 (0x70)44#define MMX_WR15 (0x78)45#define MMX_WCSSF (0x80)46#define MMX_WCASF (0x84)47#define MMX_WCGR0 (0x88)48#define MMX_WCGR1 (0x8C)49#define MMX_WCGR2 (0x90)50#define MMX_WCGR3 (0x94)5152#define MMX_SIZE (0x98)5354.text5556/*57* Lazy switching of Concan coprocessor context58*59* r10 = struct thread_info pointer60* r9 = ret_from_exception61* lr = undefined instr exit62*63* called from prefetch exception handler with interrupts disabled64*/6566ENTRY(iwmmxt_task_enable)6768XSC(mrc p15, 0, r2, c15, c1, 0)69PJ4(mrc p15, 0, r2, c1, c0, 2)70@ CP0 and CP1 accessible?71XSC(tst r2, #0x3)72PJ4(tst r2, #0xf)73movne pc, lr @ if so no business here74@ enable access to CP0 and CP175XSC(orr r2, r2, #0x3)76XSC(mcr p15, 0, r2, c15, c1, 0)77PJ4(orr r2, r2, #0xf)78PJ4(mcr p15, 0, r2, c1, c0, 2)7980ldr r3, =concan_owner81add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area82ldr r2, [sp, #60] @ current task pc value83ldr r1, [r3] @ get current Concan owner84str r0, [r3] @ this task now owns Concan regs85sub r2, r2, #4 @ adjust pc back86str r2, [sp, #60]8788mrc p15, 0, r2, c2, c0, 089mov r2, r2 @ cpwait9091teq r1, #0 @ test for last ownership92mov lr, r9 @ normal exit from exception93beq concan_load @ no owner, skip save9495concan_save:9697tmrc r2, wCon9899@ CUP? wCx100tst r2, #0x1101beq 1f102103concan_dump:104105wstrw wCSSF, [r1, #MMX_WCSSF]106wstrw wCASF, [r1, #MMX_WCASF]107wstrw wCGR0, [r1, #MMX_WCGR0]108wstrw wCGR1, [r1, #MMX_WCGR1]109wstrw wCGR2, [r1, #MMX_WCGR2]110wstrw wCGR3, [r1, #MMX_WCGR3]1111121: @ MUP? wRn113tst r2, #0x2114beq 2f115116wstrd wR0, [r1, #MMX_WR0]117wstrd wR1, [r1, #MMX_WR1]118wstrd wR2, [r1, #MMX_WR2]119wstrd wR3, [r1, #MMX_WR3]120wstrd wR4, [r1, #MMX_WR4]121wstrd wR5, [r1, #MMX_WR5]122wstrd wR6, [r1, #MMX_WR6]123wstrd wR7, [r1, #MMX_WR7]124wstrd wR8, [r1, #MMX_WR8]125wstrd wR9, [r1, #MMX_WR9]126wstrd wR10, [r1, #MMX_WR10]127wstrd wR11, [r1, #MMX_WR11]128wstrd wR12, [r1, #MMX_WR12]129wstrd wR13, [r1, #MMX_WR13]130wstrd wR14, [r1, #MMX_WR14]131wstrd wR15, [r1, #MMX_WR15]1321332: teq r0, #0 @ anything to load?134moveq pc, lr135136concan_load:137138@ Load wRn139wldrd wR0, [r0, #MMX_WR0]140wldrd wR1, [r0, #MMX_WR1]141wldrd wR2, [r0, #MMX_WR2]142wldrd wR3, [r0, #MMX_WR3]143wldrd wR4, [r0, #MMX_WR4]144wldrd wR5, [r0, #MMX_WR5]145wldrd wR6, [r0, #MMX_WR6]146wldrd wR7, [r0, #MMX_WR7]147wldrd wR8, [r0, #MMX_WR8]148wldrd wR9, [r0, #MMX_WR9]149wldrd wR10, [r0, #MMX_WR10]150wldrd wR11, [r0, #MMX_WR11]151wldrd wR12, [r0, #MMX_WR12]152wldrd wR13, [r0, #MMX_WR13]153wldrd wR14, [r0, #MMX_WR14]154wldrd wR15, [r0, #MMX_WR15]155156@ Load wCx157wldrw wCSSF, [r0, #MMX_WCSSF]158wldrw wCASF, [r0, #MMX_WCASF]159wldrw wCGR0, [r0, #MMX_WCGR0]160wldrw wCGR1, [r0, #MMX_WCGR1]161wldrw wCGR2, [r0, #MMX_WCGR2]162wldrw wCGR3, [r0, #MMX_WCGR3]163164@ clear CUP/MUP (only if r1 != 0)165teq r1, #0166mov r2, #0167moveq pc, lr168tmcr wCon, r2169mov pc, lr170171/*172* Back up Concan regs to save area and disable access to them173* (mainly for gdb or sleep mode usage)174*175* r0 = struct thread_info pointer of target task or NULL for any176*/177178ENTRY(iwmmxt_task_disable)179180stmfd sp!, {r4, lr}181182mrs ip, cpsr183orr r2, ip, #PSR_I_BIT @ disable interrupts184msr cpsr_c, r2185186ldr r3, =concan_owner187add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area188ldr r1, [r3] @ get current Concan owner189teq r1, #0 @ any current owner?190beq 1f @ no: quit191teq r0, #0 @ any owner?192teqne r1, r2 @ or specified one?193bne 1f @ no: quit194195@ enable access to CP0 and CP1196XSC(mrc p15, 0, r4, c15, c1, 0)197XSC(orr r4, r4, #0xf)198XSC(mcr p15, 0, r4, c15, c1, 0)199PJ4(mrc p15, 0, r4, c1, c0, 2)200PJ4(orr r4, r4, #0x3)201PJ4(mcr p15, 0, r4, c1, c0, 2)202203mov r0, #0 @ nothing to load204str r0, [r3] @ no more current owner205mrc p15, 0, r2, c2, c0, 0206mov r2, r2 @ cpwait207bl concan_save208209@ disable access to CP0 and CP1210XSC(bic r4, r4, #0x3)211XSC(mcr p15, 0, r4, c15, c1, 0)212PJ4(bic r4, r4, #0xf)213PJ4(mcr p15, 0, r4, c1, c0, 2)214215mrc p15, 0, r2, c2, c0, 0216mov r2, r2 @ cpwait2172181: msr cpsr_c, ip @ restore interrupt mode219ldmfd sp!, {r4, pc}220221/*222* Copy Concan state to given memory address223*224* r0 = struct thread_info pointer of target task225* r1 = memory address where to store Concan state226*227* this is called mainly in the creation of signal stack frames228*/229230ENTRY(iwmmxt_task_copy)231232mrs ip, cpsr233orr r2, ip, #PSR_I_BIT @ disable interrupts234msr cpsr_c, r2235236ldr r3, =concan_owner237add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area238ldr r3, [r3] @ get current Concan owner239teq r2, r3 @ does this task own it...240beq 1f241242@ current Concan values are in the task save area243msr cpsr_c, ip @ restore interrupt mode244mov r0, r1245mov r1, r2246mov r2, #MMX_SIZE247b memcpy2482491: @ this task owns Concan regs -- grab a copy from there250mov r0, #0 @ nothing to load251mov r2, #3 @ save all regs252mov r3, lr @ preserve return address253bl concan_dump254msr cpsr_c, ip @ restore interrupt mode255mov pc, r3256257/*258* Restore Concan state from given memory address259*260* r0 = struct thread_info pointer of target task261* r1 = memory address where to get Concan state from262*263* this is used to restore Concan state when unwinding a signal stack frame264*/265266ENTRY(iwmmxt_task_restore)267268mrs ip, cpsr269orr r2, ip, #PSR_I_BIT @ disable interrupts270msr cpsr_c, r2271272ldr r3, =concan_owner273add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area274ldr r3, [r3] @ get current Concan owner275bic r2, r2, #0x7 @ 64-bit alignment276teq r2, r3 @ does this task own it...277beq 1f278279@ this task doesn't own Concan regs -- use its save area280msr cpsr_c, ip @ restore interrupt mode281mov r0, r2282mov r2, #MMX_SIZE283b memcpy2842851: @ this task owns Concan regs -- load them directly286mov r0, r1287mov r1, #0 @ don't clear CUP/MUP288mov r3, lr @ preserve return address289bl concan_load290msr cpsr_c, ip @ restore interrupt mode291mov pc, r3292293/*294* Concan handling on task switch295*296* r0 = next thread_info pointer297*298* Called only from the iwmmxt notifier with task preemption disabled.299*/300ENTRY(iwmmxt_task_switch)301302XSC(mrc p15, 0, r1, c15, c1, 0)303PJ4(mrc p15, 0, r1, c1, c0, 2)304@ CP0 and CP1 accessible?305XSC(tst r1, #0x3)306PJ4(tst r1, #0xf)307bne 1f @ yes: block them for next task308309ldr r2, =concan_owner310add r3, r0, #TI_IWMMXT_STATE @ get next task Concan save area311ldr r2, [r2] @ get current Concan owner312teq r2, r3 @ next task owns it?313movne pc, lr @ no: leave Concan disabled3143151: @ flip Conan access316XSC(eor r1, r1, #0x3)317XSC(mcr p15, 0, r1, c15, c1, 0)318PJ4(eor r1, r1, #0xf)319PJ4(mcr p15, 0, r1, c1, c0, 2)320321mrc p15, 0, r1, c2, c0, 0322sub pc, lr, r1, lsr #32 @ cpwait and return323324/*325* Remove Concan ownership of given task326*327* r0 = struct thread_info pointer328*/329ENTRY(iwmmxt_task_release)330331mrs r2, cpsr332orr ip, r2, #PSR_I_BIT @ disable interrupts333msr cpsr_c, ip334ldr r3, =concan_owner335add r0, r0, #TI_IWMMXT_STATE @ get task Concan save area336ldr r1, [r3] @ get current Concan owner337eors r0, r0, r1 @ if equal...338streq r0, [r3] @ then clear ownership339msr cpsr_c, r2 @ restore interrupts340mov pc, lr341342.data343concan_owner:344.word 0345346347348