/**************************************************************************** * arch/xtensa/src/common/xtensa_coproc.S * * Adapted from use in NuttX by: * * Copyright (C) 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Derives from logic originally provided by Cadence Design Systems Inc. * * Copyright (c) 2006-2015 Cadence Design Systems Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************/ .file "xtensa_coproc.S" /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include "xtensa_abi.h" #if XCHAL_CP_NUM > 0 /**************************************************************************** * Public Data ****************************************************************************/ .section .rodata, "a" /* Offset to CP n save area in thread's CP save area. */ .global _xtensa_coproc_saoffsets .type _xtensa_coproc_saoffsets, @object .align 16 /* Minimize crossing cache boundaries */ _xtensa_coproc_saoffsets: .word XTENSA_CP0_SA, XTENSA_CP1_SA, XTENSA_CP2_SA, XTENSA_CP3_SA .word XTENSA_CP4_SA, XTENSA_CP5_SA, XTENSA_CP6_SA, XTENSA_CP7_SA .size _xtensa_coproc_saoffsets, . - _xtensa_coproc_saoffsets /**************************************************************************** * Public Functions ****************************************************************************/ .text /**************************************************************************** * Name: _xtensa_coproc_savestate * * Description: * If there is a current thread and it has a coprocessor state save area, * then save all callee-saved state into this area. This function is * called from the solicited context switch handler. It calls a system- * specific function to get the coprocessor save area base address. * * It is also called from xtensa_coproc_savestate() for synchronous * context switches. xtensa_coproc_savestate() is simply a C wrapper * around the assembly language call to _xtensa_coproc_savestate. * * Entry Conditions: * - A2 holds the address of the co-processor state save area * - The thread being switched out is still the current thread. * - CPENABLE state reflects which coprocessors are active. * - Registers have been saved/spilled already. * * Exit conditions: * - All necessary CP callee-saved state has been saved. * - Registers a2-a7, a13-a15 have been trashed. * * Must be called from assembly code only, using CALL0. * ****************************************************************************/ .global _xtensa_coproc_savestate .type _xtensa_coproc_savestate, @function .align 4 .literal_position .align 4 _xtensa_coproc_savestate: /* Move the address of the thread state save area to R15 */ mov a15, a2 /* A15 is now the address of the save area */ /* CPENABLE should show which CPs are enabled. */ rsr a2, CPENABLE /* a2 = which CPs are enabled */ beqz a2, .Ldone1 /* Quick exit if none */ s16i a2, a15, XTENSA_CPSTORED /* Save mask of CPs being stored */ movi a13, _xtensa_coproc_saoffsets /* Array of CP save offsets */ l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */ #if XCHAL_CP0_SA_SIZE > 0 bbci.l a2, 0, 2f /* CP 0 not enabled */ l32i a14, a13, 0 /* a14 = _xtensa_coproc_saoffsets[0] */ add a3, a14, a15 /* a3 = save area for CP 0 */ xchal_cp0_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP1_SA_SIZE > 0 bbci.l a2, 1, 2f /* CP 1 not enabled */ l32i a14, a13, 4 /* a14 = _xtensa_coproc_saoffsets[1] */ add a3, a14, a15 /* a3 = save area for CP 1 */ xchal_cp1_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP2_SA_SIZE > 0 bbci.l a2, 2, 2f l32i a14, a13, 8 add a3, a14, a15 xchal_cp2_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP3_SA_SIZE > 0 bbci.l a2, 3, 2f l32i a14, a13, 12 add a3, a14, a15 xchal_cp3store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP4_SA_SIZE > 0 bbci.l a2, 4, 2f l32i a14, a13, 16 add a3, a14, a15 xchal_cp4store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP5_SA_SIZE > 0 bbci.l a2, 5, 2f l32i a14, a13, 20 add a3, a14, a15 xchal_cp5store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP6_SA_SIZE > 0 bbci.l a2, 6, 2f l32i a14, a13, 24 add a3, a14, a15 xchal_cp6store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP7_SA_SIZE > 0 bbci.l a2, 7, 2f l32i a14, a13, 28 add a3, a14, a15 xchal_cp7store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif .Ldone1: ret .size _xtensa_coproc_savestate, . - _xtensa_coproc_savestate /**************************************************************************** * Name: xtensa_coproc_savestate * * Description: * If there is a current thread and it has a coprocessor state save area, * then save all callee-saved state into this area. xtensa_coproc_savestate() * is simply a C wrapper around the assembly language call to * _xtensa_coproc_savestate. * * Input Parameters: * A2 - Address of co-processor save area * * Returned Value: * None * * Assumptions: * Called with interrupts disabled. * ****************************************************************************/ .global xtensa_coproc_savestate .type xtensa_coproc_savestate, @function .align 4 .literal_position .align 4 xtensa_coproc_savestate: #ifdef __XTENSA_CALL0_ABI__ /* Need to preserve a8-11. _xtensa_coproc_savestate modifies a2-a7, * a13-a15. a12-a15 are callee saved registers so a13-a14 must be * preserved. */ ENTRY(16) s32i a13, sp, LOCAL_OFFSET(1) /* Save clobbered registers */ s32i a14, sp, LOCAL_OFFSET(2) s32i a15, sp, LOCAL_OFFSET(3) /* Call _xtensa_coproc_savestate() with A2=address of co-processor * save area. */ call0 _xtensa_coproc_savestate /* Restore a13-15 and return */ l32i a13, sp, LOCAL_OFFSET(1) /* Restore clobbered registers */ l32i a14, sp, LOCAL_OFFSET(2) l32i a15, sp, LOCAL_OFFSET(3) RET(16) #else /* Need to preserve a8-15. _xtensa_coproc_savestate modifies a2-a7, * a13-a15. So a13-a15 may need to be preserved. */ ENTRY(32 /*16*/) /* REVISIT: Why 32? */ s32i a0, sp, LOCAL_OFFSET(1) /* Save return address */ /* Call _xtensa_coproc_savestate() with A2=address of co-processor * save area. */ call0 _xtensa_coproc_savestate /* Restore a0 and return */ l32i a0, sp, LOCAL_OFFSET(1) /* Recover return address */ RET(32 /*16*/) /* REVISIT: Why 32? */ #endif .size xtensa_coproc_savestate, . - xtensa_coproc_savestate /**************************************************************************** * Name: _xtensa_coproc_restorestate * * Description: * Restore any callee-saved coprocessor state for the incoming thread. * This function is called from coprocessor exception handling, when * giving ownership to a thread that solicited a context switch earlier. * It calls a system-specific function to get the coprocessor save area * base address. * * It is also called from xtensa_coproc_restorestate() for synchronous * context switches. xtensa_coproc_restorestate() is simply a C wrapper * around the assembly language call to _xtensa_coproc_restorestate. * * Entry Conditions: * - A2 holds the address of the co-processor state save area * - The incoming thread is set as the current thread. * * Exit conditions: * - All necessary CP callee-saved state has been restored. * - CPENABLE - Set up correctly for the current thread. * - Registers a2-a7, a13-a15 have been trashed. * * Must be called from assembly code only, using CALL0. * ****************************************************************************/ .global _xtensa_coproc_restorestate .type _xtensa_coproc_restorestate, @function .align 4 .literal_position .align 4 _xtensa_coproc_restorestate: /* Move the address of the thread state save area to R15 */ mov a15, a2 /* A15 is now the address of the save area */ #ifdef CONFIG_XTENSA_CP_LAZY movi a2, 0 /* a2 = Will disable all coprocessors */ #else l16ui a2, a15, XTENSA_CPENABLE /* a2 = Which CPs have been enable for this thread? */ #endif wsr a2, CPENABLE /* Set CPENABLE correctly for this thread */ l16ui a2, a15, XTENSA_CPSTORED /* a2 = Which CPs have been saved for this thread? */ movi a3, 0 /* Clear the ones being restored (all of them) */ s16i a3, a15, XTENSA_CPSTORED /* Clear saved CP mask */ movi a13, _xtensa_coproc_saoffsets /* Array of CP save offsets */ l32i a15, a15, XTENSA_CPASA /* a15 = base of aligned save area */ #if XCHAL_CP0_SA_SIZE bbci.l a2, 0, 2f /* CP 0 not enabled */ l32i a14, a13, 0 /* a14 = _xtensa_coproc_saoffsets[0] */ add a3, a14, a15 /* a3 = save area for CP 0 */ xchal_cp0_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP1_SA_SIZE bbci.l a2, 1, 2f /* CP 1 not enabled */ l32i a14, a13, 4 /* a14 = _xtensa_coproc_saoffsets[1] */ add a3, a14, a15 /* a3 = save area for CP 1 */ xchal_cp1_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP2_SA_SIZE bbci.l a2, 2, 2f l32i a14, a13, 8 add a3, a14, a15 xchal_cp2_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP3_SA_SIZE bbci.l a2, 3, 2f l32i a14, a13, 12 add a3, a14, a15 xchal_cp3_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP4_SA_SIZE bbci.l a2, 4, 2f l32i a14, a13, 16 add a3, a14, a15 xchal_cp4_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP5_SA_SIZE bbci.l a2, 5, 2f l32i a14, a13, 20 add a3, a14, a15 xchal_cp5_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP6_SA_SIZE bbci.l a2, 6, 2f l32i a14, a13, 24 add a3, a14, a15 xchal_cp6_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif #if XCHAL_CP7_SA_SIZE bbci.l a2, 7, 2f l32i a14, a13, 28 add a3, a14, a15 xchal_cp7_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL 2: #endif /* Ensure wsr.CPENABLE has completed. */ rsync ret .size _xtensa_coproc_restorestate, . - _xtensa_coproc_restorestate /**************************************************************************** * Name: xtensa_coproc_restorestate * * Description: * Restore any callee-saved coprocessor state for the incoming thread. * xtensa_coproc_restorestate() is simply a C wrapper around the assembly * language call to _xtensa_coproc_restorestate. * * Input Parameters: * - A2 holds the address of the threads state save area * * Returned Value: * None * * Assumptions: * Called with interrupts disabled. * ****************************************************************************/ .global xtensa_coproc_restorestate .type xtensa_coproc_restorestate, @function .align 4 .literal_position .align 4 xtensa_coproc_restorestate: #ifdef __XTENSA_CALL0_ABI__ /* Need to preserve a8-11. _xtensa_coproc_restorestate modifies a2-a7, * a13-a15. a12-a15 are callee saved registers so a13-a14 must be * preserved. */ ENTRY(16) s32i a13, sp, LOCAL_OFFSET(1) /* Save clobbered values */ s32i a14, sp, LOCAL_OFFSET(2) s32i a15, sp, LOCAL_OFFSET(3) /* Call _xtensa_coproc_restorestate() with A2=address of co-processor * save area. Registers a0, a2-a7, a13-a15 have been trashed. */ call0 _xtensa_coproc_restorestate /* Restore a13-a15 and return */ l32i a13, sp, LOCAL_OFFSET(1) /* Restore clobbered registers */ l32i a14, sp, LOCAL_OFFSET(2) l32i a15, sp, LOCAL_OFFSET(3) RET(16) #else /* Need to preserve a8-15. _xtensa_coproc_savestate modifies a2-a7, * a13-a15. So a13-a15 may need to be preserved. */ ENTRY(32 /*16*/) /* REVISIT: Why 32? */ s32i a0, sp, LOCAL_OFFSET(1) /* Save return address */ /* Call _xtensa_coproc_restorestate() with A2=address of co-processor * save area. Registers a0, a2-a7, a13-a15 have been trashed. */ call0 _xtensa_coproc_restorestate /* Restore a0 and return */ l32i a0, sp, LOCAL_OFFSET(1) /* Recover return address */ RET(32 /*16*/) /* REVISIT: Why 32? */ #endif .size xtensa_coproc_restorestate, . - xtensa_coproc_restorestate #endif /* XCHAL_CP_NUM > 0 */