/* * Hacked atomics with hpa-specific lw.l/sw.u instructions */ #ifndef ATOMIC_H #define ATOMIC_H #include "compiler.h" typedef uint32_t atomic_t; #define lw_l(x) ({ \ volatile atomic_t *__p = (volatile atomic_t *)(x); \ atomic_t __v; \ asm inline volatile("lw.l %0,%1" \ : "=r" (__v), "+m" (*__p) \ : : "memory"); \ (typeof(*(x))) __v; \ }) static inline void _sw_u(volatile atomic_t *__p, atomic_t __v) { asm inline volatile("sw.u %1,%0" : "+m" (*__p) : "r" (__v) : "memory"); } #define sw_u(x,v) _sw_u((volatile atomic_t *)(x), (v)) /* Simple barrier-enforcing accessors */ static inline atomic_t atomic_get(const volatile atomic_t *_p) { atomic_t _v; asm inline volatile("lw %0,%1" : "=r" (_v) : "m" (*_p) : "memory"); return _v; } static inline void atomic_set(volatile atomic_t *_p, atomic_t _v) { asm inline volatile("sw %1,%0" : "=m" (*_p) : "r" (_v) : "memory"); } static inline atomic_t atomic_swap(volatile atomic_t *_p, atomic_t _v) { atomic_t _o = lw_l(_p); sw_u(_p, _v); return _o; } /* These functions all do read-modify-write returning the old or new values */ #define ATOMIC_OP2_RET(name, op, ret) \ static inline atomic_t \ atomic_ ## name (volatile atomic_t *_p, atomic_t _v) \ { \ atomic_t _o = lw_l(_p); \ atomic_t _n = _o op _v; \ sw_u(_p, _n); \ return ret; \ } #define ATOMIC_OP2(name, op) \ ATOMIC_OP2_RET(name, op, _n) \ ATOMIC_OP2_RET(xchg_ ## name, op, _o) ATOMIC_OP2(add, +) ATOMIC_OP2(sub, -) ATOMIC_OP2(and, &) ATOMIC_OP2(or, |) ATOMIC_OP2(xor, ^) static inline atomic_t atomic_xchg_and_xor(volatile atomic_t *_p, atomic_t _va, atomic_t _vx) { atomic_t _o = lw_l(_p); atomic_t _n = (_o & _va) ^ _vx; sw_u(_p, _n); return _o; } #endif /* ATOMIC_H */