Merge branches 'work.misc' and 'work.dcache' of git://git.kernel.org/pub/scm/linux...
[sfrench/cifs-2.6.git] / arch / mips / include / asm / atomic.h
index 79be687de4ab8f358857eb1500a7335fda77ac01..0269b3de8b5197ab171ea9e4e4870ab4fe68dea9 100644 (file)
 #include <asm/cmpxchg.h>
 #include <asm/war.h>
 
+/*
+ * Using a branch-likely instruction to check the result of an sc instruction
+ * works around a bug present in R10000 CPUs prior to revision 3.0 that could
+ * cause ll-sc sequences to execute non-atomically.
+ */
+#if R10000_LLSC_WAR
+# define __scbeqz "beqzl"
+#else
+# define __scbeqz "beqz"
+#endif
+
 #define ATOMIC_INIT(i)   { (i) }
 
 /*
 #define ATOMIC_OP(op, c_op, asm_op)                                          \
 static __inline__ void atomic_##op(int i, atomic_t * v)                              \
 {                                                                            \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                int temp;                                                     \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     ll      %0, %1          # atomic_" #op "        \n"   \
                "       " #asm_op " %0, %2                              \n"   \
                "       sc      %0, %1                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)          \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               int temp;                                                     \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       ll      %0, %1          # atomic_" #op "\n"   \
-                       "       " #asm_op " %0, %2                      \n"   \
-                       "       sc      %0, %1                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)  \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!temp));                                    \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@ -83,36 +81,20 @@ static __inline__ int atomic_##op##_return_relaxed(int i, atomic_t * v)           \
 {                                                                            \
        int result;                                                           \
                                                                              \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                int temp;                                                     \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     ll      %1, %2          # atomic_" #op "_return \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       sc      %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               int temp;                                                     \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       ll      %1, %2  # atomic_" #op "_return \n"   \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       sc      %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "+" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp; result c_op i;                                 \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@ -131,36 +113,20 @@ static __inline__ int atomic_fetch_##op##_relaxed(int i, atomic_t * v)          \
 {                                                                            \
        int result;                                                           \
                                                                              \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                int temp;                                                     \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     ll      %1, %2          # atomic_fetch_" #op "  \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       sc      %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       move    %0, %1                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               int temp;                                                     \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       ll      %1, %2  # atomic_fetch_" #op "  \n"   \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       sc      %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "+" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp;                                                \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@ -218,38 +184,17 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 
        smp_mb__before_llsc();
 
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               int temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     ll      %1, %2          # atomic_sub_if_positive\n"
-               "       subu    %0, %1, %3                              \n"
-               "       bltz    %0, 1f                                  \n"
-               "       sc      %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqzl   %0, 1b                                  \n"
-               "        subu   %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
-               "1:                                                     \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp),
-                 "+" GCC_OFF_SMALL_ASM() (v->counter)
-               : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)
-               : "memory");
-       } else if (kernel_uses_llsc) {
+       if (kernel_uses_llsc) {
                int temp;
 
                __asm__ __volatile__(
                "       .set    "MIPS_ISA_LEVEL"                        \n"
                "1:     ll      %1, %2          # atomic_sub_if_positive\n"
                "       subu    %0, %1, %3                              \n"
+               "       move    %1, %0                                  \n"
                "       bltz    %0, 1f                                  \n"
-               "       sc      %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqz    %0, 1b                                  \n"
-               "        subu   %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
+               "       sc      %1, %2                                  \n"
+               "\t" __scbeqz " %1, 1b                                  \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp),
@@ -301,31 +246,18 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 #define ATOMIC64_OP(op, c_op, asm_op)                                        \
 static __inline__ void atomic64_##op(long i, atomic64_t * v)                 \
 {                                                                            \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                long temp;                                                    \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     lld     %0, %1          # atomic64_" #op "      \n"   \
                "       " #asm_op " %0, %2                              \n"   \
                "       scd     %0, %1                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)          \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               long temp;                                                    \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       lld     %0, %1          # atomic64_" #op "\n" \
-                       "       " #asm_op " %0, %2                      \n"   \
-                       "       scd     %0, %1                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (temp), "+" GCC_OFF_SMALL_ASM() (v->counter)      \
-                       : "Ir" (i));                                          \
-               } while (unlikely(!temp));                                    \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@ -340,37 +272,20 @@ static __inline__ long atomic64_##op##_return_relaxed(long i, atomic64_t * v) \
 {                                                                            \
        long result;                                                          \
                                                                              \
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {                            \
+       if (kernel_uses_llsc) {                                               \
                long temp;                                                    \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     lld     %1, %2          # atomic64_" #op "_return\n"  \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       scd     %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               long temp;                                                    \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       lld     %1, %2  # atomic64_" #op "_return\n"  \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       scd     %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "=" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)          \
-                       : "memory");                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp; result c_op i;                                 \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@ -393,33 +308,16 @@ static __inline__ long atomic64_fetch_##op##_relaxed(long i, atomic64_t * v)  \
                long temp;                                                    \
                                                                              \
                __asm__ __volatile__(                                         \
-               "       .set    arch=r4000                              \n"   \
+               "       .set    "MIPS_ISA_LEVEL"                        \n"   \
                "1:     lld     %1, %2          # atomic64_fetch_" #op "\n"   \
                "       " #asm_op " %0, %1, %3                          \n"   \
                "       scd     %0, %2                                  \n"   \
-               "       beqzl   %0, 1b                                  \n"   \
+               "\t" __scbeqz " %0, 1b                                  \n"   \
                "       move    %0, %1                                  \n"   \
                "       .set    mips0                                   \n"   \
                : "=&r" (result), "=&r" (temp),                               \
                  "+" GCC_OFF_SMALL_ASM() (v->counter)                        \
                : "Ir" (i));                                                  \
-       } else if (kernel_uses_llsc) {                                        \
-               long temp;                                                    \
-                                                                             \
-               do {                                                          \
-                       __asm__ __volatile__(                                 \
-                       "       .set    "MIPS_ISA_LEVEL"                \n"   \
-                       "       lld     %1, %2  # atomic64_fetch_" #op "\n"   \
-                       "       " #asm_op " %0, %1, %3                  \n"   \
-                       "       scd     %0, %2                          \n"   \
-                       "       .set    mips0                           \n"   \
-                       : "=&r" (result), "=&r" (temp),                       \
-                         "=" GCC_OFF_SMALL_ASM() (v->counter)                \
-                       : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)          \
-                       : "memory");                                          \
-               } while (unlikely(!result));                                  \
-                                                                             \
-               result = temp;                                                \
        } else {                                                              \
                unsigned long flags;                                          \
                                                                              \
@@ -478,38 +376,17 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
 
        smp_mb__before_llsc();
 
-       if (kernel_uses_llsc && R10000_LLSC_WAR) {
-               long temp;
-
-               __asm__ __volatile__(
-               "       .set    arch=r4000                              \n"
-               "1:     lld     %1, %2          # atomic64_sub_if_positive\n"
-               "       dsubu   %0, %1, %3                              \n"
-               "       bltz    %0, 1f                                  \n"
-               "       scd     %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqzl   %0, 1b                                  \n"
-               "        dsubu  %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
-               "1:                                                     \n"
-               "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp),
-                 "=" GCC_OFF_SMALL_ASM() (v->counter)
-               : "Ir" (i), GCC_OFF_SMALL_ASM() (v->counter)
-               : "memory");
-       } else if (kernel_uses_llsc) {
+       if (kernel_uses_llsc) {
                long temp;
 
                __asm__ __volatile__(
                "       .set    "MIPS_ISA_LEVEL"                        \n"
                "1:     lld     %1, %2          # atomic64_sub_if_positive\n"
                "       dsubu   %0, %1, %3                              \n"
+               "       move    %1, %0                                  \n"
                "       bltz    %0, 1f                                  \n"
-               "       scd     %0, %2                                  \n"
-               "       .set    noreorder                               \n"
-               "       beqz    %0, 1b                                  \n"
-               "        dsubu  %0, %1, %3                              \n"
-               "       .set    reorder                                 \n"
+               "       scd     %1, %2                                  \n"
+               "\t" __scbeqz " %1, 1b                                  \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
                : "=&r" (result), "=&r" (temp),