xref: /freebsd-src/sys/riscv/include/atomic.h (revision ac2156c139f8f685b84a71a7f0f164d6cccc7656)
18d7e7a98SRuslan Bukin /*-
22183004eSRuslan Bukin  * Copyright (c) 2015-2024 Ruslan Bukin <br@bsdpad.com>
38d7e7a98SRuslan Bukin  * All rights reserved.
48d7e7a98SRuslan Bukin  *
58d7e7a98SRuslan Bukin  * Portions of this software were developed by SRI International and the
68d7e7a98SRuslan Bukin  * University of Cambridge Computer Laboratory under DARPA/AFRL contract
78d7e7a98SRuslan Bukin  * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
88d7e7a98SRuslan Bukin  *
98d7e7a98SRuslan Bukin  * Portions of this software were developed by the University of Cambridge
108d7e7a98SRuslan Bukin  * Computer Laboratory as part of the CTSRD Project, with support from the
118d7e7a98SRuslan Bukin  * UK Higher Education Innovation Fund (HEIF).
128d7e7a98SRuslan Bukin  *
138d7e7a98SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
148d7e7a98SRuslan Bukin  * modification, are permitted provided that the following conditions
158d7e7a98SRuslan Bukin  * are met:
168d7e7a98SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
178d7e7a98SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
188d7e7a98SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
198d7e7a98SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
208d7e7a98SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
218d7e7a98SRuslan Bukin  *
228d7e7a98SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
238d7e7a98SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
248d7e7a98SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
258d7e7a98SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
268d7e7a98SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
278d7e7a98SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
288d7e7a98SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
298d7e7a98SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
308d7e7a98SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
318d7e7a98SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
328d7e7a98SRuslan Bukin  * SUCH DAMAGE.
338d7e7a98SRuslan Bukin  */
348d7e7a98SRuslan Bukin 
358d7e7a98SRuslan Bukin #ifndef	_MACHINE_ATOMIC_H_
368d7e7a98SRuslan Bukin #define	_MACHINE_ATOMIC_H_
378d7e7a98SRuslan Bukin 
3830d4f9e8SKonstantin Belousov #include <sys/atomic_common.h>
3930d4f9e8SKonstantin Belousov 
408d7e7a98SRuslan Bukin #define	fence()	__asm __volatile("fence" ::: "memory");
418d7e7a98SRuslan Bukin #define	mb()	fence()
428d7e7a98SRuslan Bukin #define	rmb()	fence()
438d7e7a98SRuslan Bukin #define	wmb()	fence()
448d7e7a98SRuslan Bukin 
4529a5f639SKyle Evans static __inline int atomic_cmpset_8(__volatile uint8_t *, uint8_t, uint8_t);
4629a5f639SKyle Evans static __inline int atomic_fcmpset_8(__volatile uint8_t *, uint8_t *, uint8_t);
4729a5f639SKyle Evans static __inline int atomic_cmpset_16(__volatile uint16_t *, uint16_t, uint16_t);
4829a5f639SKyle Evans static __inline int atomic_fcmpset_16(__volatile uint16_t *, uint16_t *,
4929a5f639SKyle Evans     uint16_t);
5029a5f639SKyle Evans 
518d7e7a98SRuslan Bukin #define	ATOMIC_ACQ_REL(NAME, WIDTH)					\
528d7e7a98SRuslan Bukin static __inline  void							\
538d7e7a98SRuslan Bukin atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
548d7e7a98SRuslan Bukin {									\
558d7e7a98SRuslan Bukin 	atomic_##NAME##_##WIDTH(p, v);					\
568d7e7a98SRuslan Bukin 	fence(); 							\
578d7e7a98SRuslan Bukin }									\
588d7e7a98SRuslan Bukin 									\
598d7e7a98SRuslan Bukin static __inline  void							\
608d7e7a98SRuslan Bukin atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
618d7e7a98SRuslan Bukin {									\
628d7e7a98SRuslan Bukin 	fence();							\
638d7e7a98SRuslan Bukin 	atomic_##NAME##_##WIDTH(p, v);					\
648d7e7a98SRuslan Bukin }
658d7e7a98SRuslan Bukin 
6629a5f639SKyle Evans #define	ATOMIC_CMPSET_ACQ_REL(WIDTH)					\
6729a5f639SKyle Evans static __inline  int							\
6829a5f639SKyle Evans atomic_cmpset_acq_##WIDTH(__volatile uint##WIDTH##_t *p,		\
6929a5f639SKyle Evans     uint##WIDTH##_t cmpval, uint##WIDTH##_t newval)			\
7029a5f639SKyle Evans {									\
7129a5f639SKyle Evans 	int retval;							\
7229a5f639SKyle Evans 									\
7329a5f639SKyle Evans 	retval = atomic_cmpset_##WIDTH(p, cmpval, newval);		\
7429a5f639SKyle Evans 	fence();							\
7529a5f639SKyle Evans 	return (retval);						\
7629a5f639SKyle Evans }									\
7729a5f639SKyle Evans 									\
7829a5f639SKyle Evans static __inline  int							\
7929a5f639SKyle Evans atomic_cmpset_rel_##WIDTH(__volatile uint##WIDTH##_t *p,		\
8029a5f639SKyle Evans     uint##WIDTH##_t cmpval, uint##WIDTH##_t newval)			\
8129a5f639SKyle Evans {									\
8229a5f639SKyle Evans 	fence();							\
8329a5f639SKyle Evans 	return (atomic_cmpset_##WIDTH(p, cmpval, newval));		\
8429a5f639SKyle Evans }
8529a5f639SKyle Evans 
8629a5f639SKyle Evans #define	ATOMIC_FCMPSET_ACQ_REL(WIDTH)					\
8729a5f639SKyle Evans static __inline  int							\
8829a5f639SKyle Evans atomic_fcmpset_acq_##WIDTH(__volatile uint##WIDTH##_t *p,		\
8929a5f639SKyle Evans     uint##WIDTH##_t *cmpval, uint##WIDTH##_t newval)			\
9029a5f639SKyle Evans {									\
9129a5f639SKyle Evans 	int retval;							\
9229a5f639SKyle Evans 									\
9329a5f639SKyle Evans 	retval = atomic_fcmpset_##WIDTH(p, cmpval, newval);		\
9429a5f639SKyle Evans 	fence();							\
9529a5f639SKyle Evans 	return (retval);						\
9629a5f639SKyle Evans }									\
9729a5f639SKyle Evans 									\
9829a5f639SKyle Evans static __inline  int							\
9929a5f639SKyle Evans atomic_fcmpset_rel_##WIDTH(__volatile uint##WIDTH##_t *p,		\
10029a5f639SKyle Evans     uint##WIDTH##_t *cmpval, uint##WIDTH##_t newval)			\
10129a5f639SKyle Evans {									\
10229a5f639SKyle Evans 	fence();							\
10329a5f639SKyle Evans 	return (atomic_fcmpset_##WIDTH(p, cmpval, newval));		\
10429a5f639SKyle Evans }
10529a5f639SKyle Evans 
10629a5f639SKyle Evans ATOMIC_CMPSET_ACQ_REL(8);
10729a5f639SKyle Evans ATOMIC_FCMPSET_ACQ_REL(8);
10829a5f639SKyle Evans 
10929a5f639SKyle Evans #define	atomic_cmpset_char		atomic_cmpset_8
11029a5f639SKyle Evans #define	atomic_cmpset_acq_char		atomic_cmpset_acq_8
11129a5f639SKyle Evans #define	atomic_cmpset_rel_char		atomic_cmpset_rel_8
11229a5f639SKyle Evans #define	atomic_fcmpset_char		atomic_fcmpset_8
11329a5f639SKyle Evans #define	atomic_fcmpset_acq_char		atomic_fcmpset_acq_8
11429a5f639SKyle Evans #define	atomic_fcmpset_rel_char		atomic_fcmpset_rel_8
11529a5f639SKyle Evans 
11629a5f639SKyle Evans #define	atomic_cmpset_short		atomic_cmpset_16
11729a5f639SKyle Evans #define	atomic_fcmpset_short		atomic_fcmpset_16
1182183004eSRuslan Bukin 
1192183004eSRuslan Bukin ATOMIC_CMPSET_ACQ_REL(16);
1202183004eSRuslan Bukin ATOMIC_FCMPSET_ACQ_REL(16);
1212183004eSRuslan Bukin 
1222183004eSRuslan Bukin #define	atomic_load_acq_16	atomic_load_acq_16
1232183004eSRuslan Bukin static __inline uint16_t
1245e9a82e8SOlivier Certner atomic_load_acq_16(const volatile uint16_t *p)
1252183004eSRuslan Bukin {
1262183004eSRuslan Bukin 	uint16_t ret;
1272183004eSRuslan Bukin 
1282183004eSRuslan Bukin 	ret = *p;
1292183004eSRuslan Bukin 
1302183004eSRuslan Bukin 	fence();
1312183004eSRuslan Bukin 
1322183004eSRuslan Bukin 	return (ret);
1332183004eSRuslan Bukin }
1342183004eSRuslan Bukin 
1352183004eSRuslan Bukin static __inline void
1362183004eSRuslan Bukin atomic_store_rel_16(volatile uint16_t *p, uint16_t val)
1372183004eSRuslan Bukin {
1382183004eSRuslan Bukin 
1392183004eSRuslan Bukin 	fence();
1402183004eSRuslan Bukin 
1412183004eSRuslan Bukin 	*p = val;
1422183004eSRuslan Bukin }
1432183004eSRuslan Bukin 
1442183004eSRuslan Bukin #define	atomic_cmpset_acq_short		atomic_cmpset_acq_16
14529a5f639SKyle Evans #define	atomic_fcmpset_acq_short	atomic_fcmpset_acq_16
1462183004eSRuslan Bukin #define	atomic_load_acq_short		atomic_load_acq_16
1472183004eSRuslan Bukin 
1482183004eSRuslan Bukin #define	atomic_cmpset_rel_short		atomic_cmpset_rel_16
14929a5f639SKyle Evans #define	atomic_fcmpset_rel_short	atomic_fcmpset_rel_16
1502183004eSRuslan Bukin #define	atomic_store_rel_short		atomic_store_rel_16
15129a5f639SKyle Evans 
1528d7e7a98SRuslan Bukin static __inline void
1538d7e7a98SRuslan Bukin atomic_add_32(volatile uint32_t *p, uint32_t val)
1548d7e7a98SRuslan Bukin {
1558d7e7a98SRuslan Bukin 
1568d7e7a98SRuslan Bukin 	__asm __volatile("amoadd.w zero, %1, %0"
1578d7e7a98SRuslan Bukin 			: "+A" (*p)
1588d7e7a98SRuslan Bukin 			: "r" (val)
1598d7e7a98SRuslan Bukin 			: "memory");
1608d7e7a98SRuslan Bukin }
1618d7e7a98SRuslan Bukin 
1628d7e7a98SRuslan Bukin static __inline void
1638d7e7a98SRuslan Bukin atomic_subtract_32(volatile uint32_t *p, uint32_t val)
1648d7e7a98SRuslan Bukin {
1658d7e7a98SRuslan Bukin 
1668d7e7a98SRuslan Bukin 	__asm __volatile("amoadd.w zero, %1, %0"
1678d7e7a98SRuslan Bukin 			: "+A" (*p)
1688d7e7a98SRuslan Bukin 			: "r" (-val)
1698d7e7a98SRuslan Bukin 			: "memory");
1708d7e7a98SRuslan Bukin }
1718d7e7a98SRuslan Bukin 
1728d7e7a98SRuslan Bukin static __inline void
1738d7e7a98SRuslan Bukin atomic_set_32(volatile uint32_t *p, uint32_t val)
1748d7e7a98SRuslan Bukin {
1758d7e7a98SRuslan Bukin 
1768d7e7a98SRuslan Bukin 	__asm __volatile("amoor.w zero, %1, %0"
1778d7e7a98SRuslan Bukin 			: "+A" (*p)
1788d7e7a98SRuslan Bukin 			: "r" (val)
1798d7e7a98SRuslan Bukin 			: "memory");
1808d7e7a98SRuslan Bukin }
1818d7e7a98SRuslan Bukin 
1828d7e7a98SRuslan Bukin static __inline void
1838d7e7a98SRuslan Bukin atomic_clear_32(volatile uint32_t *p, uint32_t val)
1848d7e7a98SRuslan Bukin {
1858d7e7a98SRuslan Bukin 
1868d7e7a98SRuslan Bukin 	__asm __volatile("amoand.w zero, %1, %0"
1878d7e7a98SRuslan Bukin 			: "+A" (*p)
1888d7e7a98SRuslan Bukin 			: "r" (~val)
1898d7e7a98SRuslan Bukin 			: "memory");
1908d7e7a98SRuslan Bukin }
1918d7e7a98SRuslan Bukin 
1928d7e7a98SRuslan Bukin static __inline int
1938d7e7a98SRuslan Bukin atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
1948d7e7a98SRuslan Bukin {
1958d7e7a98SRuslan Bukin 	uint32_t tmp;
1968d7e7a98SRuslan Bukin 	int res;
1978d7e7a98SRuslan Bukin 
1988d7e7a98SRuslan Bukin 	res = 0;
1998d7e7a98SRuslan Bukin 
2008d7e7a98SRuslan Bukin 	__asm __volatile(
2018d7e7a98SRuslan Bukin 		"0:"
2028d7e7a98SRuslan Bukin 			"li   %1, 1\n" /* Preset to fail */
2038d7e7a98SRuslan Bukin 			"lr.w %0, %2\n"
2048d7e7a98SRuslan Bukin 			"bne  %0, %z3, 1f\n"
2058d7e7a98SRuslan Bukin 			"sc.w %1, %z4, %2\n"
2068d7e7a98SRuslan Bukin 			"bnez %1, 0b\n"
2078d7e7a98SRuslan Bukin 		"1:"
2088d7e7a98SRuslan Bukin 			: "=&r" (tmp), "=&r" (res), "+A" (*p)
209b96562ebSJohn Baldwin 			: "rJ" ((long)(int32_t)cmpval), "rJ" (newval)
2108d7e7a98SRuslan Bukin 			: "memory");
2118d7e7a98SRuslan Bukin 
2128d7e7a98SRuslan Bukin 	return (!res);
2138d7e7a98SRuslan Bukin }
2148d7e7a98SRuslan Bukin 
21543b595f6SRuslan Bukin static __inline int
21643b595f6SRuslan Bukin atomic_fcmpset_32(volatile uint32_t *p, uint32_t *cmpval, uint32_t newval)
21743b595f6SRuslan Bukin {
21843b595f6SRuslan Bukin 	uint32_t tmp;
21943b595f6SRuslan Bukin 	int res;
22043b595f6SRuslan Bukin 
22143b595f6SRuslan Bukin 	res = 0;
22243b595f6SRuslan Bukin 
22343b595f6SRuslan Bukin 	__asm __volatile(
22443b595f6SRuslan Bukin 		"0:"
22543b595f6SRuslan Bukin 			"li   %1, 1\n"		/* Preset to fail */
22643b595f6SRuslan Bukin 			"lr.w %0, %2\n"		/* Load old value */
22743b595f6SRuslan Bukin 			"bne  %0, %z4, 1f\n"	/* Compare */
22843b595f6SRuslan Bukin 			"sc.w %1, %z5, %2\n"	/* Try to store new value */
22943b595f6SRuslan Bukin 			"j 2f\n"
23043b595f6SRuslan Bukin 		"1:"
23143b595f6SRuslan Bukin 			"sw   %0, %3\n"		/* Save old value */
23243b595f6SRuslan Bukin 		"2:"
23343b595f6SRuslan Bukin 			: "=&r" (tmp), "=&r" (res), "+A" (*p), "+A" (*cmpval)
234b96562ebSJohn Baldwin 			: "rJ" ((long)(int32_t)*cmpval), "rJ" (newval)
23543b595f6SRuslan Bukin 			: "memory");
23643b595f6SRuslan Bukin 
23743b595f6SRuslan Bukin 	return (!res);
23843b595f6SRuslan Bukin }
23943b595f6SRuslan Bukin 
2408d7e7a98SRuslan Bukin static __inline uint32_t
2418d7e7a98SRuslan Bukin atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
2428d7e7a98SRuslan Bukin {
2438d7e7a98SRuslan Bukin 	uint32_t ret;
2448d7e7a98SRuslan Bukin 
2458d7e7a98SRuslan Bukin 	__asm __volatile("amoadd.w %0, %2, %1"
2468d7e7a98SRuslan Bukin 			: "=&r" (ret), "+A" (*p)
2478d7e7a98SRuslan Bukin 			: "r" (val)
2488d7e7a98SRuslan Bukin 			: "memory");
2498d7e7a98SRuslan Bukin 
2508d7e7a98SRuslan Bukin 	return (ret);
2518d7e7a98SRuslan Bukin }
2528d7e7a98SRuslan Bukin 
2538d7e7a98SRuslan Bukin static __inline uint32_t
2548d7e7a98SRuslan Bukin atomic_readandclear_32(volatile uint32_t *p)
2558d7e7a98SRuslan Bukin {
2568d7e7a98SRuslan Bukin 	uint32_t ret;
2578d7e7a98SRuslan Bukin 	uint32_t val;
2588d7e7a98SRuslan Bukin 
2598d7e7a98SRuslan Bukin 	val = 0;
2608d7e7a98SRuslan Bukin 
2618d7e7a98SRuslan Bukin 	__asm __volatile("amoswap.w %0, %2, %1"
2628d7e7a98SRuslan Bukin 			: "=&r"(ret), "+A" (*p)
2638d7e7a98SRuslan Bukin 			: "r" (val)
2648d7e7a98SRuslan Bukin 			: "memory");
2658d7e7a98SRuslan Bukin 
2668d7e7a98SRuslan Bukin 	return (ret);
2678d7e7a98SRuslan Bukin }
2688d7e7a98SRuslan Bukin 
269a474e53dSJohn Baldwin static __inline int
270a474e53dSJohn Baldwin atomic_testandclear_32(volatile uint32_t *p, u_int val)
271a474e53dSJohn Baldwin {
272a474e53dSJohn Baldwin 	uint32_t mask, old;
273a474e53dSJohn Baldwin 
274a474e53dSJohn Baldwin 	mask = 1u << (val & 31);
275a474e53dSJohn Baldwin 	__asm __volatile("amoand.w %0, %2, %1"
276a474e53dSJohn Baldwin 			: "=&r" (old), "+A" (*p)
277a474e53dSJohn Baldwin 			: "r" (~mask)
278a474e53dSJohn Baldwin 			: "memory");
279a474e53dSJohn Baldwin 
280a474e53dSJohn Baldwin 	return ((old & mask) != 0);
281a474e53dSJohn Baldwin }
282a474e53dSJohn Baldwin 
283a474e53dSJohn Baldwin static __inline int
284a474e53dSJohn Baldwin atomic_testandset_32(volatile uint32_t *p, u_int val)
285a474e53dSJohn Baldwin {
286a474e53dSJohn Baldwin 	uint32_t mask, old;
287a474e53dSJohn Baldwin 
288a474e53dSJohn Baldwin 	mask = 1u << (val & 31);
289a474e53dSJohn Baldwin 	__asm __volatile("amoor.w %0, %2, %1"
290a474e53dSJohn Baldwin 			: "=&r" (old), "+A" (*p)
291a474e53dSJohn Baldwin 			: "r" (mask)
292a474e53dSJohn Baldwin 			: "memory");
293a474e53dSJohn Baldwin 
294a474e53dSJohn Baldwin 	return ((old & mask) != 0);
295a474e53dSJohn Baldwin }
296a474e53dSJohn Baldwin 
2978d7e7a98SRuslan Bukin #define	atomic_add_int		atomic_add_32
2988d7e7a98SRuslan Bukin #define	atomic_clear_int	atomic_clear_32
2998d7e7a98SRuslan Bukin #define	atomic_cmpset_int	atomic_cmpset_32
30043b595f6SRuslan Bukin #define	atomic_fcmpset_int	atomic_fcmpset_32
3018d7e7a98SRuslan Bukin #define	atomic_fetchadd_int	atomic_fetchadd_32
3028d7e7a98SRuslan Bukin #define	atomic_readandclear_int	atomic_readandclear_32
3038d7e7a98SRuslan Bukin #define	atomic_set_int		atomic_set_32
3048d7e7a98SRuslan Bukin #define	atomic_subtract_int	atomic_subtract_32
3058d7e7a98SRuslan Bukin 
3068d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(set, 32)
3078d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(clear, 32)
3088d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(add, 32)
3098d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(subtract, 32)
3108d7e7a98SRuslan Bukin 
31129a5f639SKyle Evans ATOMIC_CMPSET_ACQ_REL(32);
31229a5f639SKyle Evans ATOMIC_FCMPSET_ACQ_REL(32);
31343b595f6SRuslan Bukin 
3148d7e7a98SRuslan Bukin static __inline uint32_t
3155e9a82e8SOlivier Certner atomic_load_acq_32(const volatile uint32_t *p)
3168d7e7a98SRuslan Bukin {
3178d7e7a98SRuslan Bukin 	uint32_t ret;
3188d7e7a98SRuslan Bukin 
3198d7e7a98SRuslan Bukin 	ret = *p;
3208d7e7a98SRuslan Bukin 
3218d7e7a98SRuslan Bukin 	fence();
3228d7e7a98SRuslan Bukin 
3238d7e7a98SRuslan Bukin 	return (ret);
3248d7e7a98SRuslan Bukin }
3258d7e7a98SRuslan Bukin 
3268d7e7a98SRuslan Bukin static __inline void
3278d7e7a98SRuslan Bukin atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
3288d7e7a98SRuslan Bukin {
3298d7e7a98SRuslan Bukin 
3308d7e7a98SRuslan Bukin 	fence();
3318d7e7a98SRuslan Bukin 
3328d7e7a98SRuslan Bukin 	*p = val;
3338d7e7a98SRuslan Bukin }
3348d7e7a98SRuslan Bukin 
3358d7e7a98SRuslan Bukin #define	atomic_add_acq_int	atomic_add_acq_32
3368d7e7a98SRuslan Bukin #define	atomic_clear_acq_int	atomic_clear_acq_32
3378d7e7a98SRuslan Bukin #define	atomic_cmpset_acq_int	atomic_cmpset_acq_32
33843b595f6SRuslan Bukin #define	atomic_fcmpset_acq_int	atomic_fcmpset_acq_32
3398d7e7a98SRuslan Bukin #define	atomic_load_acq_int	atomic_load_acq_32
3408d7e7a98SRuslan Bukin #define	atomic_set_acq_int	atomic_set_acq_32
3418d7e7a98SRuslan Bukin #define	atomic_subtract_acq_int	atomic_subtract_acq_32
3428d7e7a98SRuslan Bukin 
3438d7e7a98SRuslan Bukin #define	atomic_add_rel_int	atomic_add_rel_32
3440d3b3beeSMitchell Horne #define	atomic_clear_rel_int	atomic_clear_rel_32
3458d7e7a98SRuslan Bukin #define	atomic_cmpset_rel_int	atomic_cmpset_rel_32
34643b595f6SRuslan Bukin #define	atomic_fcmpset_rel_int	atomic_fcmpset_rel_32
3478d7e7a98SRuslan Bukin #define	atomic_set_rel_int	atomic_set_rel_32
3488d7e7a98SRuslan Bukin #define	atomic_subtract_rel_int	atomic_subtract_rel_32
3498d7e7a98SRuslan Bukin #define	atomic_store_rel_int	atomic_store_rel_32
3508d7e7a98SRuslan Bukin 
3518d7e7a98SRuslan Bukin static __inline void
3528d7e7a98SRuslan Bukin atomic_add_64(volatile uint64_t *p, uint64_t val)
3538d7e7a98SRuslan Bukin {
3548d7e7a98SRuslan Bukin 
3558d7e7a98SRuslan Bukin 	__asm __volatile("amoadd.d zero, %1, %0"
3568d7e7a98SRuslan Bukin 			: "+A" (*p)
3578d7e7a98SRuslan Bukin 			: "r" (val)
3588d7e7a98SRuslan Bukin 			: "memory");
3598d7e7a98SRuslan Bukin }
3608d7e7a98SRuslan Bukin 
3618d7e7a98SRuslan Bukin static __inline void
3628d7e7a98SRuslan Bukin atomic_subtract_64(volatile uint64_t *p, uint64_t val)
3638d7e7a98SRuslan Bukin {
3648d7e7a98SRuslan Bukin 
3658d7e7a98SRuslan Bukin 	__asm __volatile("amoadd.d zero, %1, %0"
3668d7e7a98SRuslan Bukin 			: "+A" (*p)
3678d7e7a98SRuslan Bukin 			: "r" (-val)
3688d7e7a98SRuslan Bukin 			: "memory");
3698d7e7a98SRuslan Bukin }
3708d7e7a98SRuslan Bukin 
3718d7e7a98SRuslan Bukin static __inline void
3728d7e7a98SRuslan Bukin atomic_set_64(volatile uint64_t *p, uint64_t val)
3738d7e7a98SRuslan Bukin {
3748d7e7a98SRuslan Bukin 
3758d7e7a98SRuslan Bukin 	__asm __volatile("amoor.d zero, %1, %0"
3768d7e7a98SRuslan Bukin 			: "+A" (*p)
3778d7e7a98SRuslan Bukin 			: "r" (val)
3788d7e7a98SRuslan Bukin 			: "memory");
3798d7e7a98SRuslan Bukin }
3808d7e7a98SRuslan Bukin 
3818d7e7a98SRuslan Bukin static __inline void
3828d7e7a98SRuslan Bukin atomic_clear_64(volatile uint64_t *p, uint64_t val)
3838d7e7a98SRuslan Bukin {
3848d7e7a98SRuslan Bukin 
3858d7e7a98SRuslan Bukin 	__asm __volatile("amoand.d zero, %1, %0"
3868d7e7a98SRuslan Bukin 			: "+A" (*p)
3878d7e7a98SRuslan Bukin 			: "r" (~val)
3888d7e7a98SRuslan Bukin 			: "memory");
3898d7e7a98SRuslan Bukin }
3908d7e7a98SRuslan Bukin 
3918d7e7a98SRuslan Bukin static __inline int
3928d7e7a98SRuslan Bukin atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
3938d7e7a98SRuslan Bukin {
3948d7e7a98SRuslan Bukin 	uint64_t tmp;
3958d7e7a98SRuslan Bukin 	int res;
3968d7e7a98SRuslan Bukin 
3978d7e7a98SRuslan Bukin 	res = 0;
3988d7e7a98SRuslan Bukin 
3998d7e7a98SRuslan Bukin 	__asm __volatile(
4008d7e7a98SRuslan Bukin 		"0:"
4018d7e7a98SRuslan Bukin 			"li   %1, 1\n" /* Preset to fail */
4028d7e7a98SRuslan Bukin 			"lr.d %0, %2\n"
4038d7e7a98SRuslan Bukin 			"bne  %0, %z3, 1f\n"
4048d7e7a98SRuslan Bukin 			"sc.d %1, %z4, %2\n"
4058d7e7a98SRuslan Bukin 			"bnez %1, 0b\n"
4068d7e7a98SRuslan Bukin 		"1:"
4078d7e7a98SRuslan Bukin 			: "=&r" (tmp), "=&r" (res), "+A" (*p)
4088d7e7a98SRuslan Bukin 			: "rJ" (cmpval), "rJ" (newval)
4098d7e7a98SRuslan Bukin 			: "memory");
4108d7e7a98SRuslan Bukin 
4118d7e7a98SRuslan Bukin 	return (!res);
4128d7e7a98SRuslan Bukin }
4138d7e7a98SRuslan Bukin 
41443b595f6SRuslan Bukin static __inline int
41543b595f6SRuslan Bukin atomic_fcmpset_64(volatile uint64_t *p, uint64_t *cmpval, uint64_t newval)
41643b595f6SRuslan Bukin {
41743b595f6SRuslan Bukin 	uint64_t tmp;
41843b595f6SRuslan Bukin 	int res;
41943b595f6SRuslan Bukin 
42043b595f6SRuslan Bukin 	res = 0;
42143b595f6SRuslan Bukin 
42243b595f6SRuslan Bukin 	__asm __volatile(
42343b595f6SRuslan Bukin 		"0:"
42443b595f6SRuslan Bukin 			"li   %1, 1\n"		/* Preset to fail */
42543b595f6SRuslan Bukin 			"lr.d %0, %2\n"		/* Load old value */
42643b595f6SRuslan Bukin 			"bne  %0, %z4, 1f\n"	/* Compare */
42743b595f6SRuslan Bukin 			"sc.d %1, %z5, %2\n"	/* Try to store new value */
42843b595f6SRuslan Bukin 			"j 2f\n"
42943b595f6SRuslan Bukin 		"1:"
43043b595f6SRuslan Bukin 			"sd   %0, %3\n"		/* Save old value */
43143b595f6SRuslan Bukin 		"2:"
43243b595f6SRuslan Bukin 			: "=&r" (tmp), "=&r" (res), "+A" (*p), "+A" (*cmpval)
43343b595f6SRuslan Bukin 			: "rJ" (*cmpval), "rJ" (newval)
43443b595f6SRuslan Bukin 			: "memory");
43543b595f6SRuslan Bukin 
43643b595f6SRuslan Bukin 	return (!res);
43743b595f6SRuslan Bukin }
43843b595f6SRuslan Bukin 
4398d7e7a98SRuslan Bukin static __inline uint64_t
4408d7e7a98SRuslan Bukin atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
4418d7e7a98SRuslan Bukin {
4428d7e7a98SRuslan Bukin 	uint64_t ret;
4438d7e7a98SRuslan Bukin 
4448d7e7a98SRuslan Bukin 	__asm __volatile("amoadd.d %0, %2, %1"
4458d7e7a98SRuslan Bukin 			: "=&r" (ret), "+A" (*p)
4468d7e7a98SRuslan Bukin 			: "r" (val)
4478d7e7a98SRuslan Bukin 			: "memory");
4488d7e7a98SRuslan Bukin 
4498d7e7a98SRuslan Bukin 	return (ret);
4508d7e7a98SRuslan Bukin }
4518d7e7a98SRuslan Bukin 
4528d7e7a98SRuslan Bukin static __inline uint64_t
4538d7e7a98SRuslan Bukin atomic_readandclear_64(volatile uint64_t *p)
4548d7e7a98SRuslan Bukin {
4558d7e7a98SRuslan Bukin 	uint64_t ret;
4568d7e7a98SRuslan Bukin 	uint64_t val;
4578d7e7a98SRuslan Bukin 
4588d7e7a98SRuslan Bukin 	val = 0;
4598d7e7a98SRuslan Bukin 
4608d7e7a98SRuslan Bukin 	__asm __volatile("amoswap.d %0, %2, %1"
4618d7e7a98SRuslan Bukin 			: "=&r"(ret), "+A" (*p)
4628d7e7a98SRuslan Bukin 			: "r" (val)
4638d7e7a98SRuslan Bukin 			: "memory");
4648d7e7a98SRuslan Bukin 
4658d7e7a98SRuslan Bukin 	return (ret);
4668d7e7a98SRuslan Bukin }
4678d7e7a98SRuslan Bukin 
468a474e53dSJohn Baldwin static __inline int
469a474e53dSJohn Baldwin atomic_testandclear_64(volatile uint64_t *p, u_int val)
470a474e53dSJohn Baldwin {
471a474e53dSJohn Baldwin 	uint64_t mask, old;
472a474e53dSJohn Baldwin 
473a474e53dSJohn Baldwin 	mask = 1ul << (val & 63);
474a474e53dSJohn Baldwin 	__asm __volatile("amoand.d %0, %2, %1"
475a474e53dSJohn Baldwin 			: "=&r" (old), "+A" (*p)
476a474e53dSJohn Baldwin 			: "r" (~mask)
477a474e53dSJohn Baldwin 			: "memory");
478a474e53dSJohn Baldwin 
479a474e53dSJohn Baldwin 	return ((old & mask) != 0);
480a474e53dSJohn Baldwin }
481a474e53dSJohn Baldwin 
482a474e53dSJohn Baldwin static __inline int
483a474e53dSJohn Baldwin atomic_testandset_64(volatile uint64_t *p, u_int val)
484a474e53dSJohn Baldwin {
485a474e53dSJohn Baldwin 	uint64_t mask, old;
486a474e53dSJohn Baldwin 
487a474e53dSJohn Baldwin 	mask = 1ul << (val & 63);
488a474e53dSJohn Baldwin 	__asm __volatile("amoor.d %0, %2, %1"
489a474e53dSJohn Baldwin 			: "=&r" (old), "+A" (*p)
490a474e53dSJohn Baldwin 			: "r" (mask)
491a474e53dSJohn Baldwin 			: "memory");
492a474e53dSJohn Baldwin 
493a474e53dSJohn Baldwin 	return ((old & mask) != 0);
494a474e53dSJohn Baldwin }
495a474e53dSJohn Baldwin 
496a474e53dSJohn Baldwin static __inline int
497a474e53dSJohn Baldwin atomic_testandset_acq_64(volatile uint64_t *p, u_int val)
498a474e53dSJohn Baldwin {
499a474e53dSJohn Baldwin 	uint64_t mask, old;
500a474e53dSJohn Baldwin 
501a474e53dSJohn Baldwin 	mask = 1ul << (val & 63);
502a474e53dSJohn Baldwin 	__asm __volatile("amoor.d.aq %0, %2, %1"
503a474e53dSJohn Baldwin 			: "=&r" (old), "+A" (*p)
504a474e53dSJohn Baldwin 			: "r" (mask)
505a474e53dSJohn Baldwin 			: "memory");
506a474e53dSJohn Baldwin 
507a474e53dSJohn Baldwin 	return ((old & mask) != 0);
508a474e53dSJohn Baldwin }
509a474e53dSJohn Baldwin 
5105fe191b0SRuslan Bukin static __inline uint32_t
5115fe191b0SRuslan Bukin atomic_swap_32(volatile uint32_t *p, uint32_t val)
5125fe191b0SRuslan Bukin {
5135fe191b0SRuslan Bukin 	uint32_t old;
5145fe191b0SRuslan Bukin 
5155fe191b0SRuslan Bukin 	__asm __volatile("amoswap.w %0, %2, %1"
5165fe191b0SRuslan Bukin 			: "=&r"(old), "+A" (*p)
5175fe191b0SRuslan Bukin 			: "r" (val)
5185fe191b0SRuslan Bukin 			: "memory");
5195fe191b0SRuslan Bukin 
5205fe191b0SRuslan Bukin 	return (old);
5215fe191b0SRuslan Bukin }
5225fe191b0SRuslan Bukin 
5238d7e7a98SRuslan Bukin static __inline uint64_t
5248d7e7a98SRuslan Bukin atomic_swap_64(volatile uint64_t *p, uint64_t val)
5258d7e7a98SRuslan Bukin {
5268d7e7a98SRuslan Bukin 	uint64_t old;
5278d7e7a98SRuslan Bukin 
5288d7e7a98SRuslan Bukin 	__asm __volatile("amoswap.d %0, %2, %1"
5298d7e7a98SRuslan Bukin 			: "=&r"(old), "+A" (*p)
5308d7e7a98SRuslan Bukin 			: "r" (val)
5318d7e7a98SRuslan Bukin 			: "memory");
5328d7e7a98SRuslan Bukin 
5338d7e7a98SRuslan Bukin 	return (old);
5348d7e7a98SRuslan Bukin }
5358d7e7a98SRuslan Bukin 
53613a10f34SMarius Strobl #define	atomic_swap_int			atomic_swap_32
53713a10f34SMarius Strobl 
5388d7e7a98SRuslan Bukin #define	atomic_add_long			atomic_add_64
5398d7e7a98SRuslan Bukin #define	atomic_clear_long		atomic_clear_64
5408d7e7a98SRuslan Bukin #define	atomic_cmpset_long		atomic_cmpset_64
54143b595f6SRuslan Bukin #define	atomic_fcmpset_long		atomic_fcmpset_64
5428d7e7a98SRuslan Bukin #define	atomic_fetchadd_long		atomic_fetchadd_64
5438d7e7a98SRuslan Bukin #define	atomic_readandclear_long	atomic_readandclear_64
5448d7e7a98SRuslan Bukin #define	atomic_set_long			atomic_set_64
5458d7e7a98SRuslan Bukin #define	atomic_subtract_long		atomic_subtract_64
54613a10f34SMarius Strobl #define	atomic_swap_long		atomic_swap_64
547a474e53dSJohn Baldwin #define	atomic_testandclear_long	atomic_testandclear_64
548a474e53dSJohn Baldwin #define	atomic_testandset_long		atomic_testandset_64
549a474e53dSJohn Baldwin #define	atomic_testandset_acq_long	atomic_testandset_acq_64
5508d7e7a98SRuslan Bukin 
5518d7e7a98SRuslan Bukin #define	atomic_add_ptr			atomic_add_64
5528d7e7a98SRuslan Bukin #define	atomic_clear_ptr		atomic_clear_64
5538d7e7a98SRuslan Bukin #define	atomic_cmpset_ptr		atomic_cmpset_64
55443b595f6SRuslan Bukin #define	atomic_fcmpset_ptr		atomic_fcmpset_64
5558d7e7a98SRuslan Bukin #define	atomic_fetchadd_ptr		atomic_fetchadd_64
5568d7e7a98SRuslan Bukin #define	atomic_readandclear_ptr		atomic_readandclear_64
5578d7e7a98SRuslan Bukin #define	atomic_set_ptr			atomic_set_64
5588d7e7a98SRuslan Bukin #define	atomic_subtract_ptr		atomic_subtract_64
55913a10f34SMarius Strobl #define	atomic_swap_ptr			atomic_swap_64
560a80b9ee1SJohn Baldwin #define	atomic_testandclear_ptr		atomic_testandclear_64
561a80b9ee1SJohn Baldwin #define	atomic_testandset_ptr		atomic_testandset_64
5628d7e7a98SRuslan Bukin 
5638d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(set, 64)
5648d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(clear, 64)
5658d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(add, 64)
5668d7e7a98SRuslan Bukin ATOMIC_ACQ_REL(subtract, 64)
5678d7e7a98SRuslan Bukin 
56829a5f639SKyle Evans ATOMIC_CMPSET_ACQ_REL(64);
56929a5f639SKyle Evans ATOMIC_FCMPSET_ACQ_REL(64);
57043b595f6SRuslan Bukin 
5718d7e7a98SRuslan Bukin static __inline uint64_t
572*ac2156c1SOlivier Certner atomic_load_acq_64(const volatile uint64_t *p)
5738d7e7a98SRuslan Bukin {
5748d7e7a98SRuslan Bukin 	uint64_t ret;
5758d7e7a98SRuslan Bukin 
5768d7e7a98SRuslan Bukin 	ret = *p;
5778d7e7a98SRuslan Bukin 
5788d7e7a98SRuslan Bukin 	fence();
5798d7e7a98SRuslan Bukin 
5808d7e7a98SRuslan Bukin 	return (ret);
5818d7e7a98SRuslan Bukin }
5828d7e7a98SRuslan Bukin 
5838d7e7a98SRuslan Bukin static __inline void
5848d7e7a98SRuslan Bukin atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
5858d7e7a98SRuslan Bukin {
5868d7e7a98SRuslan Bukin 
5878d7e7a98SRuslan Bukin 	fence();
5888d7e7a98SRuslan Bukin 
5898d7e7a98SRuslan Bukin 	*p = val;
5908d7e7a98SRuslan Bukin }
5918d7e7a98SRuslan Bukin 
5928d7e7a98SRuslan Bukin #define	atomic_add_acq_long		atomic_add_acq_64
5930d3b3beeSMitchell Horne #define	atomic_clear_acq_long		atomic_clear_acq_64
5948d7e7a98SRuslan Bukin #define	atomic_cmpset_acq_long		atomic_cmpset_acq_64
59543b595f6SRuslan Bukin #define	atomic_fcmpset_acq_long		atomic_fcmpset_acq_64
5968d7e7a98SRuslan Bukin #define	atomic_load_acq_long		atomic_load_acq_64
5978d7e7a98SRuslan Bukin #define	atomic_set_acq_long		atomic_set_acq_64
5988d7e7a98SRuslan Bukin #define	atomic_subtract_acq_long	atomic_subtract_acq_64
5998d7e7a98SRuslan Bukin 
6008d7e7a98SRuslan Bukin #define	atomic_add_acq_ptr		atomic_add_acq_64
6010d3b3beeSMitchell Horne #define	atomic_clear_acq_ptr		atomic_clear_acq_64
6028d7e7a98SRuslan Bukin #define	atomic_cmpset_acq_ptr		atomic_cmpset_acq_64
60343b595f6SRuslan Bukin #define	atomic_fcmpset_acq_ptr		atomic_fcmpset_acq_64
6048d7e7a98SRuslan Bukin #define	atomic_load_acq_ptr		atomic_load_acq_64
6058d7e7a98SRuslan Bukin #define	atomic_set_acq_ptr		atomic_set_acq_64
6068d7e7a98SRuslan Bukin #define	atomic_subtract_acq_ptr		atomic_subtract_acq_64
6078d7e7a98SRuslan Bukin 
6085c118142SRuslan Bukin #undef ATOMIC_ACQ_REL
6095c118142SRuslan Bukin 
6108d7e7a98SRuslan Bukin static __inline void
6118d7e7a98SRuslan Bukin atomic_thread_fence_acq(void)
6128d7e7a98SRuslan Bukin {
6138d7e7a98SRuslan Bukin 
6148d7e7a98SRuslan Bukin 	fence();
6158d7e7a98SRuslan Bukin }
6168d7e7a98SRuslan Bukin 
6178d7e7a98SRuslan Bukin static __inline void
6188d7e7a98SRuslan Bukin atomic_thread_fence_rel(void)
6198d7e7a98SRuslan Bukin {
6208d7e7a98SRuslan Bukin 
6218d7e7a98SRuslan Bukin 	fence();
6228d7e7a98SRuslan Bukin }
6238d7e7a98SRuslan Bukin 
6248d7e7a98SRuslan Bukin static __inline void
6258d7e7a98SRuslan Bukin atomic_thread_fence_acq_rel(void)
6268d7e7a98SRuslan Bukin {
6278d7e7a98SRuslan Bukin 
6288d7e7a98SRuslan Bukin 	fence();
6298d7e7a98SRuslan Bukin }
6308d7e7a98SRuslan Bukin 
6318d7e7a98SRuslan Bukin static __inline void
6328d7e7a98SRuslan Bukin atomic_thread_fence_seq_cst(void)
6338d7e7a98SRuslan Bukin {
6348d7e7a98SRuslan Bukin 
6358d7e7a98SRuslan Bukin 	fence();
6368d7e7a98SRuslan Bukin }
6378d7e7a98SRuslan Bukin 
6388d7e7a98SRuslan Bukin #define	atomic_add_rel_long		atomic_add_rel_64
6398d7e7a98SRuslan Bukin #define	atomic_clear_rel_long		atomic_clear_rel_64
6408d7e7a98SRuslan Bukin 
6418d7e7a98SRuslan Bukin #define	atomic_add_rel_long		atomic_add_rel_64
6428d7e7a98SRuslan Bukin #define	atomic_clear_rel_long		atomic_clear_rel_64
6438d7e7a98SRuslan Bukin #define	atomic_cmpset_rel_long		atomic_cmpset_rel_64
64443b595f6SRuslan Bukin #define	atomic_fcmpset_rel_long		atomic_fcmpset_rel_64
6458d7e7a98SRuslan Bukin #define	atomic_set_rel_long		atomic_set_rel_64
6468d7e7a98SRuslan Bukin #define	atomic_subtract_rel_long	atomic_subtract_rel_64
6478d7e7a98SRuslan Bukin #define	atomic_store_rel_long		atomic_store_rel_64
6488d7e7a98SRuslan Bukin 
6498d7e7a98SRuslan Bukin #define	atomic_add_rel_ptr		atomic_add_rel_64
6508d7e7a98SRuslan Bukin #define	atomic_clear_rel_ptr		atomic_clear_rel_64
6518d7e7a98SRuslan Bukin #define	atomic_cmpset_rel_ptr		atomic_cmpset_rel_64
65243b595f6SRuslan Bukin #define	atomic_fcmpset_rel_ptr		atomic_fcmpset_rel_64
6538d7e7a98SRuslan Bukin #define	atomic_set_rel_ptr		atomic_set_rel_64
6548d7e7a98SRuslan Bukin #define	atomic_subtract_rel_ptr		atomic_subtract_rel_64
6558d7e7a98SRuslan Bukin #define	atomic_store_rel_ptr		atomic_store_rel_64
6568d7e7a98SRuslan Bukin 
65729a5f639SKyle Evans #include <sys/_atomic_subword.h>
65829a5f639SKyle Evans 
6598d7e7a98SRuslan Bukin #endif /* _MACHINE_ATOMIC_H_ */
660