home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / src / linux-headers-2.6.17-6 / include / asm-arm / atomic.h < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-11  |  4.5 KB  |  212 lines

  1. /*
  2.  *  linux/include/asm-arm/atomic.h
  3.  *
  4.  *  Copyright (C) 1996 Russell King.
  5.  *  Copyright (C) 2002 Deep Blue Solutions Ltd.
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 2 as
  9.  * published by the Free Software Foundation.
  10.  */
  11. #ifndef __ASM_ARM_ATOMIC_H
  12. #define __ASM_ARM_ATOMIC_H
  13.  
  14. #include <linux/compiler.h>
  15.  
  16. typedef struct { volatile int counter; } atomic_t;
  17.  
  18. #define ATOMIC_INIT(i)    { (i) }
  19.  
  20. #ifdef __KERNEL__
  21.  
  22. #define atomic_read(v)    ((v)->counter)
  23.  
  24. #if __LINUX_ARM_ARCH__ >= 6
  25.  
  26. /*
  27.  * ARMv6 UP and SMP safe atomic ops.  We use load exclusive and
  28.  * store exclusive to ensure that these are atomic.  We may loop
  29.  * to ensure that the update happens.  Writing to 'v->counter'
  30.  * without using the following operations WILL break the atomic
  31.  * nature of these ops.
  32.  */
  33. static inline void atomic_set(atomic_t *v, int i)
  34. {
  35.     unsigned long tmp;
  36.  
  37.     __asm__ __volatile__("@ atomic_set\n"
  38. "1:    ldrex    %0, [%1]\n"
  39. "    strex    %0, %2, [%1]\n"
  40. "    teq    %0, #0\n"
  41. "    bne    1b"
  42.     : "=&r" (tmp)
  43.     : "r" (&v->counter), "r" (i)
  44.     : "cc");
  45. }
  46.  
  47. static inline int atomic_add_return(int i, atomic_t *v)
  48. {
  49.     unsigned long tmp;
  50.     int result;
  51.  
  52.     __asm__ __volatile__("@ atomic_add_return\n"
  53. "1:    ldrex    %0, [%2]\n"
  54. "    add    %0, %0, %3\n"
  55. "    strex    %1, %0, [%2]\n"
  56. "    teq    %1, #0\n"
  57. "    bne    1b"
  58.     : "=&r" (result), "=&r" (tmp)
  59.     : "r" (&v->counter), "Ir" (i)
  60.     : "cc");
  61.  
  62.     return result;
  63. }
  64.  
  65. static inline int atomic_sub_return(int i, atomic_t *v)
  66. {
  67.     unsigned long tmp;
  68.     int result;
  69.  
  70.     __asm__ __volatile__("@ atomic_sub_return\n"
  71. "1:    ldrex    %0, [%2]\n"
  72. "    sub    %0, %0, %3\n"
  73. "    strex    %1, %0, [%2]\n"
  74. "    teq    %1, #0\n"
  75. "    bne    1b"
  76.     : "=&r" (result), "=&r" (tmp)
  77.     : "r" (&v->counter), "Ir" (i)
  78.     : "cc");
  79.  
  80.     return result;
  81. }
  82.  
  83. static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
  84. {
  85.     unsigned long oldval, res;
  86.  
  87.     do {
  88.         __asm__ __volatile__("@ atomic_cmpxchg\n"
  89.         "ldrex    %1, [%2]\n"
  90.         "mov    %0, #0\n"
  91.         "teq    %1, %3\n"
  92.         "strexeq %0, %4, [%2]\n"
  93.             : "=&r" (res), "=&r" (oldval)
  94.             : "r" (&ptr->counter), "Ir" (old), "r" (new)
  95.             : "cc");
  96.     } while (res);
  97.  
  98.     return oldval;
  99. }
  100.  
  101. static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
  102. {
  103.     unsigned long tmp, tmp2;
  104.  
  105.     __asm__ __volatile__("@ atomic_clear_mask\n"
  106. "1:    ldrex    %0, %2\n"
  107. "    bic    %0, %0, %3\n"
  108. "    strex    %1, %0, %2\n"
  109. "    teq    %1, #0\n"
  110. "    bne    1b"
  111.     : "=&r" (tmp), "=&r" (tmp2)
  112.     : "r" (addr), "Ir" (mask)
  113.     : "cc");
  114. }
  115.  
  116. #else /* ARM_ARCH_6 */
  117.  
  118. #include <asm/system.h>
  119.  
  120. #ifdef CONFIG_SMP
  121. #error SMP not supported on pre-ARMv6 CPUs
  122. #endif
  123.  
  124. #define atomic_set(v,i)    (((v)->counter) = (i))
  125.  
  126. static inline int atomic_add_return(int i, atomic_t *v)
  127. {
  128.     unsigned long flags;
  129.     int val;
  130.  
  131.     local_irq_save(flags);
  132.     val = v->counter;
  133.     v->counter = val += i;
  134.     local_irq_restore(flags);
  135.  
  136.     return val;
  137. }
  138.  
  139. static inline int atomic_sub_return(int i, atomic_t *v)
  140. {
  141.     unsigned long flags;
  142.     int val;
  143.  
  144.     local_irq_save(flags);
  145.     val = v->counter;
  146.     v->counter = val -= i;
  147.     local_irq_restore(flags);
  148.  
  149.     return val;
  150. }
  151.  
  152. static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
  153. {
  154.     int ret;
  155.     unsigned long flags;
  156.  
  157.     local_irq_save(flags);
  158.     ret = v->counter;
  159.     if (likely(ret == old))
  160.         v->counter = new;
  161.     local_irq_restore(flags);
  162.  
  163.     return ret;
  164. }
  165.  
  166. static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
  167. {
  168.     unsigned long flags;
  169.  
  170.     local_irq_save(flags);
  171.     *addr &= ~mask;
  172.     local_irq_restore(flags);
  173. }
  174.  
  175. #endif /* __LINUX_ARM_ARCH__ */
  176.  
  177. #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
  178.  
  179. static inline int atomic_add_unless(atomic_t *v, int a, int u)
  180. {
  181.     int c, old;
  182.  
  183.     c = atomic_read(v);
  184.     while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
  185.         c = old;
  186.     return c != u;
  187. }
  188. #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
  189.  
  190. #define atomic_add(i, v)    (void) atomic_add_return(i, v)
  191. #define atomic_inc(v)        (void) atomic_add_return(1, v)
  192. #define atomic_sub(i, v)    (void) atomic_sub_return(i, v)
  193. #define atomic_dec(v)        (void) atomic_sub_return(1, v)
  194.  
  195. #define atomic_inc_and_test(v)    (atomic_add_return(1, v) == 0)
  196. #define atomic_dec_and_test(v)    (atomic_sub_return(1, v) == 0)
  197. #define atomic_inc_return(v)    (atomic_add_return(1, v))
  198. #define atomic_dec_return(v)    (atomic_sub_return(1, v))
  199. #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
  200.  
  201. #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0)
  202.  
  203. /* Atomic operations are already serializing on ARM */
  204. #define smp_mb__before_atomic_dec()    barrier()
  205. #define smp_mb__after_atomic_dec()    barrier()
  206. #define smp_mb__before_atomic_inc()    barrier()
  207. #define smp_mb__after_atomic_inc()    barrier()
  208.  
  209. #include <asm-generic/atomic.h>
  210. #endif
  211. #endif
  212.