Line data Source code
1 : /* $OpenBSD: drm_linux_atomic.h,v 1.2 2018/01/30 08:15:17 jsg Exp $ */
2 : /**
3 : * \file drm_atomic.h
4 : * Atomic operations used in the DRM which may or may not be provided by the OS.
5 : *
6 : * \author Eric Anholt <anholt@FreeBSD.org>
7 : */
8 :
9 : /*-
10 : * Copyright 2004 Eric Anholt
11 : * All Rights Reserved.
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice (including the next
21 : * paragraph) shall be included in all copies or substantial portions of the
22 : * Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28 : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29 : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30 : * OTHER DEALINGS IN THE SOFTWARE.
31 : */
32 :
33 : #ifndef _DRM_LINUX_ATOMIC_H_
34 : #define _DRM_LINUX_ATOMIC_H_
35 :
36 : #include <machine/atomic.h>
37 :
38 : typedef uint32_t atomic_t;
39 :
40 : #define atomic_set(p, v) (*(p) = (v))
41 : #define atomic_read(p) (*(p))
42 : #define atomic_inc(p) __sync_fetch_and_add(p, 1)
43 : #define atomic_dec(p) __sync_fetch_and_sub(p, 1)
44 : #define atomic_add(n, p) __sync_fetch_and_add(p, n)
45 : #define atomic_sub(n, p) __sync_fetch_and_sub(p, n)
46 : #define atomic_add_return(n, p) __sync_add_and_fetch(p, n)
47 : #define atomic_sub_return(n, p) __sync_sub_and_fetch(p, n)
48 : #define atomic_inc_return(v) atomic_add_return(1, (v))
49 : #define atomic_dec_return(v) atomic_sub_return(1, (v))
50 : #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
51 : #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
52 : #define atomic_or(n, p) atomic_setbits_int(p, n)
53 : #define atomic_cmpxchg(p, o, n) __sync_val_compare_and_swap(p, o, n)
54 :
55 : static __inline int
56 0 : atomic_xchg(volatile int *v, int n)
57 : {
58 0 : __sync_synchronize();
59 0 : return __sync_lock_test_and_set(v, n);
60 : }
61 :
62 : static __inline int
63 0 : atomic_add_unless(volatile int *v, int n, int u)
64 : {
65 0 : int o = *v;
66 :
67 0 : do {
68 0 : o = *v;
69 0 : if (o == u)
70 0 : return 0;
71 0 : } while (__sync_val_compare_and_swap(v, o, o +n) != o);
72 :
73 0 : return 1;
74 0 : }
75 :
76 : #define atomic_long_read(p) (*(p))
77 :
78 : #ifdef __LP64__
79 : typedef uint64_t atomic64_t;
80 :
81 : #define atomic64_set(p, v) (*(p) = (v))
82 : #define atomic64_read(p) (*(p))
83 :
84 : static __inline int64_t
85 0 : atomic64_xchg(volatile int64_t *v, int64_t n)
86 : {
87 0 : __sync_synchronize();
88 0 : return __sync_lock_test_and_set(v, n);
89 : }
90 :
91 : #define atomic64_add(n, p) __sync_fetch_and_add_8(p, n)
92 : #define atomic64_sub(n, p) __sync_fetch_and_sub_8(p, n)
93 :
94 : #else
95 :
96 : typedef struct {
97 : volatile uint64_t val;
98 : struct mutex lock;
99 : } atomic64_t;
100 :
101 : static __inline void
102 : atomic64_set(atomic64_t *v, int64_t i)
103 : {
104 : mtx_init(&v->lock, IPL_HIGH);
105 : v->val = i;
106 : }
107 :
108 : static __inline int64_t
109 : atomic64_read(atomic64_t *v)
110 : {
111 : int64_t val;
112 :
113 : mtx_enter(&v->lock);
114 : val = v->val;
115 : mtx_leave(&v->lock);
116 :
117 : return val;
118 : }
119 :
120 : static __inline int64_t
121 : atomic64_xchg(atomic64_t *v, int64_t n)
122 : {
123 : int64_t val;
124 :
125 : mtx_enter(&v->lock);
126 : val = v->val;
127 : v->val = n;
128 : mtx_leave(&v->lock);
129 :
130 : return val;
131 : }
132 :
133 : static __inline void
134 : atomic64_add(int i, atomic64_t *v)
135 : {
136 : mtx_enter(&v->lock);
137 : v->val += i;
138 : mtx_leave(&v->lock);
139 : }
140 :
141 : static __inline void
142 : atomic64_sub(int i, atomic64_t *v)
143 : {
144 : mtx_enter(&v->lock);
145 : v->val -= i;
146 : mtx_leave(&v->lock);
147 : }
148 : #endif
149 :
150 : static inline int
151 0 : atomic_inc_not_zero(atomic_t *p)
152 : {
153 0 : if (*p == 0)
154 0 : return (0);
155 :
156 0 : *(p) += 1;
157 0 : return (*p);
158 0 : }
159 :
160 : /* FIXME */
161 : #define atomic_set_int(p, bits) atomic_setbits_int(p,bits)
162 : #define atomic_set_mask(bits, p) atomic_setbits_int(p,bits)
163 : #define atomic_clear_int(p, bits) atomic_clearbits_int(p,bits)
164 : #define atomic_clear_mask(bits, p) atomic_clearbits_int(p,bits)
165 : #define atomic_fetchadd_int(p, n) __sync_fetch_and_add(p, n)
166 : #define atomic_fetchsub_int(p, n) __sync_fetch_and_sub(p, n)
167 :
168 : #if defined(__i386__) || defined(__amd64__)
169 : static __inline int
170 : atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
171 : {
172 : int res = exp;
173 :
174 : __asm __volatile (
175 : " lock ; "
176 : " cmpxchgl %1,%2 ; "
177 : " setz %%al ; "
178 : " movzbl %%al,%0 ; "
179 : "1: "
180 : "# atomic_cmpset_int"
181 : : "+a" (res) /* 0 (result) */
182 : : "r" (src), /* 1 */
183 : "m" (*(dst)) /* 2 */
184 : : "memory");
185 :
186 : return (res);
187 : }
188 : #else /* __i386__ */
189 : static __inline int
190 : atomic_cmpset_int(__volatile__ u_int *dst, u_int old, u_int new)
191 : {
192 : int s = splhigh();
193 : if (*dst==old) {
194 : *dst = new;
195 : splx(s);
196 : return 1;
197 : }
198 : splx(s);
199 : return 0;
200 : }
201 : #endif /* !__i386__ */
202 :
203 : static __inline atomic_t
204 0 : test_and_set_bit(u_int b, volatile void *p)
205 : {
206 0 : int s = splhigh();
207 0 : unsigned int m = 1<<b;
208 0 : unsigned int r = *(volatile int *)p & m;
209 0 : *(volatile int *)p |= m;
210 0 : splx(s);
211 0 : return r;
212 : }
213 :
214 : static __inline void
215 0 : clear_bit(u_int b, volatile void *p)
216 : {
217 0 : atomic_clear_int(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f));
218 0 : }
219 :
220 : static __inline void
221 0 : set_bit(u_int b, volatile void *p)
222 : {
223 0 : atomic_set_int(((volatile u_int *)p) + (b >> 5), 1 << (b & 0x1f));
224 0 : }
225 :
226 : static __inline void
227 0 : __clear_bit(u_int b, volatile void *p)
228 : {
229 0 : volatile u_int *ptr = (volatile u_int *)p;
230 0 : ptr[b >> 5] &= ~(1 << (b & 0x1f));
231 0 : }
232 :
233 : static __inline void
234 0 : __set_bit(u_int b, volatile void *p)
235 : {
236 0 : volatile u_int *ptr = (volatile u_int *)p;
237 0 : ptr[b >> 5] |= (1 << (b & 0x1f));
238 0 : }
239 :
240 : static __inline int
241 0 : test_bit(u_int b, volatile void *p)
242 : {
243 0 : return !!(((volatile u_int *)p)[b >> 5] & (1 << (b & 0x1f)));
244 : }
245 :
246 : static __inline int
247 0 : __test_and_clear_bit(u_int b, volatile void *p)
248 : {
249 0 : volatile u_int *ptr = (volatile u_int *)p;
250 0 : int rv = !!(ptr[b >> 5] & (1 << (b & 0x1f)));
251 0 : ptr[b >> 5] &= ~(1 << (b & 0x1f));
252 0 : return rv;
253 : }
254 :
255 : static __inline int
256 0 : find_first_zero_bit(volatile void *p, int max)
257 : {
258 : int b;
259 0 : volatile u_int *ptr = (volatile u_int *)p;
260 :
261 0 : for (b = 0; b < max; b += 32) {
262 0 : if (ptr[b >> 5] != ~0) {
263 0 : for (;;) {
264 0 : if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
265 0 : return b;
266 0 : b++;
267 : }
268 : }
269 : }
270 0 : return max;
271 0 : }
272 :
273 : static __inline int
274 0 : find_first_bit(volatile void *p, int max)
275 : {
276 : int b;
277 0 : volatile u_int *ptr = (volatile u_int *)p;
278 :
279 0 : for (b = 0; b < max; b += 32) {
280 0 : if (ptr[b >> 5] != 0) {
281 0 : for (;;) {
282 0 : if (ptr[b >> 5] & (1 << (b & 0x1f)))
283 0 : return b;
284 0 : b++;
285 : }
286 : }
287 : }
288 0 : return max;
289 0 : }
290 :
291 : static __inline int
292 0 : find_next_bit(volatile void *p, int max, int b)
293 : {
294 0 : volatile u_int *ptr = (volatile u_int *)p;
295 :
296 0 : for (; b < max; b+= 32) {
297 0 : if (ptr[b >> 5] != 0) {
298 0 : for (;;) {
299 0 : if (ptr[b >> 5] & (1 << (b & 0x1f)))
300 0 : return b;
301 0 : b++;
302 : }
303 : }
304 : }
305 0 : return max;
306 0 : }
307 :
308 : #define for_each_set_bit(b, p, max) \
309 : for ((b) = find_first_bit((p), (max)); \
310 : (b) < (max); \
311 : (b) = find_next_bit((p), (max), (b) + 1))
312 :
313 : #endif
|