2013-01-22 22:53:24 +04:00
|
|
|
#ifndef __CR_ATOMIC_H__
|
|
|
|
#define __CR_ATOMIC_H__
|
|
|
|
|
2016-10-24 14:58:07 +03:00
|
|
|
#include "common/arch/arm/asm/processor.h"
|
2014-12-03 19:28:00 +02:00
|
|
|
|
2013-01-22 22:53:24 +04:00
|
|
|
typedef struct {
|
2013-08-16 19:31:55 +04:00
|
|
|
int counter;
|
2013-01-22 22:53:24 +04:00
|
|
|
} atomic_t;
|
|
|
|
|
|
|
|
|
|
|
|
/* Copied from the Linux kernel header arch/arm/include/asm/atomic.h */
|
|
|
|
|
2013-07-10 10:15:55 +04:00
|
|
|
#if defined(CONFIG_ARMV7)
|
|
|
|
|
2013-01-22 22:53:24 +04:00
|
|
|
#define smp_mb() __asm__ __volatile__ ("dmb" : : : "memory")
|
|
|
|
|
2014-12-22 14:16:00 +03:00
|
|
|
static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
|
|
|
|
{
|
|
|
|
int oldval;
|
|
|
|
unsigned long res;
|
|
|
|
|
|
|
|
smp_mb();
|
|
|
|
prefetchw(&ptr->counter);
|
|
|
|
|
|
|
|
do {
|
|
|
|
__asm__ __volatile__("@ atomic_cmpxchg\n"
|
|
|
|
"ldrex %1, [%3]\n"
|
|
|
|
"mov %0, #0\n"
|
|
|
|
"teq %1, %4\n"
|
arm: rm -Wa from CFLAGS
Somehow clang doesn't always like -Wa flags, for example when making
dependencies (see commit 9303ed3 ("Makefiles: move -Wa,--noexecstack
out of CFLAGS"), which causes build break, scary error messages, and
even hair loss.
There are many ways to solve this. This patch employs the one
that is simple and clean.
The -Wa,-mimplicit-it=always flag was added by commit 79c4b74
("arm: fix compilation on ARMv7"). The reason is, ARM needs an IT
instruction before certain conditionals. Those IT instructions are
almost always automatically generated by assembler itself, but in some
cases a special assembler flag (like the one above) is needed.
As there is only one place in the code that need IT, it's easy to patch
it (add explicit IT) and remove the flag. Note that "IT" generates
no machine code per se, so there should not be any functional change
(although I haven't checked it).
For more info on IT, see http://tinyurl.com/z3ldsdr
Hope for a review from our ARM experts.
travis-ci: success for Fixes to compile on arm with clang
Cc: Christopher Covington <cov@codeaurora.org>
Cc: Dmitry Safonov <dsafonov@virtuozzo.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
2016-11-03 16:39:39 -07:00
|
|
|
"it eq\n"
|
2014-12-22 14:16:00 +03:00
|
|
|
"strexeq %0, %5, [%3]\n"
|
|
|
|
: "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter)
|
|
|
|
: "r" (&ptr->counter), "Ir" (old), "r" (new)
|
|
|
|
: "cc");
|
|
|
|
} while (res);
|
|
|
|
|
|
|
|
smp_mb();
|
|
|
|
|
|
|
|
return oldval;
|
|
|
|
}
|
|
|
|
|
2013-07-10 10:15:55 +04:00
|
|
|
#elif defined(CONFIG_ARMV6)
|
|
|
|
|
2014-12-22 14:16:00 +03:00
|
|
|
/* SMP isn't supported for ARMv6 */
|
|
|
|
|
2013-07-10 10:15:55 +04:00
|
|
|
#define smp_mb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory")
|
|
|
|
|
2014-12-22 14:16:00 +03:00
|
|
|
static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = v->counter;
|
|
|
|
if (ret == old)
|
|
|
|
v->counter = new;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-07 21:04:00 +04:00
|
|
|
#else
|
|
|
|
|
|
|
|
#error ARM architecture version (CONFIG_ARMV*) not set or unsupported.
|
|
|
|
|
2013-07-10 10:15:55 +04:00
|
|
|
#endif
|
|
|
|
|
2013-08-16 19:31:56 +04:00
|
|
|
static inline int atomic_read(const atomic_t *v)
|
|
|
|
{
|
|
|
|
return (*(volatile int *)&(v)->counter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void atomic_set(atomic_t *v, int i)
|
|
|
|
{
|
|
|
|
v->counter = i;
|
|
|
|
}
|
2013-07-10 10:15:55 +04:00
|
|
|
|
2013-08-16 19:31:56 +04:00
|
|
|
#define atomic_get atomic_read
|
2013-01-22 22:53:24 +04:00
|
|
|
|
2013-08-16 19:31:54 +04:00
|
|
|
static inline int atomic_add_return(int i, atomic_t *v)
|
2013-01-22 22:53:24 +04:00
|
|
|
{
|
|
|
|
unsigned long tmp;
|
2013-08-16 19:31:54 +04:00
|
|
|
int result;
|
2013-01-22 22:53:24 +04:00
|
|
|
|
|
|
|
smp_mb();
|
|
|
|
|
|
|
|
__asm__ __volatile__("@ atomic_add_return\n"
|
|
|
|
"1: ldrex %0, [%3]\n"
|
|
|
|
" add %0, %0, %4\n"
|
|
|
|
" strex %1, %0, [%3]\n"
|
|
|
|
" teq %1, #0\n"
|
|
|
|
" bne 1b\n"
|
|
|
|
: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
|
|
|
|
: "r" (&v->counter), "Ir" (i)
|
|
|
|
: "cc");
|
|
|
|
|
|
|
|
smp_mb();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-08-16 19:31:54 +04:00
|
|
|
static inline int atomic_sub_return(int i, atomic_t *v)
|
2013-01-22 22:53:24 +04:00
|
|
|
{
|
|
|
|
unsigned long tmp;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
smp_mb();
|
|
|
|
|
|
|
|
__asm__ __volatile__("@ atomic_sub_return\n"
|
|
|
|
"1: ldrex %0, [%3]\n"
|
|
|
|
" sub %0, %0, %4\n"
|
|
|
|
" strex %1, %0, [%3]\n"
|
|
|
|
" teq %1, #0\n"
|
|
|
|
" bne 1b\n"
|
|
|
|
: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
|
|
|
|
: "r" (&v->counter), "Ir" (i)
|
|
|
|
: "cc");
|
|
|
|
|
|
|
|
smp_mb();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-08-16 19:31:54 +04:00
|
|
|
static inline int atomic_inc(atomic_t *v) { return atomic_add_return(1, v) - 1; }
|
2013-01-22 22:53:24 +04:00
|
|
|
|
2013-08-16 19:31:55 +04:00
|
|
|
static inline int atomic_add(int val, atomic_t *v) { return atomic_add_return(val, v) - val; }
|
2013-08-13 20:05:43 +04:00
|
|
|
|
2013-08-16 19:31:54 +04:00
|
|
|
static inline int atomic_dec(atomic_t *v) { return atomic_sub_return(1, v) + 1; }
|
2013-01-22 22:53:24 +04:00
|
|
|
|
|
|
|
/* true if the result is 0, or false for all other cases. */
|
|
|
|
#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
|
2016-11-01 19:35:23 +03:00
|
|
|
#define atomic_dec_return(v) (atomic_sub_return(1, v))
|
2013-01-22 22:53:24 +04:00
|
|
|
|
2013-08-16 19:31:55 +04:00
|
|
|
#define atomic_inc_return(v) (atomic_add_return(1, v))
|
|
|
|
|
2013-01-22 22:53:24 +04:00
|
|
|
#endif /* __CR_ATOMIC_H__ */
|