Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Nov 2015 22:45:01 +1100
From:      George Abdelmalik <gabdelmalik@uniridge.com.au>
To:        Konstantin Belousov <kostikbel@gmail.com>
Cc:        freebsd-arm@freebsd.org
Subject:   Re: atomic_testandset_int seems unimplemented
Message-ID:  <563DE43D.7030107@uniridge.com.au>
In-Reply-To: <20151107113011.GW2257@kib.kiev.ua>
References:  <563DA3E8.2060802@uniridge.com.au> <20151107113011.GW2257@kib.kiev.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
On 07/11/15 22:30, Konstantin Belousov wrote:
> On Sat, Nov 07, 2015 at 06:10:32PM +1100, George Abdelmalik wrote:
>> Hi,
>>
>> My reading of atomic(9) implies that the atomic_testandset_* family of
>> functions should be present
>> on the arm architecture, however I don't see any evidence of it in any
>> of the expected locations,
>> ./sys/arm/include/atomic-v4.h
>> ./sys/arm/include/atomic-v6.h
>> ./sys/arm/include/atomic.h
>>
>> Is there some impediment within the architecture which doesn't make that
>> semantic possible or is
>> it just that there is no in-tree consumer yet?
> No consumers, apparently.  testandset has somewhat rarely needed semantic,
> and readandclear semantic is not complimentary, to confuse the users even
> more.
>
>> Any thoughts on this matter would be appreciated, or better yet a
>> possible implementation - sadly for
>> me assembly is not my strength.
> Below is the patch for ARMv6.  I did not tested the _64 implementation,
> and I also doubt that we run in big endian mode for ARMv6 at all.
> Do you also need an implementation for ARMv5 ?
No I don't need ARMv5, my target is a Xilinx Zynq SOC which is
ARMv7 that we will only run in little endian mode.

Thanks for the below patch. I will try it out tomorrow and report
back my experience.

George.
>
> diff --git a/sys/arm/include/atomic-v6.h b/sys/arm/include/atomic-v6.h
> index d22f7e1..9ee8043 100644
> --- a/sys/arm/include/atomic-v6.h
> +++ b/sys/arm/include/atomic-v6.h
> @@ -593,6 +593,60 @@ 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, [%3]        \n"
> +	"       orr     %1, %0, %4      \n"
> +	"       strex   %2, %1, [%3]    \n"
> +	"       cmp     %2, #0          \n"
> +	"       it      ne              \n"
> +	"       bne     1b              \n"
> +	: "=&r" (res), "=&r" (tmp), "=&r" (tmp2), "+&r" (p)
> +	: "r" (mask)
> +	: "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;
> +#if BYTE_ORDER == LITTLE_ENDIAN
> +	if (v >= 32) {
> +		v &= 0x1f;
> +		p32++;
> +	}
> +#else
> +	if (v >= 32)
> +		v &= 0x1f;
> +	else
> +		p32++;
> +#endif
> +	return (atomic_testandset_32(p32, v));
> +}
> +
>   #undef ATOMIC_ACQ_REL
>   #undef ATOMIC_ACQ_REL_LONG
>   




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?563DE43D.7030107>