1/* Linux-specific atomic operations for Nios II Linux.
2   Copyright (C) 2008-2020 Free Software Foundation, Inc.
3
4This file is free software; you can redistribute it and/or modify it
5under the terms of the GNU General Public License as published by the
6Free Software Foundation; either version 3, or (at your option) any
7later version.
8
9This file is distributed in the hope that it will be useful, but
10WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12General Public License for more details.
13
14Under Section 7 of GPL version 3, you are granted additional
15permissions described in the GCC Runtime Library Exception, version
163.1, as published by the Free Software Foundation.
17
18You should have received a copy of the GNU General Public License and
19a copy of the GCC Runtime Library Exception along with this program;
20see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
21<http://www.gnu.org/licenses/>.  */
22
23/* We implement byte, short and int versions of each atomic operation
24   using the kernel helper defined below.  There is no support for
25   64-bit operations yet.  */
26
27/* Crash a userspace program with SIGSEV.  */
28#define ABORT_INSTRUCTION asm ("stw zero, 0(zero)")
29
30/* Kernel helper for compare-and-exchange a 32-bit value.  */
31static inline long
32__kernel_cmpxchg (int oldval, int newval, int *mem)
33{
34  register int r2 asm ("r2");
35  register int *r4 asm ("r4") = mem;
36  register int r5 asm ("r5") = oldval;
37  register int r6 asm ("r6") = newval;
38
39  /* Call the kernel provided fixed address cmpxchg helper routine.  */
40  asm volatile ("movi %0, %4\n\t"
41		"callr %0\n"
42		: "=r" (r2)
43		: "r" (r4), "r" (r5), "r" (r6), "I" (0x00001004)
44		: "ra", "memory");
45  return r2;
46}
47
48#define HIDDEN __attribute__ ((visibility ("hidden")))
49
50#ifdef __nios2_little_endian__
51#define INVERT_MASK_1 0
52#define INVERT_MASK_2 0
53#else
54#define INVERT_MASK_1 24
55#define INVERT_MASK_2 16
56#endif
57
58#define MASK_1 0xffu
59#define MASK_2 0xffffu
60
61#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP)				\
62  int HIDDEN								\
63  __sync_fetch_and_##OP##_4 (int *ptr, int val)				\
64  {									\
65    int failure, tmp;							\
66									\
67    do {								\
68      tmp = *ptr;							\
69      failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr);	\
70    } while (failure != 0);						\
71									\
72    return tmp;								\
73  }
74
75FETCH_AND_OP_WORD (add,   , +)
76FETCH_AND_OP_WORD (sub,   , -)
77FETCH_AND_OP_WORD (or,    , |)
78FETCH_AND_OP_WORD (and,   , &)
79FETCH_AND_OP_WORD (xor,   , ^)
80FETCH_AND_OP_WORD (nand, ~, &)
81
82#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH
83#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH
84
85/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for
86   subword-sized quantities.  */
87
88#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN)	\
89  TYPE HIDDEN								\
90  NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val)			\
91  {									\
92    int *wordptr = (int *) ((unsigned long) ptr & ~3);			\
93    unsigned int mask, shift, oldval, newval;				\
94    int failure;							\
95									\
96    shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;	\
97    mask = MASK_##WIDTH << shift;					\
98									\
99    do {								\
100      oldval = *wordptr;						\
101      newval = ((PFX_OP (((oldval & mask) >> shift)			\
102			 INF_OP (unsigned int) val)) << shift) & mask;	\
103      newval |= oldval & ~mask;						\
104      failure = __kernel_cmpxchg (oldval, newval, wordptr);		\
105    } while (failure != 0);						\
106									\
107    return (RETURN & mask) >> shift;					\
108  }
109
110SUBWORD_SYNC_OP (add,   , +, unsigned short, 2, oldval)
111SUBWORD_SYNC_OP (sub,   , -, unsigned short, 2, oldval)
112SUBWORD_SYNC_OP (or,    , |, unsigned short, 2, oldval)
113SUBWORD_SYNC_OP (and,   , &, unsigned short, 2, oldval)
114SUBWORD_SYNC_OP (xor,   , ^, unsigned short, 2, oldval)
115SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, oldval)
116
117SUBWORD_SYNC_OP (add,   , +, unsigned char, 1, oldval)
118SUBWORD_SYNC_OP (sub,   , -, unsigned char, 1, oldval)
119SUBWORD_SYNC_OP (or,    , |, unsigned char, 1, oldval)
120SUBWORD_SYNC_OP (and,   , &, unsigned char, 1, oldval)
121SUBWORD_SYNC_OP (xor,   , ^, unsigned char, 1, oldval)
122SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval)
123
124#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP)				\
125  int HIDDEN								\
126  __sync_##OP##_and_fetch_4 (int *ptr, int val)				\
127  {									\
128    int tmp, failure;							\
129									\
130    do {								\
131      tmp = *ptr;							\
132      failure = __kernel_cmpxchg (tmp, PFX_OP (tmp INF_OP val), ptr);	\
133    } while (failure != 0);						\
134									\
135    return PFX_OP (tmp INF_OP val);					\
136  }
137
138OP_AND_FETCH_WORD (add,   , +)
139OP_AND_FETCH_WORD (sub,   , -)
140OP_AND_FETCH_WORD (or,    , |)
141OP_AND_FETCH_WORD (and,   , &)
142OP_AND_FETCH_WORD (xor,   , ^)
143OP_AND_FETCH_WORD (nand, ~, &)
144
145SUBWORD_SYNC_OP (add,   , +, unsigned short, 2, newval)
146SUBWORD_SYNC_OP (sub,   , -, unsigned short, 2, newval)
147SUBWORD_SYNC_OP (or,    , |, unsigned short, 2, newval)
148SUBWORD_SYNC_OP (and,   , &, unsigned short, 2, newval)
149SUBWORD_SYNC_OP (xor,   , ^, unsigned short, 2, newval)
150SUBWORD_SYNC_OP (nand, ~, &, unsigned short, 2, newval)
151
152SUBWORD_SYNC_OP (add,   , +, unsigned char, 1, newval)
153SUBWORD_SYNC_OP (sub,   , -, unsigned char, 1, newval)
154SUBWORD_SYNC_OP (or,    , |, unsigned char, 1, newval)
155SUBWORD_SYNC_OP (and,   , &, unsigned char, 1, newval)
156SUBWORD_SYNC_OP (xor,   , ^, unsigned char, 1, newval)
157SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval)
158
159int HIDDEN
160__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
161{
162  int actual_oldval, fail;
163
164  while (1)
165    {
166      actual_oldval = *ptr;
167
168      if (oldval != actual_oldval)
169	return actual_oldval;
170
171      fail = __kernel_cmpxchg (actual_oldval, newval, ptr);
172
173      if (!fail)
174	return oldval;
175    }
176}
177
178#define SUBWORD_VAL_CAS(TYPE, WIDTH)					\
179  TYPE HIDDEN								\
180  __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,		\
181				       TYPE newval)			\
182  {									\
183    int *wordptr = (int *)((unsigned long) ptr & ~3), fail;		\
184    unsigned int mask, shift, actual_oldval, actual_newval;		\
185									\
186    shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;	\
187    mask = MASK_##WIDTH << shift;					\
188									\
189    while (1)								\
190      {									\
191	actual_oldval = *wordptr;					\
192									\
193	if (((actual_oldval & mask) >> shift) != (unsigned int) oldval)	\
194          return (actual_oldval & mask) >> shift;			\
195									\
196	actual_newval = (actual_oldval & ~mask)				\
197			| (((unsigned int) newval << shift) & mask);	\
198									\
199	fail = __kernel_cmpxchg (actual_oldval, actual_newval,		\
200				 wordptr);				\
201									\
202	if (!fail)							\
203	  return oldval;						\
204      }									\
205  }
206
207SUBWORD_VAL_CAS (unsigned short, 2)
208SUBWORD_VAL_CAS (unsigned char,  1)
209
210typedef unsigned char bool;
211
212bool HIDDEN
213__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
214{
215  int failure = __kernel_cmpxchg (oldval, newval, ptr);
216  return (failure == 0);
217}
218
219#define SUBWORD_BOOL_CAS(TYPE, WIDTH)					\
220  bool HIDDEN								\
221  __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,		\
222					TYPE newval)			\
223  {									\
224    TYPE actual_oldval							\
225      = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval);	\
226    return (oldval == actual_oldval);					\
227  }
228
229SUBWORD_BOOL_CAS (unsigned short, 2)
230SUBWORD_BOOL_CAS (unsigned char,  1)
231
232int HIDDEN
233__sync_lock_test_and_set_4 (int *ptr, int val)
234{
235  int failure, oldval;
236
237  do {
238    oldval = *ptr;
239    failure = __kernel_cmpxchg (oldval, val, ptr);
240  } while (failure != 0);
241
242  return oldval;
243}
244
245#define SUBWORD_TEST_AND_SET(TYPE, WIDTH)				\
246  TYPE HIDDEN								\
247  __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val)		\
248  {									\
249    int failure;							\
250    unsigned int oldval, newval, shift, mask;				\
251    int *wordptr = (int *) ((unsigned long) ptr & ~3);			\
252									\
253    shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH;	\
254    mask = MASK_##WIDTH << shift;					\
255									\
256    do {								\
257      oldval = *wordptr;						\
258      newval = (oldval & ~mask)						\
259	       | (((unsigned int) val << shift) & mask);		\
260      failure = __kernel_cmpxchg (oldval, newval, wordptr);		\
261    } while (failure != 0);						\
262									\
263    return (oldval & mask) >> shift;					\
264  }
265
266SUBWORD_TEST_AND_SET (unsigned short, 2)
267SUBWORD_TEST_AND_SET (unsigned char,  1)
268
269#define SYNC_LOCK_RELEASE(TYPE, WIDTH)					\
270  void HIDDEN								\
271  __sync_lock_release_##WIDTH (TYPE *ptr)				\
272  {									\
273    /* All writes before this point must be seen before we release	\
274       the lock itself.  */						\
275    __builtin_sync ();							\
276    *ptr = 0;								\
277  }
278
279SYNC_LOCK_RELEASE (int,   4)
280SYNC_LOCK_RELEASE (short, 2)
281SYNC_LOCK_RELEASE (char,  1)
282