1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#ifndef __CR_ATOMIC_H__
#define __CR_ATOMIC_H__
#include "common/arch/arm/asm/processor.h"
typedef struct {
int counter;
} atomic_t;
/* Copied from the Linux kernel header arch/arm/include/asm/atomic.h */
#if defined(CONFIG_ARMV7)
#define smp_mb() __asm__ __volatile__("dmb" : : : "memory")
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"
"it eq\n"
"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;
}
#elif defined(CONFIG_ARMV6)
/* SMP isn't supported for ARMv6 */
#define smp_mb() __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
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;
}
#else
#error ARM architecture version (CONFIG_ARMV*) not set or unsupported.
#endif
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;
}
#define atomic_get atomic_read
static inline int atomic_add_return(int i, atomic_t *v)
{
unsigned long tmp;
int result;
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;
}
static inline int atomic_sub_return(int i, atomic_t *v)
{
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;
}
static inline int atomic_inc(atomic_t *v)
{
return atomic_add_return(1, v) - 1;
}
static inline int atomic_add(int val, atomic_t *v)
{
return atomic_add_return(val, v) - val;
}
static inline int atomic_dec(atomic_t *v)
{
return atomic_sub_return(1, v) + 1;
}
/* true if the result is 0, or false for all other cases. */
#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
#define atomic_dec_return(v) (atomic_sub_return(1, v))
#define atomic_inc_return(v) (atomic_add_return(1, v))
#endif /* __CR_ATOMIC_H__ */
|