1*9bec9e43Sjsg /* $OpenBSD: atomic.h,v 1.12 2023/04/10 04:21:20 jsg Exp $ */
2f57756c9Sart
3f57756c9Sart /* Public Domain */
4f57756c9Sart
52fa72412Spirofti #ifndef _MACHINE_ATOMIC_H_
62fa72412Spirofti #define _MACHINE_ATOMIC_H_
7f57756c9Sart
88aa3ef09Sderaadt #if defined(_KERNEL)
98aa3ef09Sderaadt
108bf031b6Sdlg typedef volatile u_int __cpu_simple_lock_t __attribute__((__aligned__(16)));
118bf031b6Sdlg
128bf031b6Sdlg #define __SIMPLELOCK_LOCKED 0
138bf031b6Sdlg #define __SIMPLELOCK_UNLOCKED 1
148bf031b6Sdlg
158bf031b6Sdlg static inline void
__cpu_simple_lock_init(__cpu_simple_lock_t * l)168bf031b6Sdlg __cpu_simple_lock_init(__cpu_simple_lock_t *l)
178bf031b6Sdlg {
188bf031b6Sdlg *l = __SIMPLELOCK_UNLOCKED;
198bf031b6Sdlg }
208bf031b6Sdlg
218bf031b6Sdlg static inline unsigned int
__cpu_simple_lock_ldcws(__cpu_simple_lock_t * l)228bf031b6Sdlg __cpu_simple_lock_ldcws(__cpu_simple_lock_t *l)
238bf031b6Sdlg {
248bf031b6Sdlg unsigned int o;
258bf031b6Sdlg
268bf031b6Sdlg asm volatile("ldcws 0(%2), %0" : "=&r" (o), "+m" (l) : "r" (l));
278bf031b6Sdlg
288bf031b6Sdlg return (o);
298bf031b6Sdlg }
308bf031b6Sdlg
318bf031b6Sdlg static inline int
__cpu_simple_lock_try(__cpu_simple_lock_t * l)328bf031b6Sdlg __cpu_simple_lock_try(__cpu_simple_lock_t *l)
338bf031b6Sdlg {
348bf031b6Sdlg return (__cpu_simple_lock_ldcws(l) == __SIMPLELOCK_UNLOCKED);
358bf031b6Sdlg }
368bf031b6Sdlg
378bf031b6Sdlg static inline void
__cpu_simple_lock(__cpu_simple_lock_t * l)38219fa113Sdlg __cpu_simple_lock(__cpu_simple_lock_t *l)
39219fa113Sdlg {
40219fa113Sdlg while (!__cpu_simple_lock_ldcws(l))
41219fa113Sdlg ;
42219fa113Sdlg }
43219fa113Sdlg
44219fa113Sdlg static inline void
__cpu_simple_unlock(__cpu_simple_lock_t * l)458bf031b6Sdlg __cpu_simple_unlock(__cpu_simple_lock_t *l)
468bf031b6Sdlg {
478bf031b6Sdlg *l = __SIMPLELOCK_UNLOCKED;
488bf031b6Sdlg }
497dda6ca7Sjsing
507dda6ca7Sjsing #ifdef MULTIPROCESSOR
518bf031b6Sdlg extern __cpu_simple_lock_t atomic_lock;
528bf031b6Sdlg #define ATOMIC_LOCK __cpu_simple_lock(&atomic_lock);
538bf031b6Sdlg #define ATOMIC_UNLOCK __cpu_simple_unlock(&atomic_lock);
547dda6ca7Sjsing #else
557dda6ca7Sjsing #define ATOMIC_LOCK
567dda6ca7Sjsing #define ATOMIC_UNLOCK
577dda6ca7Sjsing #endif
587dda6ca7Sjsing
598bf031b6Sdlg static inline register_t
atomic_enter(void)608bf031b6Sdlg atomic_enter(void)
61f57756c9Sart {
62f8b1aca5Smiod register_t eiem;
63f8b1aca5Smiod
642df76cc2Sguenther __asm volatile("mfctl %%cr15, %0": "=r" (eiem));
652df76cc2Sguenther __asm volatile("mtctl %r0, %cr15");
667dda6ca7Sjsing ATOMIC_LOCK;
678bf031b6Sdlg
688bf031b6Sdlg return (eiem);
698bf031b6Sdlg }
708bf031b6Sdlg
718bf031b6Sdlg static inline void
atomic_leave(register_t eiem)728bf031b6Sdlg atomic_leave(register_t eiem)
738bf031b6Sdlg {
747dda6ca7Sjsing ATOMIC_UNLOCK;
752df76cc2Sguenther __asm volatile("mtctl %0, %%cr15":: "r" (eiem));
76f57756c9Sart }
77f57756c9Sart
788bf031b6Sdlg static inline unsigned int
_atomic_cas_uint(volatile unsigned int * uip,unsigned int o,unsigned int n)798bf031b6Sdlg _atomic_cas_uint(volatile unsigned int *uip, unsigned int o, unsigned int n)
808bf031b6Sdlg {
818bf031b6Sdlg register_t eiem;
828bf031b6Sdlg unsigned int rv;
838bf031b6Sdlg
848bf031b6Sdlg eiem = atomic_enter();
858bf031b6Sdlg rv = *uip;
868bf031b6Sdlg if (rv == o)
878bf031b6Sdlg *uip = n;
888bf031b6Sdlg atomic_leave(eiem);
898bf031b6Sdlg
908bf031b6Sdlg return (rv);
918bf031b6Sdlg }
928bf031b6Sdlg #define atomic_cas_uint(_p, _o, _n) _atomic_cas_uint((_p), (_o), (_n))
938bf031b6Sdlg
948bf031b6Sdlg static inline unsigned long
_atomic_cas_ulong(volatile unsigned long * uip,unsigned long o,unsigned long n)958bf031b6Sdlg _atomic_cas_ulong(volatile unsigned long *uip, unsigned long o, unsigned long n)
968bf031b6Sdlg {
978bf031b6Sdlg register_t eiem;
988bf031b6Sdlg unsigned long rv;
998bf031b6Sdlg
1008bf031b6Sdlg eiem = atomic_enter();
1018bf031b6Sdlg rv = *uip;
1028bf031b6Sdlg if (rv == o)
1038bf031b6Sdlg *uip = n;
1048bf031b6Sdlg atomic_leave(eiem);
1058bf031b6Sdlg
1068bf031b6Sdlg return (rv);
1078bf031b6Sdlg }
1088bf031b6Sdlg #define atomic_cas_ulong(_p, _o, _n) _atomic_cas_ulong((_p), (_o), (_n))
1098bf031b6Sdlg
1108bf031b6Sdlg static inline void *
_atomic_cas_ptr(volatile void * uip,void * o,void * n)1118bf031b6Sdlg _atomic_cas_ptr(volatile void *uip, void *o, void *n)
1128bf031b6Sdlg {
1138bf031b6Sdlg register_t eiem;
1148bf031b6Sdlg void * volatile *uipp = (void * volatile *)uip;
1158bf031b6Sdlg void *rv;
1168bf031b6Sdlg
1178bf031b6Sdlg eiem = atomic_enter();
1188bf031b6Sdlg rv = *uipp;
1198bf031b6Sdlg if (rv == o)
1208bf031b6Sdlg *uipp = n;
1218bf031b6Sdlg atomic_leave(eiem);
1228bf031b6Sdlg
1238bf031b6Sdlg return (rv);
1248bf031b6Sdlg }
1258bf031b6Sdlg #define atomic_cas_ptr(_p, _o, _n) _atomic_cas_ptr((_p), (_o), (_n))
1268bf031b6Sdlg
1278bf031b6Sdlg static inline unsigned int
_atomic_swap_uint(volatile unsigned int * uip,unsigned int n)1288bf031b6Sdlg _atomic_swap_uint(volatile unsigned int *uip, unsigned int n)
1298bf031b6Sdlg {
1308bf031b6Sdlg register_t eiem;
1318bf031b6Sdlg unsigned int rv;
1328bf031b6Sdlg
1338bf031b6Sdlg eiem = atomic_enter();
1348bf031b6Sdlg rv = *uip;
1358bf031b6Sdlg *uip = n;
1368bf031b6Sdlg atomic_leave(eiem);
1378bf031b6Sdlg
1388bf031b6Sdlg return (rv);
1398bf031b6Sdlg }
1408bf031b6Sdlg #define atomic_swap_uint(_p, _n) _atomic_swap_uint((_p), (_n))
1418bf031b6Sdlg
1428bf031b6Sdlg static inline unsigned long
_atomic_swap_ulong(volatile unsigned long * uip,unsigned long n)1438bf031b6Sdlg _atomic_swap_ulong(volatile unsigned long *uip, unsigned long n)
1448bf031b6Sdlg {
1458bf031b6Sdlg register_t eiem;
1468bf031b6Sdlg unsigned long rv;
1478bf031b6Sdlg
1488bf031b6Sdlg eiem = atomic_enter();
1498bf031b6Sdlg rv = *uip;
1508bf031b6Sdlg *uip = n;
1518bf031b6Sdlg atomic_leave(eiem);
1528bf031b6Sdlg
1538bf031b6Sdlg return (rv);
1548bf031b6Sdlg }
1553480ef41Sdlg #define atomic_swap_ulong(_p, _n) _atomic_swap_ulong((_p), (_n))
1568bf031b6Sdlg
1578bf031b6Sdlg static inline void *
_atomic_swap_ptr(volatile void * uip,void * n)1588bf031b6Sdlg _atomic_swap_ptr(volatile void *uip, void *n)
1598bf031b6Sdlg {
1608bf031b6Sdlg register_t eiem;
1618bf031b6Sdlg void * volatile *uipp = (void * volatile *)uip;
1628bf031b6Sdlg void *rv;
1638bf031b6Sdlg
1648bf031b6Sdlg eiem = atomic_enter();
1658bf031b6Sdlg rv = *uipp;
1668bf031b6Sdlg *uipp = n;
1678bf031b6Sdlg atomic_leave(eiem);
1688bf031b6Sdlg
1698bf031b6Sdlg return (rv);
1708bf031b6Sdlg }
1713480ef41Sdlg #define atomic_swap_ptr(_p, _n) _atomic_swap_ptr((_p), (_n))
1728bf031b6Sdlg
1738bf031b6Sdlg static __inline unsigned int
_atomic_add_int_nv(volatile unsigned int * uip,unsigned int v)1748bf031b6Sdlg _atomic_add_int_nv(volatile unsigned int *uip, unsigned int v)
1758bf031b6Sdlg {
1768bf031b6Sdlg register_t eiem;
1778bf031b6Sdlg unsigned int rv;
1788bf031b6Sdlg
1798bf031b6Sdlg eiem = atomic_enter();
1808bf031b6Sdlg rv = *uip + v;
1818bf031b6Sdlg *uip = rv;
1828bf031b6Sdlg atomic_leave(eiem);
1838bf031b6Sdlg
1848bf031b6Sdlg return (rv);
1858bf031b6Sdlg }
1868bf031b6Sdlg #define atomic_add_int_nv(_uip, _v) _atomic_add_int_nv((_uip), (_v))
1878bf031b6Sdlg #define atomic_sub_int_nv(_uip, _v) _atomic_add_int_nv((_uip), 0 - (_v))
1888bf031b6Sdlg
1898bf031b6Sdlg static __inline unsigned long
_atomic_add_long_nv(volatile unsigned long * uip,unsigned long v)1908bf031b6Sdlg _atomic_add_long_nv(volatile unsigned long *uip, unsigned long v)
1918bf031b6Sdlg {
1928bf031b6Sdlg register_t eiem;
1938bf031b6Sdlg unsigned long rv;
1948bf031b6Sdlg
1958bf031b6Sdlg eiem = atomic_enter();
1968bf031b6Sdlg rv = *uip + v;
1978bf031b6Sdlg *uip = rv;
1988bf031b6Sdlg atomic_leave(eiem);
1998bf031b6Sdlg
2008bf031b6Sdlg return (rv);
2018bf031b6Sdlg }
2028bf031b6Sdlg #define atomic_add_long_nv(_uip, _v) _atomic_add_long_nv((_uip), (_v))
2038bf031b6Sdlg #define atomic_sub_long_nv(_uip, _v) _atomic_add_long_nv((_uip), 0 - (_v))
2048bf031b6Sdlg
2058bf031b6Sdlg static __inline void
atomic_setbits_int(volatile unsigned int * uip,unsigned int v)2068bf031b6Sdlg atomic_setbits_int(volatile unsigned int *uip, unsigned int v)
2078bf031b6Sdlg {
2088bf031b6Sdlg register_t eiem;
2098bf031b6Sdlg
2108bf031b6Sdlg eiem = atomic_enter();
2118bf031b6Sdlg *uip |= v;
2128bf031b6Sdlg atomic_leave(eiem);
2138bf031b6Sdlg }
2148bf031b6Sdlg
215f57756c9Sart static __inline void
atomic_clearbits_int(volatile unsigned int * uip,unsigned int v)2162df76cc2Sguenther atomic_clearbits_int(volatile unsigned int *uip, unsigned int v)
217f57756c9Sart {
218f8b1aca5Smiod register_t eiem;
219f8b1aca5Smiod
2208bf031b6Sdlg eiem = atomic_enter();
221f57756c9Sart *uip &= ~v;
2228bf031b6Sdlg atomic_leave(eiem);
223f8b1aca5Smiod }
224f8b1aca5Smiod
225f8b1aca5Smiod static __inline void
atomic_setbits_long(volatile unsigned long * uip,unsigned long v)2262df76cc2Sguenther atomic_setbits_long(volatile unsigned long *uip, unsigned long v)
227f8b1aca5Smiod {
228f8b1aca5Smiod register_t eiem;
229f8b1aca5Smiod
2308bf031b6Sdlg eiem = atomic_enter();
231f8b1aca5Smiod *uip |= v;
2328bf031b6Sdlg atomic_leave(eiem);
233f8b1aca5Smiod }
234f8b1aca5Smiod
235f8b1aca5Smiod static __inline void
atomic_clearbits_long(volatile unsigned long * uip,unsigned long v)2362df76cc2Sguenther atomic_clearbits_long(volatile unsigned long *uip, unsigned long v)
237f8b1aca5Smiod {
238f8b1aca5Smiod register_t eiem;
239f8b1aca5Smiod
2408bf031b6Sdlg eiem = atomic_enter();
241f8b1aca5Smiod *uip &= ~v;
2428bf031b6Sdlg atomic_leave(eiem);
243f57756c9Sart }
244f57756c9Sart
245ca950ec4Skettenis #endif /* defined(_KERNEL) */
246ca950ec4Skettenis
247095af81fSkettenis /*
248095af81fSkettenis * Although the PA-RISC 2.0 architecture allows an implementation to
249*9bec9e43Sjsg * be weakly ordered, all PA-RISC processors to date implement a
250095af81fSkettenis * strong memory ordering model. So all we need is a compiler
251095af81fSkettenis * barrier.
252095af81fSkettenis */
253095af81fSkettenis
254095af81fSkettenis static inline void
__insn_barrier(void)255095af81fSkettenis __insn_barrier(void)
256095af81fSkettenis {
257095af81fSkettenis __asm volatile("" : : : "memory");
258095af81fSkettenis }
259095af81fSkettenis
260095af81fSkettenis #define membar_enter() __insn_barrier()
261095af81fSkettenis #define membar_exit() __insn_barrier()
262095af81fSkettenis #define membar_producer() __insn_barrier()
263095af81fSkettenis #define membar_consumer() __insn_barrier()
264095af81fSkettenis #define membar_sync() __insn_barrier()
265095af81fSkettenis
2662fa72412Spirofti #endif /* _MACHINE_ATOMIC_H_ */
267