1/* $OpenBSD: atomic.h,v 1.12 2019/10/28 09:41:37 visa Exp $ */
2
3/* Public Domain */
4
5#ifndef _MIPS64_ATOMIC_H_
6#define _MIPS64_ATOMIC_H_
7
8#if defined(_KERNEL)
9
10/* wait until the bits to set are clear, and set them */
11static __inline void
12atomic_wait_and_setbits_int(volatile unsigned int *uip, unsigned int v)
13{
14 unsigned int tmp0, tmp1;
15
16 __asm__ volatile (
17 "1: ll %0, 0(%2)\n"
18 " and %1, %0, %3\n"
19 " bnez %1, 1b\n"
20 " or %0, %3, %0\n"
21 " sc %0, 0(%2)\n"
22 " beqz %0, 1b\n"
23 " nop\n" :
24 "=&r"(tmp0), "=&r"(tmp1) :
25 "r"(uip), "r"(v) : "memory");
26}
27
28static __inline void
29atomic_setbits_int(volatile unsigned int *uip, unsigned int v)
30{
31 unsigned int tmp;
32
33 __asm__ volatile (
34 "1: ll %0, 0(%1)\n"
35 " or %0, %2, %0\n"
36 " sc %0, 0(%1)\n"
37 " beqz %0, 1b\n"
38 " nop\n" :
39 "=&r"(tmp) :
40 "r"(uip), "r"(v) : "memory");
41}
42
43static __inline void
44atomic_clearbits_int(volatile unsigned int *uip, unsigned int v)
45{
46 unsigned int tmp;
47
48 __asm__ volatile (
49 "1: ll %0, 0(%1)\n"
50 " and %0, %2, %0\n"
51 " sc %0, 0(%1)\n"
52 " beqz %0, 1b\n"
53 " nop\n" :
54 "=&r"(tmp) :
55 "r"(uip), "r"(~v) : "memory");
56}
57
58#endif /* defined(_KERNEL) */
59
60static inline unsigned int
61_atomic_cas_uint(volatile unsigned int *p, unsigned int o, unsigned int n)
62{
63 unsigned int rv, wv;
64
65 __asm__ volatile (
66 "1: ll %0, %1\n"
67 " bne %0, %4, 2f\n"
68 " move %2, %3\n"
69 " sc %2, %1\n"
70 " beqz %2, 1b\n"
71 "2: nop\n"
72 : "=&r" (rv), "+m" (*p), "=&r" (wv)
73 : "r" (n), "Ir" (o));
74
75 return (rv);
76}
77#define atomic_cas_uint(_p, _o, _n) _atomic_cas_uint((_p), (_o), (_n))
78
79static inline unsigned long
80_atomic_cas_ulong(volatile unsigned long *p, unsigned long o, unsigned long n)
81{
82 unsigned long rv, wv;
83
84 __asm__ volatile (
85 "1: lld %0, %1\n"
86 " bne %0, %4, 2f\n"
87 " move %2, %3\n"
88 " scd %2, %1\n"
89 " beqz %2, 1b\n"
90 "2: nop\n"
91 : "=&r" (rv), "+m" (*p), "=&r" (wv)
92 : "r" (n), "Ir" (o));
93
94 return (rv);
95}
96#define atomic_cas_ulong(_p, _o, _n) _atomic_cas_ulong((_p), (_o), (_n))
97
98static inline void *
99_atomic_cas_ptr(volatile void *pp, void *o, void *n)
100{
101 void * volatile *p = pp;
102 void *rv, *wv;
103
104 __asm__ volatile (
105 "1: lld %0, %1\n"
106 " bne %0, %4, 2f\n"
107 " move %2, %3\n"
108 " scd %2, %1\n"
109 " beqz %2, 1b\n"
110 "2: nop\n"
111 : "=&r" (rv), "+m" (*p), "=&r" (wv)
112 : "r" (n), "Ir" (o));
113
114 return (rv);
115}
116#define atomic_cas_ptr(_p, _o, _n) _atomic_cas_ptr((_p), (_o), (_n))
117
118
119
120static inline unsigned int
121_atomic_swap_uint(volatile unsigned int *uip, unsigned int v)
122{
123 unsigned int o, t;
124
125 __asm__ volatile (
126 "1: ll %0, %1\n"
127 " move %2, %3\n"
128 " sc %2, %1\n"
129 " beqz %2, 1b\n"
130 " nop\n"
131 : "=&r" (o), "+m" (*uip), "=&r" (t)
132 : "r" (v));
133
134 return (o);
135}
136#define atomic_swap_uint(_p, _v) _atomic_swap_uint((_p), (_v))
137
138static inline unsigned long
139_atomic_swap_ulong(volatile unsigned long *uip, unsigned long v)
140{
141 unsigned long o, t;
142
143 __asm__ volatile (
144 "1: lld %0, %1\n"
145 " move %2, %3\n"
146 " scd %2, %1\n"
147 " beqz %2, 1b\n"
148 " nop\n"
149 : "=&r" (o), "+m" (*uip), "=&r" (t)
150 : "r" (v));
151
152 return (o);
153}
154#define atomic_swap_ulong(_p, _v) _atomic_swap_ulong((_p), (_v))
155
156
157static inline void *
158_atomic_swap_ptr(volatile void *uipp, void *n)
159{
160 void * volatile *uip = uipp;
161 void *o, *t;
162
163 __asm__ volatile (
164 "1: lld %0, %1\n"
165 " move %2, %3\n"
166 " scd %2, %1\n"
167 " beqz %2, 1b\n"
168 " nop\n"
169 : "=&r" (o), "+m" (*uip), "=&r" (t)
170 : "r" (n));
171
172 return (o);
173}
174#define atomic_swap_ptr(_p, _n) _atomic_swap_ptr((_p), (_n))
175
176static inline unsigned int
177_atomic_add_int_nv(volatile unsigned int *uip, unsigned int v)
178{
179 unsigned int rv, nv;
180
181 __asm__ volatile (
182 "1: ll %0, %1\n"
183 " addu %2, %0, %3\n"
184 " sc %2, %1\n"
185 " beqz %2, 1b\n"
186 " nop\n"
187 : "=&r" (rv), "+m" (*uip), "=&r" (nv)
188 : "Ir" (v));
189
190 return (rv + v);
191}
192#define atomic_add_int_nv(_uip, _v) _atomic_add_int_nv((_uip), (_v))
193#define atomic_sub_int_nv(_uip, _v) _atomic_add_int_nv((_uip), 0 - (_v))
194
195static inline unsigned long
196_atomic_add_long_nv(volatile unsigned long *uip, unsigned long v)
197{
198 unsigned long rv, nv;
199
200 __asm__ volatile (
201 "1: lld %0, %1\n"
202 " daddu %2, %0, %3\n"
203 " scd %2, %1\n"
204 " beqz %2, 1b\n"
205 " nop\n"
206 : "=&r" (rv), "+m" (*uip), "=&r" (nv)
207 : "Ir" (v));
208
209 return (rv + v);
210}
211#define atomic_add_long_nv(_uip, _v) _atomic_add_long_nv((_uip), (_v))
212#define atomic_sub_long_nv(_uip, _v) _atomic_add_long_nv((_uip), 0UL - (_v))
213
214#endif /* _MIPS64_ATOMIC_H_ */