diff options
author | Peter Zijlstra <peterz@infradead.org> | 2016-04-17 19:16:04 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-06-16 04:48:29 -0400 |
commit | 7d9794e7523798e1b9422ad9f4e4d808ae5d5932 (patch) | |
tree | 3a1a550803485049b8e8c2a434c0c9107831f3a6 | |
parent | 56fefbbc3f13ad8cc9f502dbc6b5c9ddc8c4395e (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.h | 34 | ||||
-rw-r--r-- | arch/sh/include/asm/atomic-irq.h | 31 | ||||
-rw-r--r-- | arch/sh/include/asm/atomic-llsc.h | 32 | ||||
-rw-r--r-- | arch/sh/include/asm/atomic.h | 2 |
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) \ |
47 | static 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 | ||
48 | ATOMIC_OPS(add) | 70 | ATOMIC_OPS(add) |
49 | ATOMIC_OPS(sub) | 71 | ATOMIC_OPS(sub) |
50 | 72 | ||
51 | ATOMIC_OP(and) | 73 | #undef ATOMIC_OPS |
52 | ATOMIC_OP(or) | 74 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) |
53 | ATOMIC_OP(xor) | 75 | |
76 | ATOMIC_OPS(and) | ||
77 | ATOMIC_OPS(or) | ||
78 | ATOMIC_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) \ |
37 | static 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 | ||
38 | ATOMIC_OPS(add, +=) | 54 | ATOMIC_OPS(add, +=) |
39 | ATOMIC_OPS(sub, -=) | 55 | ATOMIC_OPS(sub, -=) |
40 | ATOMIC_OP(and, &=) | ||
41 | ATOMIC_OP(or, |=) | ||
42 | ATOMIC_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 | |||
62 | ATOMIC_OPS(and, &=) | ||
63 | ATOMIC_OPS(or, |=) | ||
64 | ATOMIC_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) \ |
52 | static 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 | ||
53 | ATOMIC_OPS(add) | 72 | ATOMIC_OPS(add) |
54 | ATOMIC_OPS(sub) | 73 | ATOMIC_OPS(sub) |
55 | ATOMIC_OP(and) | ||
56 | ATOMIC_OP(or) | ||
57 | ATOMIC_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 | |||
78 | ATOMIC_OPS(and) | ||
79 | ATOMIC_OPS(or) | ||
80 | ATOMIC_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)) |