[MIPS] Improve branch prediction in ll/sc atomic operations.
[pandora-kernel.git] / include / asm-mips / spinlock.h
index 4d0135b..f1755d2 100644 (file)
@@ -3,23 +3,23 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 06 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
 #ifndef _ASM_SPINLOCK_H
 #define _ASM_SPINLOCK_H
 
-#include <linux/config.h>
+#include <asm/barrier.h>
 #include <asm/war.h>
 
 /*
  * Your basic SMP spinlocks, allowing only a single CPU anywhere
  */
 
-#define __raw_spin_is_locked(x)        ((x)->lock != 0)
+#define __raw_spin_is_locked(x)       ((x)->lock != 0)
 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
 #define __raw_spin_unlock_wait(x) \
-               do { cpu_relax(); } while ((x)->lock)
+       do { cpu_relax(); } while ((x)->lock)
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
@@ -41,7 +41,6 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               "       sync                                            \n"
                "       .set    reorder                                 \n"
                : "=m" (lock->lock), "=&r" (tmp)
                : "m" (lock->lock)
@@ -50,23 +49,33 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                __asm__ __volatile__(
                "       .set    noreorder       # __raw_spin_lock       \n"
                "1:     ll      %1, %2                                  \n"
-               "       bnez    %1, 1b                                  \n"
+               "       bnez    %1, 2f                                  \n"
                "        li     %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
-               "        sync                                           \n"
+               "       beqz    %1, 2f                                  \n"
+               "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     ll      %1, %2                                  \n"
+               "       bnez    %1, 2b                                  \n"
+               "        li     %1, 1                                   \n"
+               "       b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (lock->lock), "=&r" (tmp)
                : "m" (lock->lock)
                : "memory");
        }
+
+       smp_mb();
 }
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
 {
+       smp_mb();
+
        __asm__ __volatile__(
        "       .set    noreorder       # __raw_spin_unlock     \n"
-       "       sync                                            \n"
        "       sw      $0, %0                                  \n"
        "       .set\treorder                                   \n"
        : "=m" (lock->lock)
@@ -87,7 +96,6 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
                "       beqzl   %2, 1b                                  \n"
                "        nop                                            \n"
                "       andi    %2, %0, 1                               \n"
-               "       sync                                            \n"
                "       .set    reorder"
                : "=&r" (temp), "=m" (lock->lock), "=&r" (res)
                : "m" (lock->lock)
@@ -98,15 +106,20 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
                "1:     ll      %0, %3                                  \n"
                "       ori     %2, %0, 1                               \n"
                "       sc      %2, %1                                  \n"
-               "       beqz    %2, 1b                                  \n"
+               "       beqz    %2, 2f                                  \n"
                "        andi   %2, %0, 1                               \n"
-               "       sync                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder"
                : "=&r" (temp), "=m" (lock->lock), "=&r" (res)
                : "m" (lock->lock)
                : "memory");
        }
 
+       smp_mb();
+
        return res == 0;
 }
 
@@ -119,6 +132,18 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
  * read-locks.
  */
 
