1#ifndef __M32R_LOCAL_H 2#define __M32R_LOCAL_H 3 4/* 5 * linux/include/asm-m32r/local.h 6 * 7 * M32R version: 8 * Copyright (C) 2001, 2002 Hitoshi Yamamoto 9 * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> 10 * Copyright (C) 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> 11 */ 12 13#include <linux/percpu.h> 14#include <asm/assembler.h> 15#include <asm/local.h> 16 17/* 18 * Atomic operations that C can't guarantee us. Useful for 19 * resource counting etc.. 20 */ 21 22/* 23 * Make sure gcc doesn't try to be clever and move things around 24 * on us. We need to use _exactly_ the address the user gave us, 25 * not some alias that contains the same information. 26 */ 27typedef struct { volatile int counter; } local_t; 28 29#define LOCAL_INIT(i) { (i) } 30 31/** 32 * local_read - read local variable 33 * @l: pointer of type local_t 34 * 35 * Atomically reads the value of @l. 36 */ 37#define local_read(l) ((l)->counter) 38 39/** 40 * local_set - set local variable 41 * @l: pointer of type local_t 42 * @i: required value 43 * 44 * Atomically sets the value of @l to @i. 45 */ 46#define local_set(l, i) (((l)->counter) = (i)) 47 48/** 49 * local_add_return - add long to local variable and return it 50 * @i: long value to add 51 * @l: pointer of type local_t 52 * 53 * Atomically adds @i to @l and return (@i + @l). 54 */ 55static inline long local_add_return(long i, local_t *l) 56{ 57 unsigned long flags; 58 long result; 59 60 local_irq_save(flags); 61 __asm__ __volatile__ ( 62 "# local_add_return \n\t" 63 DCACHE_CLEAR("%0", "r4", "%1") 64 "ld %0, @%1; \n\t" 65 "add %0, %2; \n\t" 66 "st %0, @%1; \n\t" 67 : "=&r" (result) 68 : "r" (&l->counter), "r" (i) 69 : "memory" 70#ifdef CONFIG_CHIP_M32700_TS1 71 , "r4" 72#endif /* CONFIG_CHIP_M32700_TS1 */ 73 ); 74 local_irq_restore(flags); 75 76 return result; 77} 78 79/** 80 * local_sub_return - subtract long from local variable and return it 81 * @i: long value to subtract 82 * @l: pointer of type local_t 83 * 84 * Atomically subtracts @i from @l and return (@l - @i). 85 */ 86static inline long local_sub_return(long i, local_t *l) 87{ 88 unsigned long flags; 89 long result; 90 91 local_irq_save(flags); 92 __asm__ __volatile__ ( 93 "# local_sub_return \n\t" 94 DCACHE_CLEAR("%0", "r4", "%1") 95 "ld %0, @%1; \n\t" 96 "sub %0, %2; \n\t" 97 "st %0, @%1; \n\t" 98 : "=&r" (result) 99 : "r" (&l->counter), "r" (i) 100 : "memory" 101#ifdef CONFIG_CHIP_M32700_TS1 102 , "r4" 103#endif /* CONFIG_CHIP_M32700_TS1 */ 104 ); 105 local_irq_restore(flags); 106 107 return result; 108} 109 110/** 111 * local_add - add long to local variable 112 * @i: long value to add 113 * @l: pointer of type local_t 114 * 115 * Atomically adds @i to @l. 116 */ 117#define local_add(i, l) ((void) local_add_return((i), (l))) 118 119/** 120 * local_sub - subtract the local variable 121 * @i: long value to subtract 122 * @l: pointer of type local_t 123 * 124 * Atomically subtracts @i from @l. 125 */ 126#define local_sub(i, l) ((void) local_sub_return((i), (l))) 127 128/** 129 * local_sub_and_test - subtract value from variable and test result 130 * @i: integer value to subtract 131 * @l: pointer of type local_t 132 * 133 * Atomically subtracts @i from @l and returns 134 * true if the result is zero, or false for all 135 * other cases. 136 */ 137#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0) 138 139/** 140 * local_inc_return - increment local variable and return it 141 * @l: pointer of type local_t 142 * 143 * Atomically increments @l by 1 and returns the result. 144 */ 145static inline long local_inc_return(local_t *l) 146{ 147 unsigned long flags; 148 long result; 149 150 local_irq_save(flags); 151 __asm__ __volatile__ ( 152 "# local_inc_return \n\t" 153 DCACHE_CLEAR("%0", "r4", "%1") 154 "ld %0, @%1; \n\t" 155 "addi %0, #1; \n\t" 156 "st %0, @%1; \n\t" 157 : "=&r" (result) 158 : "r" (&l->counter) 159 : "memory" 160#ifdef CONFIG_CHIP_M32700_TS1 161 , "r4" 162#endif /* CONFIG_CHIP_M32700_TS1 */ 163 ); 164 local_irq_restore(flags); 165 166 return result; 167} 168 169/** 170 * local_dec_return - decrement local variable and return it 171 * @l: pointer of type local_t 172 * 173 * Atomically decrements @l by 1 and returns the result. 174 */ 175static inline long local_dec_return(local_t *l) 176{ 177 unsigned long flags; 178 long result; 179 180 local_irq_save(flags); 181 __asm__ __volatile__ ( 182 "# local_dec_return \n\t" 183 DCACHE_CLEAR("%0", "r4", "%1") 184 "ld %0, @%1; \n\t" 185 "addi %0, #-1; \n\t" 186 "st %0, @%1; \n\t" 187 : "=&r" (result) 188 : "r" (&l->counter) 189 : "memory" 190#ifdef CONFIG_CHIP_M32700_TS1 191 , "r4" 192#endif /* CONFIG_CHIP_M32700_TS1 */ 193 ); 194 local_irq_restore(flags); 195 196 return result; 197} 198 199/** 200 * local_inc - increment local variable 201 * @l: pointer of type local_t 202 * 203 * Atomically increments @l by 1. 204 */ 205#define local_inc(l) ((void)local_inc_return(l)) 206 207/** 208 * local_dec - decrement local variable 209 * @l: pointer of type local_t 210 * 211 * Atomically decrements @l by 1. 212 */ 213#define local_dec(l) ((void)local_dec_return(l)) 214 215/** 216 * local_inc_and_test - increment and test 217 * @l: pointer of type local_t 218 * 219 * Atomically increments @l by 1 220 * and returns true if the result is zero, or false for all 221 * other cases. 222 */ 223#define local_inc_and_test(l) (local_inc_return(l) == 0) 224 225/** 226 * local_dec_and_test - decrement and test 227 * @l: pointer of type local_t 228 * 229 * Atomically decrements @l by 1 and 230 * returns true if the result is 0, or false for all 231 * other cases. 232 */ 233#define local_dec_and_test(l) (local_dec_return(l) == 0) 234 235/** 236 * local_add_negative - add and test if negative 237 * @l: pointer of type local_t 238 * @i: integer value to add 239 * 240 * Atomically adds @i to @l and returns true 241 * if the result is negative, or false when 242 * result is greater than or equal to zero. 243 */ 244#define local_add_negative(i, l) (local_add_return((i), (l)) < 0) 245 246#define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n))) 247#define local_xchg(v, new) (xchg_local(&((l)->counter), new)) 248 249/** 250 * local_add_unless - add unless the number is a given value 251 * @l: pointer of type local_t 252 * @a: the amount to add to l... 253 * @u: ...unless l is equal to u. 254 * 255 * Atomically adds @a to @l, so long as it was not @u. 256 * Returns non-zero if @l was not @u, and zero otherwise. 257 */ 258static inline int local_add_unless(local_t *l, long a, long u) 259{ 260 long c, old; 261 c = local_read(l); 262 for (;;) { 263 if (unlikely(c == (u))) 264 break; 265 old = local_cmpxchg((l), c, c + (a)); 266 if (likely(old == c)) 267 break; 268 c = old; 269 } 270 return c != (u); 271} 272 273#define local_inc_not_zero(l) local_add_unless((l), 1, 0) 274 275static inline void local_clear_mask(unsigned long mask, local_t *addr) 276{ 277 unsigned long flags; 278 unsigned long tmp; 279 280 local_irq_save(flags); 281 __asm__ __volatile__ ( 282 "# local_clear_mask \n\t" 283 DCACHE_CLEAR("%0", "r5", "%1") 284 "ld %0, @%1; \n\t" 285 "and %0, %2; \n\t" 286 "st %0, @%1; \n\t" 287 : "=&r" (tmp) 288 : "r" (addr), "r" (~mask) 289 : "memory" 290#ifdef CONFIG_CHIP_M32700_TS1 291 , "r5" 292#endif /* CONFIG_CHIP_M32700_TS1 */ 293 ); 294 local_irq_restore(flags); 295} 296 297static inline void local_set_mask(unsigned long mask, local_t *addr) 298{ 299 unsigned long flags; 300 unsigned long tmp; 301 302 local_irq_save(flags); 303 __asm__ __volatile__ ( 304 "# local_set_mask \n\t" 305 DCACHE_CLEAR("%0", "r5", "%1") 306 "ld %0, @%1; \n\t" 307 "or %0, %2; \n\t" 308 "st %0, @%1; \n\t" 309 : "=&r" (tmp) 310 : "r" (addr), "r" (mask) 311 : "memory" 312#ifdef CONFIG_CHIP_M32700_TS1 313 , "r5" 314#endif /* CONFIG_CHIP_M32700_TS1 */ 315 ); 316 local_irq_restore(flags); 317} 318 319/* Atomic operations are already serializing on m32r */ 320#define smp_mb__before_local_dec() barrier() 321#define smp_mb__after_local_dec() barrier() 322#define smp_mb__before_local_inc() barrier() 323#define smp_mb__after_local_inc() barrier() 324 325/* Use these for per-cpu local_t variables: on some archs they are 326 * much more efficient than these naive implementations. Note they take 327 * a variable, not an address. 328 */ 329 330#define __local_inc(l) ((l)->a.counter++) 331#define __local_dec(l) ((l)->a.counter++) 332#define __local_add(i, l) ((l)->a.counter += (i)) 333#define __local_sub(i, l) ((l)->a.counter -= (i)) 334 335/* Use these for per-cpu local_t variables: on some archs they are 336 * much more efficient than these naive implementations. Note they take 337 * a variable, not an address. 338 */ 339 340#endif /* __M32R_LOCAL_H */ 341