1 /* 2 * Generic C implementation of atomic counter operations. Usable on 3 * UP systems only. Do not include in machine independent code. 4 * 5 * Originally implemented for MN10300. 6 * 7 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 8 * Written by David Howells (dhowells@redhat.com) 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public Licence 12 * as published by the Free Software Foundation; either version 13 * 2 of the Licence, or (at your option) any later version. 14 */ 15 #ifndef __ASM_GENERIC_ATOMIC_H 16 #define __ASM_GENERIC_ATOMIC_H 17 18 #include <asm/cmpxchg.h> 19 #include <asm/barrier.h> 20 21 #ifdef CONFIG_SMP 22 /* Force people to define core atomics */ 23 # if !defined(atomic_add_return) || !defined(atomic_sub_return) || \ 24 !defined(atomic_clear_mask) || !defined(atomic_set_mask) 25 # error "SMP requires a little arch-specific magic" 26 # endif 27 #endif 28 29 /* 30 * Atomic operations that C can't guarantee us. Useful for 31 * resource counting etc.. 32 */ 33 34 #define ATOMIC_INIT(i) { (i) } 35 36 #ifdef __KERNEL__ 37 38 /** 39 * atomic_read - read atomic variable 40 * @v: pointer of type atomic_t 41 * 42 * Atomically reads the value of @v. 43 */ 44 #ifndef atomic_read 45 #define atomic_read(v) (*(volatile int *)&(v)->counter) 46 #endif 47 48 /** 49 * atomic_set - set atomic variable 50 * @v: pointer of type atomic_t 51 * @i: required value 52 * 53 * Atomically sets the value of @v to @i. 54 */ 55 #define atomic_set(v, i) (((v)->counter) = (i)) 56 57 #include <linux/irqflags.h> 58 59 /** 60 * atomic_add_return - add integer to atomic variable 61 * @i: integer value to add 62 * @v: pointer of type atomic_t 63 * 64 * Atomically adds @i to @v and returns the result 65 */ 66 #ifndef atomic_add_return 67 static inline int atomic_add_return(int i, atomic_t *v) 68 { 69 unsigned long flags; 70 int temp; 71 72 raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ 73 temp = v->counter; 74 temp += i; 75 v->counter = temp; 76 raw_local_irq_restore(flags); 77 78 return temp; 79 } 80 #endif 81 82 /** 83 * atomic_sub_return - subtract integer from atomic variable 84 * @i: integer value to subtract 85 * @v: pointer of type atomic_t 86 * 87 * Atomically subtracts @i from @v and returns the result 88 */ 89 #ifndef atomic_sub_return 90 static inline int atomic_sub_return(int i, atomic_t *v) 91 { 92 unsigned long flags; 93 int temp; 94 95 raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ 96 temp = v->counter; 97 temp -= i; 98 v->counter = temp; 99 raw_local_irq_restore(flags); 100 101 return temp; 102 } 103 #endif 104 105 static inline int atomic_add_negative(int i, atomic_t *v) 106 { 107 return atomic_add_return(i, v) < 0; 108 } 109 110 static inline void atomic_add(int i, atomic_t *v) 111 { 112 atomic_add_return(i, v); 113 } 114 115 static inline void atomic_sub(int i, atomic_t *v) 116 { 117 atomic_sub_return(i, v); 118 } 119 120 static inline void atomic_inc(atomic_t *v) 121 { 122 atomic_add_return(1, v); 123 } 124 125 static inline void atomic_dec(atomic_t *v) 126 { 127 atomic_sub_return(1, v); 128 } 129 130 #define atomic_dec_return(v) atomic_sub_return(1, (v)) 131 #define atomic_inc_return(v) atomic_add_return(1, (v)) 132 133 #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) 134 #define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) 135 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) 136 137 #define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) 138 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 139 140 static inline int __atomic_add_unless(atomic_t *v, int a, int u) 141 { 142 int c, old; 143 c = atomic_read(v); 144 while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) 145 c = old; 146 return c; 147 } 148 149 /** 150 * atomic_clear_mask - Atomically clear bits in atomic variable 151 * @mask: Mask of the bits to be cleared 152 * @v: pointer of type atomic_t 153 * 154 * Atomically clears the bits set in @mask from @v 155 */ 156 #ifndef atomic_clear_mask 157 static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) 158 { 159 unsigned long flags; 160 161 mask = ~mask; 162 raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ 163 v->counter &= mask; 164 raw_local_irq_restore(flags); 165 } 166 #endif 167 168 /** 169 * atomic_set_mask - Atomically set bits in atomic variable 170 * @mask: Mask of the bits to be set 171 * @v: pointer of type atomic_t 172 * 173 * Atomically sets the bits set in @mask in @v 174 */ 175 #ifndef atomic_set_mask 176 static inline void atomic_set_mask(unsigned int mask, atomic_t *v) 177 { 178 unsigned long flags; 179 180 raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ 181 v->counter |= mask; 182 raw_local_irq_restore(flags); 183 } 184 #endif 185 186 #endif /* __KERNEL__ */ 187 #endif /* __ASM_GENERIC_ATOMIC_H */ 188