+/*
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_read_can_lock(rw)        ((rw)->lock >= 0)
+
+/*
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define __raw_write_can_lock(rw)       (!(rw)->lock)
+
 static inline void __raw_read_lock(raw_rwlock_t *rw)
 {
        unsigned int tmp;
@@ -132,7 +157,6 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               "       sync                                            \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
@@ -141,16 +165,25 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
                __asm__ __volatile__(
                "       .set    noreorder       # __raw_read_lock       \n"
                "1:     ll      %1, %2                                  \n"
-               "       bltz    %1, 1b                                  \n"
+               "       bltz    %1, 2f                                  \n"
                "        addu   %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
                "       beqz    %1, 1b                                  \n"
-               "        sync                                           \n"
+               "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     ll      %1, %2                                  \n"
+               "       bltz    %1, 2b                                  \n"
+               "        addu   %1, 1                                   \n"
+               "       b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
                : "memory");
        }
+
+       smp_mb();
 }
 
 /* Note the use of sub, not subu which will make the kernel die with an
@@ -160,13 +193,14 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
 {
        unsigned int tmp;
 
+       smp_mb();
+
        if (R10000_LLSC_WAR) {
                __asm__ __volatile__(
                "1:     ll      %1, %2          # __raw_read_unlock     \n"
                "       sub     %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
-               "       sync                                            \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
                : "memory");
@@ -176,8 +210,12 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
                "1:     ll      %1, %2                                  \n"
                "       sub     %1, 1                                   \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
-               "        sync                                           \n"
+               "       beqz    %1, 2f                                  \n"
+               "        nop                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
@@ -198,7 +236,6 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               "       sync                                            \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
@@ -207,30 +244,82 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
                __asm__ __volatile__(
                "       .set    noreorder       # __raw_write_lock      \n"
                "1:     ll      %1, %2                                  \n"
-               "       bnez    %1, 1b                                  \n"
+               "       bnez    %1, 2f                                  \n"
                "        lui    %1, 0x8000                              \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
+               "       beqz    %1, 2f                                  \n"
                "        nop                                            \n"
-               "       sync                                            \n"
+               "       .subsection 2                                   \n"
+               "2:     ll      %1, %2                                  \n"
+               "       bnez    %1, 2b                                  \n"
+               "        lui    %1, 0x8000                              \n"
+               "       b       1b                                      \n"
+               "        nop                                            \n"
+               "       .previous                                       \n"
                "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp)
                : "m" (rw->lock)
                : "memory");
        }
+
+       smp_mb();
 }
 
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
 {
+       smp_mb();
+
        __asm__ __volatile__(
-       "       sync                    # __raw_write_unlock    \n"
+       "                               # __raw_write_unlock    \n"
        "       sw      $0, %0                                  \n"
        : "=m" (rw->lock)
        : "m" (rw->lock)
        : "memory");
 }
 
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
+{
+       unsigned int tmp;
+       int ret;
+
+       if (R10000_LLSC_WAR) {
+               __asm__ __volatile__(
+               "       .set    noreorder       # __raw_read_trylock    \n"
+               "       li      %2, 0                                   \n"
+               "1:     ll      %1, %3                                  \n"
+               "       bnez    %1, 2f                                  \n"
+               "        addu   %1, 1                                   \n"
+               "       sc      %1, %0                                  \n"
+               "       .set    reorder                                 \n"
+               "       beqzl   %1, 1b                                  \n"
+               "        nop                                            \n"
+               __WEAK_ORDERING_MB
+               "       li      %2, 1                                   \n"
+               "2:                                                     \n"
+               : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+               : "m" (rw->lock)
+               : "memory");
+       } else {
+               __asm__ __volatile__(
+               "       .set    noreorder       # __raw_read_trylock    \n"
+               "       li      %2, 0                                   \n"
+               "1:     ll      %1, %3                                  \n"
+               "       bnez    %1, 2f                                  \n"
+               "        addu   %1, 1                                   \n"
+               "       sc      %1, %0                                  \n"
+               "       beqz    %1, 1b                                  \n"
+               "        nop                                            \n"
+               "       .set    reorder                                 \n"
+               __WEAK_ORDERING_MB
+               "       li      %2, 1                                   \n"
+               "2:                                                     \n"
+               : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+               : "m" (rw->lock)
+               : "memory");
+       }
+
+       return ret;
+}
 
 static inline int __raw_write_trylock(raw_rwlock_t *rw)
 {
@@ -247,7 +336,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               "       sync                                            \n"
+               __WEAK_ORDERING_MB
                "       li      %2, 1                                   \n"
                "       .set    reorder                                 \n"
                "2:                                                     \n"
@@ -262,11 +351,15 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       bnez    %1, 2f                                  \n"
                "       lui     %1, 0x8000                              \n"
                "       sc      %1, %0                                  \n"
-               "       beqz    %1, 1b                                  \n"
-               "        sync                                           \n"
-               "       li      %2, 1                                   \n"
-               "       .set    reorder                                 \n"
+               "       beqz    %1, 3f                                  \n"
+               "        li     %2, 1                                   \n"
                "2:                                                     \n"
+               __WEAK_ORDERING_MB
+               "       .subsection 2                                   \n"
+               "3:     b       1b                                      \n"
+               "        li     %2, 0                                   \n"
+               "       .previous                                       \n"
+               "       .set    reorder                                 \n"
                : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
                : "m" (rw->lock)
                : "memory");
@@ -275,4 +368,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
        return ret;
 }
 
+
+#define _raw_spin_relax(lock)  cpu_relax()
+#define _raw_read_relax(lock)  cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
 #endif /* _ASM_SPINLOCK_H */