1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 21da177e4SLinus Torvalds/* 31da177e4SLinus Torvalds * linux/arch/arm/kernel/iwmmxt.S 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * XScale iWMMXt (Concan) context switching and handling 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Initial code: 81da177e4SLinus Torvalds * Copyright (c) 2003, Intel Corporation 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Full lazy switching support, optimizations and more, by Nicolas Pitre 111da177e4SLinus Torvalds* Copyright (c) 2003-2004, MontaVista Software, Inc. 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds#include <linux/linkage.h> 151da177e4SLinus Torvalds#include <asm/ptrace.h> 161da177e4SLinus Torvalds#include <asm/thread_info.h> 17e6ae744dSSam Ravnborg#include <asm/asm-offsets.h> 18431a84b1SCatalin Marinas#include <asm/assembler.h> 193c9f5708SJian Cai#include "iwmmxt.h" 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds#define MMX_WR0 (0x00) 221da177e4SLinus Torvalds#define MMX_WR1 (0x08) 231da177e4SLinus Torvalds#define MMX_WR2 (0x10) 241da177e4SLinus Torvalds#define MMX_WR3 (0x18) 251da177e4SLinus Torvalds#define MMX_WR4 (0x20) 261da177e4SLinus Torvalds#define MMX_WR5 (0x28) 271da177e4SLinus Torvalds#define MMX_WR6 (0x30) 281da177e4SLinus Torvalds#define MMX_WR7 (0x38) 291da177e4SLinus Torvalds#define MMX_WR8 (0x40) 301da177e4SLinus Torvalds#define MMX_WR9 (0x48) 311da177e4SLinus Torvalds#define MMX_WR10 (0x50) 321da177e4SLinus Torvalds#define MMX_WR11 (0x58) 331da177e4SLinus Torvalds#define MMX_WR12 (0x60) 341da177e4SLinus Torvalds#define MMX_WR13 (0x68) 351da177e4SLinus Torvalds#define MMX_WR14 (0x70) 361da177e4SLinus Torvalds#define MMX_WR15 (0x78) 371da177e4SLinus Torvalds#define MMX_WCSSF (0x80) 381da177e4SLinus Torvalds#define MMX_WCASF (0x84) 391da177e4SLinus Torvalds#define MMX_WCGR0 (0x88) 401da177e4SLinus Torvalds#define MMX_WCGR1 (0x8C) 411da177e4SLinus Torvalds#define MMX_WCGR2 (0x90) 421da177e4SLinus Torvalds#define MMX_WCGR3 (0x94) 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds#define MMX_SIZE (0x98) 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds .text 4713d1b957SArd Biesheuvel .arm 481da177e4SLinus Torvalds 49303d6da1SArd BiesheuvelENTRY(iwmmxt_undef_handler) 50303d6da1SArd Biesheuvel push {r9, r10, lr} 51303d6da1SArd Biesheuvel get_thread_info r10 52303d6da1SArd Biesheuvel mov r9, pc 53303d6da1SArd Biesheuvel b iwmmxt_task_enable 54303d6da1SArd Biesheuvel mov r0, #0 55303d6da1SArd Biesheuvel pop {r9, r10, pc} 56303d6da1SArd BiesheuvelENDPROC(iwmmxt_undef_handler) 57303d6da1SArd Biesheuvel 581da177e4SLinus Torvalds/* 591da177e4SLinus Torvalds * Lazy switching of Concan coprocessor context 601da177e4SLinus Torvalds * 61303d6da1SArd Biesheuvel * r0 = struct pt_regs pointer 621da177e4SLinus Torvalds * r10 = struct thread_info pointer 631da177e4SLinus Torvalds * r9 = ret_from_exception 641da177e4SLinus Torvalds * lr = undefined instr exit 651da177e4SLinus Torvalds * 661417a6b8SCatalin Marinas * called from prefetch exception handler with interrupts enabled 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds 691da177e4SLinus TorvaldsENTRY(iwmmxt_task_enable) 70431a84b1SCatalin Marinas inc_preempt_count r10, r3 711da177e4SLinus Torvalds 72*66689127SArd Biesheuvel mrc p15, 0, r2, c15, c1, 0 73ef6c8445SHaojian Zhuang @ CP0 and CP1 accessible? 74*66689127SArd Biesheuvel tst r2, #0x3 75431a84b1SCatalin Marinas bne 4f @ if so no business here 76ef6c8445SHaojian Zhuang @ enable access to CP0 and CP1 77*66689127SArd Biesheuvel orr r2, r2, #0x3 78*66689127SArd Biesheuvel mcr p15, 0, r2, c15, c1, 0 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds ldr r3, =concan_owner 81303d6da1SArd Biesheuvel ldr r2, [r0, #S_PC] @ current task pc value 821da177e4SLinus Torvalds ldr r1, [r3] @ get current Concan owner 831da177e4SLinus Torvalds sub r2, r2, #4 @ adjust pc back 84303d6da1SArd Biesheuvel str r2, [r0, #S_PC] 85303d6da1SArd Biesheuvel add r0, r10, #TI_IWMMXT_STATE @ get task Concan save area 86303d6da1SArd Biesheuvel str r0, [r3] @ this task now owns Concan regs 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds mrc p15, 0, r2, c2, c0, 0 891da177e4SLinus Torvalds mov r2, r2 @ cpwait 908cf2389bSSebastian Hesselbarth bl concan_save 911da177e4SLinus Torvalds 928cf2389bSSebastian Hesselbarth#ifdef CONFIG_PREEMPT_COUNT 938cf2389bSSebastian Hesselbarth get_thread_info r10 948cf2389bSSebastian Hesselbarth#endif 958cf2389bSSebastian Hesselbarth4: dec_preempt_count r10, r3 9671095615SRussell King ret r9 @ normal exit from exception 971da177e4SLinus Torvalds 981da177e4SLinus Torvaldsconcan_save: 991da177e4SLinus Torvalds 1008cf2389bSSebastian Hesselbarth teq r1, #0 @ test for last ownership 1018cf2389bSSebastian Hesselbarth beq concan_load @ no owner, skip save 1028cf2389bSSebastian Hesselbarth 1031da177e4SLinus Torvalds tmrc r2, wCon 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds @ CUP? wCx 1061da177e4SLinus Torvalds tst r2, #0x1 1071da177e4SLinus Torvalds beq 1f 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvaldsconcan_dump: 1101da177e4SLinus Torvalds 1113c9f5708SJian Cai wstrw wCSSF, r1, MMX_WCSSF 1123c9f5708SJian Cai wstrw wCASF, r1, MMX_WCASF 1133c9f5708SJian Cai wstrw wCGR0, r1, MMX_WCGR0 1143c9f5708SJian Cai wstrw wCGR1, r1, MMX_WCGR1 1153c9f5708SJian Cai wstrw wCGR2, r1, MMX_WCGR2 1163c9f5708SJian Cai wstrw wCGR3, r1, MMX_WCGR3 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds1: @ MUP? wRn 1191da177e4SLinus Torvalds tst r2, #0x2 1201da177e4SLinus Torvalds beq 2f 1211da177e4SLinus Torvalds 1223c9f5708SJian Cai wstrd wR0, r1, MMX_WR0 1233c9f5708SJian Cai wstrd wR1, r1, MMX_WR1 1243c9f5708SJian Cai wstrd wR2, r1, MMX_WR2 1253c9f5708SJian Cai wstrd wR3, r1, MMX_WR3 1263c9f5708SJian Cai wstrd wR4, r1, MMX_WR4 1273c9f5708SJian Cai wstrd wR5, r1, MMX_WR5 1283c9f5708SJian Cai wstrd wR6, r1, MMX_WR6 1293c9f5708SJian Cai wstrd wR7, r1, MMX_WR7 1303c9f5708SJian Cai wstrd wR8, r1, MMX_WR8 1313c9f5708SJian Cai wstrd wR9, r1, MMX_WR9 1323c9f5708SJian Cai wstrd wR10, r1, MMX_WR10 1333c9f5708SJian Cai wstrd wR11, r1, MMX_WR11 1343c9f5708SJian Cai wstrd wR12, r1, MMX_WR12 1353c9f5708SJian Cai wstrd wR13, r1, MMX_WR13 1363c9f5708SJian Cai wstrd wR14, r1, MMX_WR14 1373c9f5708SJian Cai wstrd wR15, r1, MMX_WR15 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds2: teq r0, #0 @ anything to load? 14071095615SRussell King reteq lr @ if not, return 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvaldsconcan_load: 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds @ Load wRn 1453c9f5708SJian Cai wldrd wR0, r0, MMX_WR0 1463c9f5708SJian Cai wldrd wR1, r0, MMX_WR1 1473c9f5708SJian Cai wldrd wR2, r0, MMX_WR2 1483c9f5708SJian Cai wldrd wR3, r0, MMX_WR3 1493c9f5708SJian Cai wldrd wR4, r0, MMX_WR4 1503c9f5708SJian Cai wldrd wR5, r0, MMX_WR5 1513c9f5708SJian Cai wldrd wR6, r0, MMX_WR6 1523c9f5708SJian Cai wldrd wR7, r0, MMX_WR7 1533c9f5708SJian Cai wldrd wR8, r0, MMX_WR8 1543c9f5708SJian Cai wldrd wR9, r0, MMX_WR9 1553c9f5708SJian Cai wldrd wR10, r0, MMX_WR10 1563c9f5708SJian Cai wldrd wR11, r0, MMX_WR11 1573c9f5708SJian Cai wldrd wR12, r0, MMX_WR12 1583c9f5708SJian Cai wldrd wR13, r0, MMX_WR13 1593c9f5708SJian Cai wldrd wR14, r0, MMX_WR14 1603c9f5708SJian Cai wldrd wR15, r0, MMX_WR15 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds @ Load wCx 1633c9f5708SJian Cai wldrw wCSSF, r0, MMX_WCSSF 1643c9f5708SJian Cai wldrw wCASF, r0, MMX_WCASF 1653c9f5708SJian Cai wldrw wCGR0, r0, MMX_WCGR0 1663c9f5708SJian Cai wldrw wCGR1, r0, MMX_WCGR1 1673c9f5708SJian Cai wldrw wCGR2, r0, MMX_WCGR2 1683c9f5708SJian Cai wldrw wCGR3, r0, MMX_WCGR3 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds @ clear CUP/MUP (only if r1 != 0) 1711da177e4SLinus Torvalds teq r1, #0 1721da177e4SLinus Torvalds mov r2, #0 17371095615SRussell King reteq lr 174431a84b1SCatalin Marinas 1758cf2389bSSebastian Hesselbarth tmcr wCon, r2 1766ebbf2ceSRussell King ret lr 1771da177e4SLinus Torvalds 17813d1b957SArd BiesheuvelENDPROC(iwmmxt_task_enable) 17913d1b957SArd Biesheuvel 1801da177e4SLinus Torvalds/* 1811da177e4SLinus Torvalds * Back up Concan regs to save area and disable access to them 1821da177e4SLinus Torvalds * (mainly for gdb or sleep mode usage) 1831da177e4SLinus Torvalds * 1841da177e4SLinus Torvalds * r0 = struct thread_info pointer of target task or NULL for any 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds 1871da177e4SLinus TorvaldsENTRY(iwmmxt_task_disable) 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds stmfd sp!, {r4, lr} 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds mrs ip, cpsr 1921da177e4SLinus Torvalds orr r2, ip, #PSR_I_BIT @ disable interrupts 1931da177e4SLinus Torvalds msr cpsr_c, r2 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds ldr r3, =concan_owner 1961da177e4SLinus Torvalds add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area 1971da177e4SLinus Torvalds ldr r1, [r3] @ get current Concan owner 1981da177e4SLinus Torvalds teq r1, #0 @ any current owner? 1991da177e4SLinus Torvalds beq 1f @ no: quit 2001da177e4SLinus Torvalds teq r0, #0 @ any owner? 2011da177e4SLinus Torvalds teqne r1, r2 @ or specified one? 2021da177e4SLinus Torvalds bne 1f @ no: quit 2031da177e4SLinus Torvalds 204ef6c8445SHaojian Zhuang @ enable access to CP0 and CP1 205*66689127SArd Biesheuvel mrc p15, 0, r4, c15, c1, 0 206*66689127SArd Biesheuvel orr r4, r4, #0x3 207*66689127SArd Biesheuvel mcr p15, 0, r4, c15, c1, 0 208ef6c8445SHaojian Zhuang 2091da177e4SLinus Torvalds mov r0, #0 @ nothing to load 2101da177e4SLinus Torvalds str r0, [r3] @ no more current owner 2111da177e4SLinus Torvalds mrc p15, 0, r2, c2, c0, 0 2121da177e4SLinus Torvalds mov r2, r2 @ cpwait 2131da177e4SLinus Torvalds bl concan_save 2141da177e4SLinus Torvalds 215ef6c8445SHaojian Zhuang @ disable access to CP0 and CP1 216*66689127SArd Biesheuvel bic r4, r4, #0x3 217*66689127SArd Biesheuvel mcr p15, 0, r4, c15, c1, 0 218ef6c8445SHaojian Zhuang 2191da177e4SLinus Torvalds mrc p15, 0, r2, c2, c0, 0 2201da177e4SLinus Torvalds mov r2, r2 @ cpwait 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds1: msr cpsr_c, ip @ restore interrupt mode 2231da177e4SLinus Torvalds ldmfd sp!, {r4, pc} 2241da177e4SLinus Torvalds 22513d1b957SArd BiesheuvelENDPROC(iwmmxt_task_disable) 22613d1b957SArd Biesheuvel 2271da177e4SLinus Torvalds/* 2281da177e4SLinus Torvalds * Copy Concan state to given memory address 2291da177e4SLinus Torvalds * 2301da177e4SLinus Torvalds * r0 = struct thread_info pointer of target task 2311da177e4SLinus Torvalds * r1 = memory address where to store Concan state 2321da177e4SLinus Torvalds * 2331da177e4SLinus Torvalds * this is called mainly in the creation of signal stack frames 2341da177e4SLinus Torvalds */ 2351da177e4SLinus Torvalds 2361da177e4SLinus TorvaldsENTRY(iwmmxt_task_copy) 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds mrs ip, cpsr 2391da177e4SLinus Torvalds orr r2, ip, #PSR_I_BIT @ disable interrupts 2401da177e4SLinus Torvalds msr cpsr_c, r2 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds ldr r3, =concan_owner 2431da177e4SLinus Torvalds add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area 2441da177e4SLinus Torvalds ldr r3, [r3] @ get current Concan owner 2451da177e4SLinus Torvalds teq r2, r3 @ does this task own it... 2461da177e4SLinus Torvalds beq 1f 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds @ current Concan values are in the task save area 2491da177e4SLinus Torvalds msr cpsr_c, ip @ restore interrupt mode 2501da177e4SLinus Torvalds mov r0, r1 2511da177e4SLinus Torvalds mov r1, r2 2521da177e4SLinus Torvalds mov r2, #MMX_SIZE 2531da177e4SLinus Torvalds b memcpy 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds1: @ this task owns Concan regs -- grab a copy from there 2561da177e4SLinus Torvalds mov r0, #0 @ nothing to load 2571da177e4SLinus Torvalds mov r2, #3 @ save all regs 2581da177e4SLinus Torvalds mov r3, lr @ preserve return address 2591da177e4SLinus Torvalds bl concan_dump 2601da177e4SLinus Torvalds msr cpsr_c, ip @ restore interrupt mode 2616ebbf2ceSRussell King ret r3 2621da177e4SLinus Torvalds 26313d1b957SArd BiesheuvelENDPROC(iwmmxt_task_copy) 26413d1b957SArd Biesheuvel 2651da177e4SLinus Torvalds/* 2661da177e4SLinus Torvalds * Restore Concan state from given memory address 2671da177e4SLinus Torvalds * 2681da177e4SLinus Torvalds * r0 = struct thread_info pointer of target task 2691da177e4SLinus Torvalds * r1 = memory address where to get Concan state from 2701da177e4SLinus Torvalds * 2711da177e4SLinus Torvalds * this is used to restore Concan state when unwinding a signal stack frame 2721da177e4SLinus Torvalds */ 2731da177e4SLinus Torvalds 2741da177e4SLinus TorvaldsENTRY(iwmmxt_task_restore) 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds mrs ip, cpsr 2771da177e4SLinus Torvalds orr r2, ip, #PSR_I_BIT @ disable interrupts 2781da177e4SLinus Torvalds msr cpsr_c, r2 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds ldr r3, =concan_owner 2811da177e4SLinus Torvalds add r2, r0, #TI_IWMMXT_STATE @ get task Concan save area 2821da177e4SLinus Torvalds ldr r3, [r3] @ get current Concan owner 2831da177e4SLinus Torvalds bic r2, r2, #0x7 @ 64-bit alignment 2841da177e4SLinus Torvalds teq r2, r3 @ does this task own it... 2851da177e4SLinus Torvalds beq 1f 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds @ this task doesn't own Concan regs -- use its save area 2881da177e4SLinus Torvalds msr cpsr_c, ip @ restore interrupt mode 2891da177e4SLinus Torvalds mov r0, r2 2901da177e4SLinus Torvalds mov r2, #MMX_SIZE 2911da177e4SLinus Torvalds b memcpy 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds1: @ this task owns Concan regs -- load them directly 2941da177e4SLinus Torvalds mov r0, r1 2951da177e4SLinus Torvalds mov r1, #0 @ don't clear CUP/MUP 2961da177e4SLinus Torvalds mov r3, lr @ preserve return address 2971da177e4SLinus Torvalds bl concan_load 2981da177e4SLinus Torvalds msr cpsr_c, ip @ restore interrupt mode 2996ebbf2ceSRussell King ret r3 3001da177e4SLinus Torvalds 30113d1b957SArd BiesheuvelENDPROC(iwmmxt_task_restore) 30213d1b957SArd Biesheuvel 3031da177e4SLinus Torvalds/* 3041da177e4SLinus Torvalds * Concan handling on task switch 3051da177e4SLinus Torvalds * 306ae95bfbbSLennert Buytenhek * r0 = next thread_info pointer 3071da177e4SLinus Torvalds * 308ae95bfbbSLennert Buytenhek * Called only from the iwmmxt notifier with task preemption disabled. 3091da177e4SLinus Torvalds */ 3101da177e4SLinus TorvaldsENTRY(iwmmxt_task_switch) 3111da177e4SLinus Torvalds 312*66689127SArd Biesheuvel mrc p15, 0, r1, c15, c1, 0 313ef6c8445SHaojian Zhuang @ CP0 and CP1 accessible? 314*66689127SArd Biesheuvel tst r1, #0x3 3151da177e4SLinus Torvalds bne 1f @ yes: block them for next task 3161da177e4SLinus Torvalds 317ae95bfbbSLennert Buytenhek ldr r2, =concan_owner 318ae95bfbbSLennert Buytenhek add r3, r0, #TI_IWMMXT_STATE @ get next task Concan save area 319ae95bfbbSLennert Buytenhek ldr r2, [r2] @ get current Concan owner 320ae95bfbbSLennert Buytenhek teq r2, r3 @ next task owns it? 3216ebbf2ceSRussell King retne lr @ no: leave Concan disabled 3221da177e4SLinus Torvalds 323392ba787SLennert Buytenhek1: @ flip Concan access 324*66689127SArd Biesheuvel eor r1, r1, #0x3 325*66689127SArd Biesheuvel mcr p15, 0, r1, c15, c1, 0 3261da177e4SLinus Torvalds 327ae95bfbbSLennert Buytenhek mrc p15, 0, r1, c2, c0, 0 328ae95bfbbSLennert Buytenhek sub pc, lr, r1, lsr #32 @ cpwait and return 3291da177e4SLinus Torvalds 33013d1b957SArd BiesheuvelENDPROC(iwmmxt_task_switch) 33113d1b957SArd Biesheuvel 3321da177e4SLinus Torvalds/* 3331da177e4SLinus Torvalds * Remove Concan ownership of given task 3341da177e4SLinus Torvalds * 3351da177e4SLinus Torvalds * r0 = struct thread_info pointer 3361da177e4SLinus Torvalds */ 3371da177e4SLinus TorvaldsENTRY(iwmmxt_task_release) 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds mrs r2, cpsr 3401da177e4SLinus Torvalds orr ip, r2, #PSR_I_BIT @ disable interrupts 3411da177e4SLinus Torvalds msr cpsr_c, ip 3421da177e4SLinus Torvalds ldr r3, =concan_owner 3431da177e4SLinus Torvalds add r0, r0, #TI_IWMMXT_STATE @ get task Concan save area 3441da177e4SLinus Torvalds ldr r1, [r3] @ get current Concan owner 3451da177e4SLinus Torvalds eors r0, r0, r1 @ if equal... 3461da177e4SLinus Torvalds streq r0, [r3] @ then clear ownership 3471da177e4SLinus Torvalds msr cpsr_c, r2 @ restore interrupts 3486ebbf2ceSRussell King ret lr 3491da177e4SLinus Torvalds 35013d1b957SArd BiesheuvelENDPROC(iwmmxt_task_release) 35113d1b957SArd Biesheuvel 3521da177e4SLinus Torvalds .data 3531abd3502SRussell King .align 2 3541da177e4SLinus Torvaldsconcan_owner: 3551da177e4SLinus Torvalds .word 0 3561da177e4SLinus Torvalds 357