1// 2// mp_asm.S - multi-processor synchronization routines 3// 4// $Id$ 5 6// Copyright (c) 2003, 2005, 2010 Tensilica Inc. 7// 8// Permission is hereby granted, free of charge, to any person obtaining 9// a copy of this software and associated documentation files (the 10// "Software"), to deal in the Software without restriction, including 11// without limitation the rights to use, copy, modify, merge, publish, 12// distribute, sublicense, and/or sell copies of the Software, and to 13// permit persons to whom the Software is furnished to do so, subject to 14// the following conditions: 15// 16// The above copyright notice and this permission notice shall be included 17// in all copies or substantial portions of the Software. 18// 19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27#include <xtensa/coreasm.h> 28 29 30/* 31 int xthal_compare_and_set( int *address, int test_value, int set_value ) 32 33 Atomically sets *address to set_value if *address equals test_value. 34 Returns the previous value of *address (the one compared with test_value). 35 36 Uses the S32C1I instruction if available. 37 S32C1I requires special support from the memory controller for 38 memory accessed via the PIF interface. For this and other reasons, 39 S32C1I might not work on the entire 4GB address range. This function 40 does not test address validity. That is the responsibility of the 41 software invoking this function. 42*/ 43 .text 44 .align 4 45 .global xthal_compare_and_set 46 .type xthal_compare_and_set,@function 47 48xthal_compare_and_set: 49 abi_entry 50 // a2 == address 51 // a3 == test value 52 // a4 == set value 53 54#if XCHAL_HAVE_EXCLUSIVE 55 mov a6, a4 // a6 = copy of set_value 561: 57 l32ex a5, a2 // a5 = *address, set monitor 58 bne a5, a3, 2f // skip write if *address != test_value 59 mov a4, a6 // a4 = set_value 60 s32ex a4, a2 // *address = set_value 61 getex a4 // get result of store 62 beqz a4, 1b 632: 64 mov a2, a5 // a2 = *address, return value 65 clrex // in case we skipped write 66#elif XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION_MAJOR >= 2200 67 mov a6, a4 // a6 = copy of set_value 68 movi a5, -1 69 xor a5, a5, a3 // a5 = ~a3 70 wsr.scompare1 a3 // set test_value 711: 72 mov a4, a6 // a4 = set_value 73 s32c1i a4, a2, 0 74 bne a4, a5, 2f // if a4 != ~SCOMPARE1 then done 75 l32i a4, a2, 0 // a4 = *address 76 bne a4, a5, 1b // retry if *address != ~SCOMPARE1 772: 78 mov a2, a4 79#else 80 mov a7, a2 // a7 == address, a2 is return val 81# if XCHAL_HAVE_INTERRUPTS 82 rsil a5, 15 // a5 == new ps 83# endif 84 l32i a2, a7, 0 // a2 == value to test, return val 85 bne a3, a2, done // test 86 87 s32i a4, a7, 0 // write the new value 88 89done: 90# if XCHAL_HAVE_INTERRUPTS 91 wsr.ps a5 // restore the PS 92 rsync 93# endif 94#endif 95 abi_return 96 97 .size xthal_compare_and_set, . - xthal_compare_and_set 98 99 100/* 101 unsigned xthal_get_prid( void ); 102 103 Returns the value of the PRID register (processor ID), 104 or 0 if not configured. 105 (Note: this register, when present, cannot / must-not 106 change value during runtime; on certain processors, 107 its value may get sampled only at reset. 108 It can never be written to, hence 109 there is no xthal_set_prid() function.) 110*/ 111 .align 4 112 .global xthal_get_prid 113 .type xthal_get_prid,@function 114xthal_get_prid: 115 abi_entry 116#if XCHAL_HAVE_PRID 117 rsr.prid a2 118#else 119 movi a2, 0 120#endif 121 abi_return 122 .size xthal_get_prid, . - xthal_get_prid 123 124