1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	gcc/atomic.h
9  * @brief	GCC specific atomic primitives for libmetal.
10  */
11 
12 #ifndef __METAL_GCC_ATOMIC__H__
13 #define __METAL_GCC_ATOMIC__H__
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 typedef int atomic_flag;
20 typedef char atomic_char;
21 typedef unsigned char atomic_uchar;
22 typedef short atomic_short;
23 typedef unsigned short atomic_ushort;
24 typedef int atomic_int;
25 typedef unsigned int atomic_uint;
26 typedef atomic_uint atomic_uintptr_t;
27 typedef long atomic_long;
28 typedef unsigned long atomic_ulong;
29 typedef long long atomic_llong;
30 typedef unsigned long long atomic_ullong;
31 
32 #define ATOMIC_FLAG_INIT	0
33 #define ATOMIC_VAR_INIT(VAL)	(VAL)
34 
35 typedef enum {
36 	memory_order_relaxed,
37 	memory_order_consume,
38 	memory_order_acquire,
39 	memory_order_release,
40 	memory_order_acq_rel,
41 	memory_order_seq_cst,
42 } memory_order;
43 
44 #define atomic_flag_test_and_set(FLAG)					\
45 	__sync_lock_test_and_set((FLAG), 1)
46 #define atomic_flag_test_and_set_explicit(FLAG, MO)			\
47 	atomic_flag_test_and_set(FLAG)
48 #define atomic_flag_clear(FLAG)						\
49 	__sync_lock_release((FLAG))
50 #define atomic_flag_clear_explicit(FLAG, MO)				\
51 	atomic_flag_clear(FLAG)
52 #define atomic_init(OBJ, VAL)						\
53 	do { *(OBJ) = (VAL); } while (0)
54 #define atomic_is_lock_free(OBJ)					\
55 	(sizeof(*(OBJ)) <= sizeof(long))
56 #define atomic_store(OBJ, VAL)						\
57 	do { *(OBJ) = (VAL); __sync_synchronize(); } while (0)
58 #define atomic_store_explicit(OBJ, VAL, MO)				\
59 	atomic_store((OBJ), (VAL))
60 #define atomic_load(OBJ)						\
61 	({ __sync_synchronize(); *(OBJ); })
62 #define atomic_load_explicit(OBJ, MO)					\
63 	atomic_load(OBJ)
64 #define atomic_exchange(OBJ, DES)					\
65 	({								\
66 		__typeof__(OBJ) obj = (OBJ);				\
67 		__typeof__(*obj) des = (DES);				\
68 		__typeof__(*obj) expval;					\
69 		__typeof__(*obj) oldval = atomic_load(obj);			\
70 		do {							\
71 			expval = oldval;				\
72 			oldval = __sync_val_compare_and_swap(		\
73 				obj, expval, des);			\
74 		} while (oldval != expval);				\
75 		oldval;							\
76 	})
77 #define atomic_exchange_explicit(OBJ, DES, MO)				\
78 	atomic_exchange((OBJ), (DES))
79 #define atomic_compare_exchange_strong(OBJ, EXP, DES)			\
80 	({								\
81 		__typeof__(OBJ) obj = (OBJ);				\
82 		__typeof__(EXP) exp = (EXP);				\
83 		__typeof__(*obj) expval = *exp;				\
84 		__typeof__(*obj) oldval = __sync_val_compare_and_swap(	\
85 			obj, expval, (DES));				\
86 		*exp = oldval;						\
87 		oldval == expval;					\
88 	})
89 #define atomic_compare_exchange_strong_explicit(OBJ, EXP, DES, MO)	\
90 	atomic_compare_exchange_strong((OBJ), (EXP), (DES))
91 #define atomic_compare_exchange_weak(OBJ, EXP, DES)			\
92 	atomic_compare_exchange_strong((OBJ), (EXP), (DES))
93 #define atomic_compare_exchange_weak_explicit(OBJ, EXP, DES, MO)	\
94 	atomic_compare_exchange_weak((OBJ), (EXP), (DES))
95 #define atomic_fetch_add(OBJ, VAL)					\
96 	__sync_fetch_and_add((OBJ), (VAL))
97 #define atomic_fetch_add_explicit(OBJ, VAL, MO)				\
98 	atomic_fetch_add((OBJ), (VAL))
99 #define atomic_fetch_sub(OBJ, VAL)					\
100 	__sync_fetch_and_sub((OBJ), (VAL))
101 #define atomic_fetch_sub_explicit(OBJ, VAL, MO)				\
102 	atomic_fetch_sub((OBJ), (VAL))
103 #define atomic_fetch_or(OBJ, VAL)					\
104 	__sync_fetch_and_or((OBJ), (VAL))
105 #define atomic_fetch_or_explicit(OBJ, VAL, MO)				\
106 	atomic_fetch_or((OBJ), (VAL))
107 #define atomic_fetch_xor(OBJ, VAL)					\
108 	__sync_fetch_and_xor((OBJ), (VAL))
109 #define atomic_fetch_xor_explicit(OBJ, VAL, MO)				\
110 	atomic_fetch_xor((OBJ), (VAL))
111 #define atomic_fetch_and(OBJ, VAL)					\
112 	__sync_fetch_and_and((OBJ), (VAL))
113 #define atomic_fetch_and_explicit(OBJ, VAL, MO)				\
114 	atomic_fetch_and((OBJ), (VAL))
115 #define atomic_thread_fence(MO)						\
116 	__sync_synchronize()
117 #define atomic_signal_fence(MO)						\
118 	__sync_synchronize()
119 
120 #ifdef __cplusplus
121 }
122 #endif
123 
124 #endif /* __METAL_GCC_ATOMIC__H__ */
125