Revision | fc48f4fb0506b2ea6ef3bb33037be3a4da2874bc (tree) |
---|---|
Zeit | 2020-08-11 20:35:02 |
Autor | Max Filippov <jcmvbkbc@gmai...> |
Commiter | Waldemar Brodkorb |
xtensa: add exclusive access support
Add XCHAL definitions for S32C1I and EXCLUSIVE options to
xtensa-config.h, include it in places that implement atomic operations
and add implementations with exclusive access option opcodes.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
@@ -18,6 +18,7 @@ | ||
18 | 18 | #ifndef _BITS_ATOMIC_H |
19 | 19 | #define _BITS_ATOMIC_H 1 |
20 | 20 | |
21 | +#include <bits/xtensa-config.h> | |
21 | 22 | #include <inttypes.h> |
22 | 23 | |
23 | 24 | typedef int32_t atomic32_t; |
@@ -50,6 +51,128 @@ typedef uintmax_t uatomic_max_t; | ||
50 | 51 | #define __arch_compare_and_exchange_bool_16_rel(mem, newval, oldval) \ |
51 | 52 | (abort (), 0) |
52 | 53 | |
54 | +#if XCHAL_HAVE_EXCLUSIVE | |
55 | + | |
56 | +/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL. | |
57 | + Return the old *MEM value. */ | |
58 | + | |
59 | +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ | |
60 | + ({__typeof__(*(mem)) __tmp, __value; \ | |
61 | + __asm__ __volatile__( \ | |
62 | + " memw \n" \ | |
63 | + "1: l32ex %0, %2 \n" \ | |
64 | + " bne %0, %4, 2f \n" \ | |
65 | + " mov %1, %3 \n" \ | |
66 | + " s32ex %1, %2 \n" \ | |
67 | + " getex %1 \n" \ | |
68 | + " beqz %1, 1b \n" \ | |
69 | + " memw \n" \ | |
70 | + "2: \n" \ | |
71 | + : "=&a" (__value), "=&a" (__tmp) \ | |
72 | + : "a" (mem), "a" (newval), "a" (oldval) \ | |
73 | + : "memory" ); \ | |
74 | + __value; \ | |
75 | + }) | |
76 | + | |
77 | +/* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL. | |
78 | + Return zero if *MEM was changed or non-zero if no exchange happened. */ | |
79 | + | |
80 | +#define __arch_compare_and_exchange_bool_32_acq(mem, newval, oldval) \ | |
81 | + ({__typeof__(*(mem)) __tmp, __value; \ | |
82 | + __asm__ __volatile__( \ | |
83 | + " memw \n" \ | |
84 | + "1: l32ex %0, %2 \n" \ | |
85 | + " sub %0, %4, %0 \n" \ | |
86 | + " bnez %0, 2f \n" \ | |
87 | + " mov %1, %3 \n" \ | |
88 | + " s32ex %1, %2 \n" \ | |
89 | + " getex %1 \n" \ | |
90 | + " beqz %1, 1b \n" \ | |
91 | + " movi %0, 0 \n" \ | |
92 | + " memw \n" \ | |
93 | + "2: \n" \ | |
94 | + : "=&a" (__value), "=&a" (__tmp) \ | |
95 | + : "a" (mem), "a" (newval), "a" (oldval) \ | |
96 | + : "memory" ); \ | |
97 | + __value != 0; \ | |
98 | + }) | |
99 | + | |
100 | +/* Store NEWVALUE in *MEM and return the old value. */ | |
101 | + | |
102 | +#define __arch_exchange_32_acq(mem, newval) \ | |
103 | + ({__typeof__(*(mem)) __tmp, __value; \ | |
104 | + __asm__ __volatile__( \ | |
105 | + " memw \n" \ | |
106 | + "1: l32ex %0, %2 \n" \ | |
107 | + " mov %1, %3 \n" \ | |
108 | + " s32ex %1, %2 \n" \ | |
109 | + " getex %1 \n" \ | |
110 | + " beqz %1, 1b \n" \ | |
111 | + " memw \n" \ | |
112 | + : "=&a" (__value), "=&a" (__tmp) \ | |
113 | + : "a" (mem), "a" (newval) \ | |
114 | + : "memory" ); \ | |
115 | + __value; \ | |
116 | + }) | |
117 | + | |
118 | +/* Add VALUE to *MEM and return the old value of *MEM. */ | |
119 | + | |
120 | +#define __arch_atomic_exchange_and_add_32(mem, value) \ | |
121 | + ({__typeof__(*(mem)) __tmp, __value; \ | |
122 | + __asm__ __volatile__( \ | |
123 | + " memw \n" \ | |
124 | + "1: l32ex %0, %2 \n" \ | |
125 | + " add %1, %0, %3 \n" \ | |
126 | + " s32ex %1, %2 \n" \ | |
127 | + " getex %1 \n" \ | |
128 | + " beqz %1, 1b \n" \ | |
129 | + " memw \n" \ | |
130 | + : "=&a" (__value), "=&a" (__tmp) \ | |
131 | + : "a" (mem), "a" (value) \ | |
132 | + : "memory" ); \ | |
133 | + __value; \ | |
134 | + }) | |
135 | + | |
136 | +/* Subtract VALUE from *MEM and return the old value of *MEM. */ | |
137 | + | |
138 | +#define __arch_atomic_exchange_and_sub_32(mem, value) \ | |
139 | + ({__typeof__(*(mem)) __tmp, __value; \ | |
140 | + __asm__ __volatile__( \ | |
141 | + " memw \n" \ | |
142 | + "1: l32ex %0, %2 \n" \ | |
143 | + " sub %1, %0, %3 \n" \ | |
144 | + " s32ex %1, %2 \n" \ | |
145 | + " getex %1 \n" \ | |
146 | + " beqz %1, 1b \n" \ | |
147 | + " memw \n" \ | |
148 | + : "=&a" (__value), "=&a" (__tmp) \ | |
149 | + : "a" (mem), "a" (value) \ | |
150 | + : "memory" ); \ | |
151 | + __tmp; \ | |
152 | + }) | |
153 | + | |
154 | +/* Decrement *MEM if it is > 0, and return the old value. */ | |
155 | + | |
156 | +#define __arch_atomic_decrement_if_positive_32(mem) \ | |
157 | + ({__typeof__(*(mem)) __tmp, __value; \ | |
158 | + __asm__ __volatile__( \ | |
159 | + " memw \n" \ | |
160 | + "1: l32ex %0, %2 \n" \ | |
161 | + " blti %0, 1, 2f \n" \ | |
162 | + " addi %1, %0, -1 \n" \ | |
163 | + " s32ex %1, %2 \n" \ | |
164 | + " getex %1 \n" \ | |
165 | + " beqz %1, 1b \n" \ | |
166 | + " memw \n" \ | |
167 | + "2: \n" \ | |
168 | + : "=&a" (__value), "=&a" (__tmp) \ | |
169 | + : "a" (mem) \ | |
170 | + : "memory" ); \ | |
171 | + __value; \ | |
172 | + }) | |
173 | + | |
174 | +#elif XCHAL_HAVE_S32C1I | |
175 | + | |
53 | 176 | /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL. |
54 | 177 | Return the old *MEM value. */ |
55 | 178 |
@@ -156,6 +279,11 @@ typedef uintmax_t uatomic_max_t; | ||
156 | 279 | __value; \ |
157 | 280 | }) |
158 | 281 | |
282 | +#else | |
283 | + | |
284 | +#error No hardware atomic operations | |
285 | + | |
286 | +#endif | |
159 | 287 | |
160 | 288 | /* These are the preferred public interfaces: */ |
161 | 289 |
@@ -43,4 +43,10 @@ | ||
43 | 43 | #undef XCHAL_NUM_AREGS |
44 | 44 | #define XCHAL_NUM_AREGS 64 |
45 | 45 | |
46 | +#undef XCHAL_HAVE_S32C1I | |
47 | +#define XCHAL_HAVE_S32C1I 1 | |
48 | + | |
49 | +#undef XCHAL_HAVE_EXCLUSIVE | |
50 | +#define XCHAL_HAVE_EXCLUSIVE 0 | |
51 | + | |
46 | 52 | #endif /* !XTENSA_CONFIG_H */ |
@@ -21,6 +21,7 @@ | ||
21 | 21 | #ifndef _PT_MACHINE_H |
22 | 22 | #define _PT_MACHINE_H 1 |
23 | 23 | |
24 | +#include <bits/xtensa-config.h> | |
24 | 25 | #include <sys/syscall.h> |
25 | 26 | #include <asm/unistd.h> |
26 | 27 |
@@ -34,6 +35,55 @@ | ||
34 | 35 | extern long int testandset (int *spinlock); |
35 | 36 | extern int __compare_and_swap (long int *p, long int oldval, long int newval); |
36 | 37 | |
38 | +#if XCHAL_HAVE_EXCLUSIVE | |
39 | + | |
40 | +/* Spinlock implementation; required. */ | |
41 | +PT_EI long int | |
42 | +testandset (int *spinlock) | |
43 | +{ | |
44 | + unsigned long tmp; | |
45 | + __asm__ volatile ( | |
46 | +" memw \n" | |
47 | +"1: l32ex %0, %1 \n" | |
48 | +" bnez %0, 2f \n" | |
49 | +" movi %0, 1 \n" | |
50 | +" s32ex %0, %1 \n" | |
51 | +" getex %0 \n" | |
52 | +" beqz %0, 1b \n" | |
53 | +" movi %0, 0 \n" | |
54 | +" memw \n" | |
55 | +"2: \n" | |
56 | + : "=&a" (tmp) | |
57 | + : "a" (spinlock) | |
58 | + : "memory" | |
59 | + ); | |
60 | + return tmp; | |
61 | +} | |
62 | + | |
63 | +PT_EI int | |
64 | +__compare_and_swap (long int *p, long int oldval, long int newval) | |
65 | +{ | |
66 | + unsigned long tmp; | |
67 | + unsigned long value; | |
68 | + __asm__ volatile ( | |
69 | +" memw \n" | |
70 | +"1: l32ex %0, %2 \n" | |
71 | +" bne %0, %4, 2f \n" | |
72 | +" mov %1, %3 \n" | |
73 | +" s32ex %1, %2 \n" | |
74 | +" getex %1 \n" | |
75 | +" beqz %1, 1b \n" | |
76 | +" memw \n" | |
77 | +"2: \n" | |
78 | + : "=&a" (tmp), "=&a" (value) | |
79 | + : "a" (p), "a" (newval), "a" (oldval) | |
80 | + : "memory" ); | |
81 | + | |
82 | + return tmp == oldval; | |
83 | +} | |
84 | + | |
85 | +#elif XCHAL_HAVE_S32C1I | |
86 | + | |
37 | 87 | /* Spinlock implementation; required. */ |
38 | 88 | PT_EI long int |
39 | 89 | testandset (int *spinlock) |
@@ -71,6 +121,12 @@ __compare_and_swap (long int *p, long int oldval, long int newval) | ||
71 | 121 | return tmp == oldval; |
72 | 122 | } |
73 | 123 | |
124 | +#else | |
125 | + | |
126 | +#error No hardware atomic operations | |
127 | + | |
128 | +#endif | |
129 | + | |
74 | 130 | /* Get some notion of the current stack. Need not be exactly the top |
75 | 131 | of the stack, just something somewhere in the current frame. */ |
76 | 132 | #define CURRENT_STACK_FRAME __builtin_frame_address (0) |
@@ -15,16 +15,32 @@ | ||
15 | 15 | License along with the GNU C Library; see the file COPYING.LIB. If |
16 | 16 | not, see <http://www.gnu.org/licenses/>. */ |
17 | 17 | |
18 | +#include <bits/xtensa-config.h> | |
18 | 19 | #include <sysdep.h> |
19 | 20 | |
20 | 21 | .text |
21 | 22 | ENTRY (pthread_spin_lock) |
22 | 23 | |
24 | +#if XCHAL_HAVE_EXCLUSIVE | |
25 | + memw | |
26 | +1: l32ex a3, a2 | |
27 | + bnez a3, 1b | |
28 | + movi a3, 1 | |
29 | + s32ex a3, a2 | |
30 | + getex a3 | |
31 | + beqz a3, 1b | |
32 | + memw | |
33 | +#elif XCHAL_HAVE_S32C1I | |
23 | 34 | movi a3, 0 |
24 | 35 | wsr a3, scompare1 |
25 | 36 | movi a3, 1 |
26 | 37 | 1: s32c1i a3, a2, 0 |
27 | 38 | bnez a3, 1b |
39 | +#else | |
40 | + | |
41 | +#error No hardware atomic operations | |
42 | + | |
43 | +#endif | |
28 | 44 | movi a2, 0 |
29 | 45 | |
30 | 46 | abi_ret |
@@ -17,15 +17,32 @@ | ||
17 | 17 | |
18 | 18 | #define _ERRNO_H 1 |
19 | 19 | #include <bits/errno.h> |
20 | +#include <bits/xtensa-config.h> | |
20 | 21 | #include <sysdep.h> |
21 | 22 | |
22 | 23 | .text |
23 | 24 | ENTRY (pthread_spin_trylock) |
24 | 25 | |
26 | +#if XCHAL_HAVE_EXCLUSIVE | |
27 | + memw | |
28 | + l32ex a3, a2 | |
29 | + bnez a3, 1f | |
30 | + movi a3, 1 | |
31 | + s32ex a3, a2 | |
32 | + getex a3 | |
33 | + addi a3, a3, -1 | |
34 | + memw | |
35 | +1: | |
36 | +#elif XCHAL_HAVE_S32C1I | |
25 | 37 | movi a3, 0 |
26 | 38 | wsr a3, scompare1 |
27 | 39 | movi a3, 1 |
28 | 40 | s32c1i a3, a2, 0 |
41 | +#else | |
42 | + | |
43 | +#error No hardware atomic operations | |
44 | + | |
45 | +#endif | |
29 | 46 | movi a2, EBUSY |
30 | 47 | moveqz a2, a3, a3 |
31 | 48 |