Implement atomic_testandset_{32,int,long,64} for ARMv6. Only

little-endian configuration for 64-bit variant is supported.

Reviewed by:	mmel
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D4113
This commit is contained in:
kib 2015-11-10 12:15:13 +00:00
parent 4e3a5b4299
commit 60024cd7aa

View File

@ -593,6 +593,54 @@ atomic_store_rel_long(volatile u_long *p, u_long v)
*p = v;
}
static __inline int
atomic_testandset_32(volatile uint32_t *p, u_int v)
{
uint32_t tmp, tmp2, res, mask;
mask = 1u << (v & 0x1f);
tmp = tmp2 = 0;
__asm __volatile(
"1: ldrex %0, [%4] \n"
" orr %1, %0, %3 \n"
" strex %2, %1, [%4] \n"
" cmp %2, #0 \n"
" it ne \n"
" bne 1b \n"
: "=&r" (res), "=&r" (tmp), "=&r" (tmp2)
: "r" (mask), "r" (p)
: "cc", "memory");
return ((res & mask) != 0);
}
static __inline int
atomic_testandset_int(volatile u_int *p, u_int v)
{
return (atomic_testandset_32((volatile uint32_t *)p, v));
}
static __inline int
atomic_testandset_long(volatile u_long *p, u_int v)
{
return (atomic_testandset_32((volatile uint32_t *)p, v));
}
static __inline int
atomic_testandset_64(volatile uint64_t *p, u_int v)
{
volatile uint32_t *p32;
p32 = (volatile uint32_t *)p;
/* Assume little-endian */
if (v >= 32) {
v &= 0x1f;
p32++;
}
return (atomic_testandset_32(p32, v));
}
#undef ATOMIC_ACQ_REL
#undef ATOMIC_ACQ_REL_LONG