summaryrefslogtreecommitdiff
path: root/arch/mips/include/asm/local.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/include/asm/local.h')
-rw-r--r--arch/mips/include/asm/local.h99
1 files changed, 43 insertions, 56 deletions
diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h
index 02783e141c32..86fc24022242 100644
--- a/arch/mips/include/asm/local.h
+++ b/arch/mips/include/asm/local.h
@@ -5,9 +5,9 @@
#include <linux/percpu.h>
#include <linux/bitops.h>
#include <linux/atomic.h>
+#include <asm/asm.h>
#include <asm/cmpxchg.h>
#include <asm/compiler.h>
-#include <asm/war.h>
typedef struct
{
@@ -31,32 +31,18 @@ static __inline__ long local_add_return(long i, local_t * l)
{
unsigned long result;
- if (kernel_uses_llsc && R10000_LLSC_WAR) {
- unsigned long temp;
-
- __asm__ __volatile__(
- " .set push \n"
- " .set arch=r4000 \n"
- "1:" __LL "%1, %2 # local_add_return \n"
- " addu %0, %1, %3 \n"
- __SC "%0, %2 \n"
- " beqzl %0, 1b \n"
- " addu %0, %1, %3 \n"
- " .set pop \n"
- : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
- : "Ir" (i), "m" (l->a.counter)
- : "memory");
- } else if (kernel_uses_llsc) {
+ if (kernel_uses_llsc) {
unsigned long temp;
__asm__ __volatile__(
" .set push \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
- "1:" __LL "%1, %2 # local_add_return \n"
- " addu %0, %1, %3 \n"
- __SC "%0, %2 \n"
- " beqz %0, 1b \n"
- " addu %0, %1, %3 \n"
+ __SYNC(full, loongson3_war) " \n"
+ "1:" __stringify(LONG_LL) " %1, %2 \n"
+ __stringify(LONG_ADDU) " %0, %1, %3 \n"
+ __stringify(LONG_SC) " %0, %2 \n"
+ __stringify(SC_BEQZ) " %0, 1b \n"
+ __stringify(LONG_ADDU) " %0, %1, %3 \n"
" .set pop \n"
: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
: "Ir" (i), "m" (l->a.counter)
@@ -78,32 +64,19 @@ static __inline__ long local_sub_return(long i, local_t * l)
{
unsigned long result;
- if (kernel_uses_llsc && R10000_LLSC_WAR) {
- unsigned long temp;
-
- __asm__ __volatile__(
- " .set push \n"
- " .set arch=r4000 \n"
- "1:" __LL "%1, %2 # local_sub_return \n"
- " subu %0, %1, %3 \n"
- __SC "%0, %2 \n"
- " beqzl %0, 1b \n"
- " subu %0, %1, %3 \n"
- " .set pop \n"
- : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
- : "Ir" (i), "m" (l->a.counter)
- : "memory");
- } else if (kernel_uses_llsc) {
+ if (kernel_uses_llsc) {
unsigned long temp;
__asm__ __volatile__(
" .set push \n"
" .set "MIPS_ISA_ARCH_LEVEL" \n"
- "1:" __LL "%1, %2 # local_sub_return \n"
- " subu %0, %1, %3 \n"
- __SC "%0, %2 \n"
- " beqz %0, 1b \n"
- " subu %0, %1, %3 \n"
+ __SYNC(full, loongson3_war) " \n"
+ "1:" __stringify(LONG_LL) " %1, %2 \n"
+ __stringify(LONG_SUBU) " %0, %1, %3 \n"
+ __stringify(LONG_SUBU) " %0, %1, %3 \n"
+ __stringify(LONG_SC) " %0, %2 \n"
+ __stringify(SC_BEQZ) " %0, 1b \n"
+ __stringify(LONG_SUBU) " %0, %1, %3 \n"
" .set pop \n"
: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
: "Ir" (i), "m" (l->a.counter)
@@ -121,27 +94,41 @@ static __inline__ long local_sub_return(long i, local_t * l)
return result;
}
-#define local_cmpxchg(l, o, n) \
- ((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
+static __inline__ long local_cmpxchg(local_t *l, long old, long new)
+{
+ return cmpxchg_local(&l->a.counter, old, new);
+}
+
+static __inline__ bool local_try_cmpxchg(local_t *l, long *old, long new)
+{
+ return try_cmpxchg_local(&l->a.counter,
+ (typeof(l->a.counter) *) old, new);
+}
+
#define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n)))
/**
- * local_add_unless - add unless the number is a given value
+ * local_add_unless - add unless the number is already a given value
* @l: pointer of type local_t
* @a: the amount to add to l...
* @u: ...unless l is equal to u.
*
- * Atomically adds @a to @l, so long as it was not @u.
- * Returns non-zero if @l was not @u, and zero otherwise.
+ * Atomically adds @a to @l, if @v was not already @u.
+ * Returns true if the addition was done.
*/
-#define local_add_unless(l, a, u) \
-({ \
- long c, old; \
- c = local_read(l); \
- while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ bool
+local_add_unless(local_t *l, long a, long u)
+{
+ long c = local_read(l);
+
+ do {
+ if (unlikely(c == u))
+ return false;
+ } while (!local_try_cmpxchg(l, &c, c + a));
+
+ return true;
+}
+
#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
#define local_dec_return(l) local_sub_return(1, (l))