]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - include/asm-mips/system.h
local_t: mips extension
[linux-2.6-omap-h63xx.git] / include / asm-mips / system.h
index 290887077e4497cda1812a13da6b24d5fd07d243..d53dd72455615dc7ae443e74cb7d5216f9a4fb27 100644 (file)
@@ -262,6 +262,58 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
        return retval;
 }
 
+static inline unsigned long __cmpxchg_u32_local(volatile int * m,
+       unsigned long old, unsigned long new)
+{
+       __u32 retval;
+
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               __asm__ __volatile__(
+               "       .set    push                                    \n"
+               "       .set    noat                                    \n"
+               "       .set    mips3                                   \n"
+               "1:     ll      %0, %2                  # __cmpxchg_u32 \n"
+               "       bne     %0, %z3, 2f                             \n"
+               "       .set    mips0                                   \n"
+               "       move    $1, %z4                                 \n"
+               "       .set    mips3                                   \n"
+               "       sc      $1, %1                                  \n"
+               "       beqzl   $1, 1b                                  \n"
+               "2:                                                     \n"
+               "       .set    pop                                     \n"
+               : "=&r" (retval), "=R" (*m)
+               : "R" (*m), "Jr" (old), "Jr" (new)
+               : "memory");
+       } else if (cpu_has_llsc) {
+               __asm__ __volatile__(
+               "       .set    push                                    \n"
+               "       .set    noat                                    \n"
+               "       .set    mips3                                   \n"
+               "1:     ll      %0, %2                  # __cmpxchg_u32 \n"
+               "       bne     %0, %z3, 2f                             \n"
+               "       .set    mips0                                   \n"
+               "       move    $1, %z4                                 \n"
+               "       .set    mips3                                   \n"
+               "       sc      $1, %1                                  \n"
+               "       beqz    $1, 1b                                  \n"
+               "2:                                                     \n"
+               "       .set    pop                                     \n"
+               : "=&r" (retval), "=R" (*m)
+               : "R" (*m), "Jr" (old), "Jr" (new)
+               : "memory");
+       } else {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               retval = *m;
+               if (retval == old)
+                       *m = new;
+               local_irq_restore(flags);       /* implies memory barrier  */
+       }
+
+       return retval;
+}
+
 #ifdef CONFIG_64BIT
 static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
        unsigned long new)
@@ -315,10 +367,62 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
 
        return retval;
 }
+
+static inline unsigned long __cmpxchg_u64_local(volatile int * m,
+       unsigned long old, unsigned long new)
+{
+       __u64 retval;
+
+       if (cpu_has_llsc && R10000_LLSC_WAR) {
+               __asm__ __volatile__(
+               "       .set    push                                    \n"
+               "       .set    noat                                    \n"
+               "       .set    mips3                                   \n"
+               "1:     lld     %0, %2                  # __cmpxchg_u64 \n"
+               "       bne     %0, %z3, 2f                             \n"
+               "       move    $1, %z4                                 \n"
+               "       scd     $1, %1                                  \n"
+               "       beqzl   $1, 1b                                  \n"
+               "2:                                                     \n"
+               "       .set    pop                                     \n"
+               : "=&r" (retval), "=R" (*m)
+               : "R" (*m), "Jr" (old), "Jr" (new)
+               : "memory");
+       } else if (cpu_has_llsc) {
+               __asm__ __volatile__(
+               "       .set    push                                    \n"
+               "       .set    noat                                    \n"
+               "       .set    mips3                                   \n"
+               "1:     lld     %0, %2                  # __cmpxchg_u64 \n"
+               "       bne     %0, %z3, 2f                             \n"
+               "       move    $1, %z4                                 \n"
+               "       scd     $1, %1                                  \n"
+               "       beqz    $1, 1b                                  \n"
+               "2:                                                     \n"
+               "       .set    pop                                     \n"
+               : "=&r" (retval), "=R" (*m)
+               : "R" (*m), "Jr" (old), "Jr" (new)
+               : "memory");
+       } else {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               retval = *m;
+               if (retval == old)
+                       *m = new;
+               local_irq_restore(flags);       /* implies memory barrier  */
+       }
+
+       return retval;
+}
+
 #else
 extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
        volatile int * m, unsigned long old, unsigned long new);
 #define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
+extern unsigned long __cmpxchg_u64_local_unsupported_on_32bit_kernels(
+       volatile int * m, unsigned long old, unsigned long new);
+#define __cmpxchg_u64_local __cmpxchg_u64_local_unsupported_on_32bit_kernels
 #endif
 
 /* This function doesn't exist, so you'll get a linker error
@@ -338,7 +442,26 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
        return old;
 }
 
-#define cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+static inline unsigned long __cmpxchg_local(volatile void * ptr,
+       unsigned long old, unsigned long new, int size)
+{
+       switch (size) {
+       case 4:
+               return __cmpxchg_u32_local(ptr, old, new);
+       case 8:
+               return __cmpxchg_u64_local(ptr, old, new);
+       }
+       __cmpxchg_called_with_bad_pointer();
+       return old;
+}
+
+#define cmpxchg(ptr,old,new) \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), \
+               (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+
+#define cmpxchg_local(ptr,old,new) \
+       ((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
+               (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
 
 extern void set_handler (unsigned long offset, void *addr, unsigned long len);
 extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len);