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