aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2016-04-17 19:16:04 -0400
committerIngo Molnar <mingo@kernel.org>2016-06-16 04:48:29 -0400
commit7d9794e7523798e1b9422ad9f4e4d808ae5d5932 (patch)
tree3a1a550803485049b8e8c2a434c0c9107831f3a6
parent56fefbbc3f13ad8cc9f502dbc6b5c9ddc8c4395e (diff)
locking/atomic, arch/sh: Implement atomic_fetch_{add,sub,and,or,xor}()
Implement FETCH-OP atomic primitives, these are very similar to the existing OP-RETURN primitives we already have, except they return the value of the atomic variable _before_ modification. This is especially useful for irreversible operations -- such as bitops (because it becomes impossible to reconstruct the state prior to modification). Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rich Felker <dalias@libc.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: linux-arch@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-sh@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/sh/include/asm/atomic-grb.h34
-rw-r--r--arch/sh/include/asm/atomic-irq.h31
-rw-r--r--arch/sh/include/asm/atomic-llsc.h32
-rw-r--r--arch/sh/include/asm/atomic.h2
4 files changed, 87 insertions, 12 deletions
diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h
index b94df40e5f2d..d755e96c3064 100644
--- a/arch/sh/include/asm/atomic-grb.h
+++ b/arch/sh/include/asm/atomic-grb.h
@@ -43,16 +43,42 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
43 return tmp; \ 43 return tmp; \
44} 44}
45 45
46#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) 46#define ATOMIC_FETCH_OP(op) \
47static inline int atomic_fetch_##op(int i, atomic_t *v) \
48{ \
49 int res, tmp; \
50 \
51 __asm__ __volatile__ ( \
52 " .align 2 \n\t" \
53 " mova 1f, r0 \n\t" /* r0 = end point */ \
54 " mov r15, r1 \n\t" /* r1 = saved sp */ \
55 " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ \
56 " mov.l @%2, %0 \n\t" /* load old value */ \
57 " mov %0, %1 \n\t" /* save old value */ \
58 " " #op " %3, %0 \n\t" /* $op */ \
59 " mov.l %0, @%2 \n\t" /* store new value */ \
60 "1: mov r1, r15 \n\t" /* LOGOUT */ \
61 : "=&r" (tmp), "=&r" (res), "+r" (v) \
62 : "r" (i) \
63 : "memory" , "r0", "r1"); \
64 \
65 return res; \
66}
67
68#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
47 69
48ATOMIC_OPS(add) 70ATOMIC_OPS(add)
49ATOMIC_OPS(sub) 71ATOMIC_OPS(sub)
50 72
51ATOMIC_OP(and) 73#undef ATOMIC_OPS
52ATOMIC_OP(or) 74#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
53ATOMIC_OP(xor) 75
76ATOMIC_OPS(and)
77ATOMIC_OPS(or)
78ATOMIC_OPS(xor)
54 79
55#undef ATOMIC_OPS 80#undef ATOMIC_OPS
81#undef ATOMIC_FETCH_OP
56#undef ATOMIC_OP_RETURN 82#undef ATOMIC_OP_RETURN
57#undef ATOMIC_OP 83#undef ATOMIC_OP
58 84
diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h
index 23fcdad5773e..8e2da5fa0178 100644
--- a/arch/sh/include/asm/atomic-irq.h
+++ b/arch/sh/include/asm/atomic-irq.h
@@ -33,15 +33,38 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
33 return temp; \ 33 return temp; \
34} 34}
35 35
36#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) 36#define ATOMIC_FETCH_OP(op, c_op) \
37static inline int atomic_fetch_##op(int i, atomic_t *v) \
38{ \
39 unsigned long temp, flags; \
40 \
41 raw_local_irq_save(flags); \
42 temp = v->counter; \
43 v->counter c_op i; \
44 raw_local_irq_restore(flags); \
45 \
46 return temp; \
47}
48
49#define ATOMIC_OPS(op, c_op) \
50 ATOMIC_OP(op, c_op) \
51 ATOMIC_OP_RETURN(op, c_op) \
52 ATOMIC_FETCH_OP(op, c_op)
37 53
38ATOMIC_OPS(add, +=) 54ATOMIC_OPS(add, +=)
39ATOMIC_OPS(sub, -=) 55ATOMIC_OPS(sub, -=)
40ATOMIC_OP(and, &=)
41ATOMIC_OP(or, |=)
42ATOMIC_OP(xor, ^=)
43 56
44#undef ATOMIC_OPS 57#undef ATOMIC_OPS
58#define ATOMIC_OPS(op, c_op) \
59 ATOMIC_OP(op, c_op) \
60 ATOMIC_FETCH_OP(op, c_op)
61
62ATOMIC_OPS(and, &=)
63ATOMIC_OPS(or, |=)
64ATOMIC_OPS(xor, ^=)
65
66#undef ATOMIC_OPS
67#undef ATOMIC_FETCH_OP
45#undef ATOMIC_OP_RETURN 68#undef ATOMIC_OP_RETURN
46#undef ATOMIC_OP 69#undef ATOMIC_OP
47 70
diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h
index 33d34b16d4d6..caea2c45f6c2 100644
--- a/arch/sh/include/asm/atomic-llsc.h
+++ b/arch/sh/include/asm/atomic-llsc.h
@@ -48,15 +48,39 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \
48 return temp; \ 48 return temp; \
49} 49}
50 50
51#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) 51#define ATOMIC_FETCH_OP(op) \
52static inline int atomic_fetch_##op(int i, atomic_t *v) \
53{ \
54 unsigned long res, temp; \
55 \
56 __asm__ __volatile__ ( \
57"1: movli.l @%3, %0 ! atomic_fetch_" #op " \n" \
58" mov %0, %1 \n" \
59" " #op " %2, %0 \n" \
60" movco.l %0, @%3 \n" \
61" bf 1b \n" \
62" synco \n" \
63 : "=&z" (temp), "=&z" (res) \
64 : "r" (i), "r" (&v->counter) \
65 : "t"); \
66 \
67 return res; \
68}
69
70#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
52 71
53ATOMIC_OPS(add) 72ATOMIC_OPS(add)
54ATOMIC_OPS(sub) 73ATOMIC_OPS(sub)
55ATOMIC_OP(and)
56ATOMIC_OP(or)
57ATOMIC_OP(xor)
58 74
59#undef ATOMIC_OPS 75#undef ATOMIC_OPS
76#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
77
78ATOMIC_OPS(and)
79ATOMIC_OPS(or)
80ATOMIC_OPS(xor)
81
82#undef ATOMIC_OPS
83#undef ATOMIC_FETCH_OP
60#undef ATOMIC_OP_RETURN 84#undef ATOMIC_OP_RETURN
61#undef ATOMIC_OP 85#undef ATOMIC_OP
62 86
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h
index c399e1c55685..d93ed7ce1b2f 100644
--- a/arch/sh/include/asm/atomic.h
+++ b/arch/sh/include/asm/atomic.h
@@ -25,6 +25,8 @@
25#include <asm/atomic-irq.h> 25#include <asm/atomic-irq.h>
26#endif 26#endif
27 27
28#define atomic_fetch_or atomic_fetch_or
29
28#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) 30#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
29#define atomic_dec_return(v) atomic_sub_return(1, (v)) 31#define atomic_dec_return(v) atomic_sub_return(1, (v))
30#define atomic_inc_return(v) atomic_add_return(1, (v)) 32#define atomic_inc_return(v) atomic_add_return(1, (v))