1 /* 2 * linux/include/asm-arm/atomic.h 3 * 4 * Copyright (c) 1996 Russell King. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Changelog: 11 * 27-06-1996 RMK Created 12 * 13-04-1997 RMK Made functions atomic! 13 * 07-12-1997 RMK Upgraded for v2.1. 14 * 26-08-1998 PJB Added #ifdef __KERNEL__ 15 */ 16 #ifndef __ASM_ARM_ATOMIC_H 17 #define __ASM_ARM_ATOMIC_H 18 19 #ifdef CONFIG_SMP 20 #error SMP not supported 21 #endif 22 23 typedef struct { volatile int counter; } atomic_t; 24 25 #define ATOMIC_INIT(i) { (i) } 26 27 #ifdef __KERNEL__ 28 #include <asm/proc/system.h> 29 30 #define atomic_read(v) ((v)->counter) 31 #define atomic_set(v,i) (((v)->counter) = (i)) 32 33 static inline void atomic_add(int i, volatile atomic_t *v) 34 { 35 unsigned long flags; 36 37 local_irq_save(flags); 38 v->counter += i; 39 local_irq_restore(flags); 40 } 41 42 static inline void atomic_sub(int i, volatile atomic_t *v) 43 { 44 unsigned long flags; 45 46 local_irq_save(flags); 47 v->counter -= i; 48 local_irq_restore(flags); 49 } 50 51 static inline void atomic_inc(volatile atomic_t *v) 52 { 53 unsigned long flags; 54 55 local_irq_save(flags); 56 v->counter += 1; 57 local_irq_restore(flags); 58 } 59 60 static inline void atomic_dec(volatile atomic_t *v) 61 { 62 unsigned long flags; 63 64 local_irq_save(flags); 65 v->counter -= 1; 66 local_irq_restore(flags); 67 } 68 69 static inline int atomic_dec_and_test(volatile atomic_t *v) 70 { 71 unsigned long flags; 72 int val; 73 74 local_irq_save(flags); 75 val = v->counter; 76 v->counter = val -= 1; 77 local_irq_restore(flags); 78 79 return val == 0; 80 } 81 82 static inline int atomic_add_negative(int i, volatile atomic_t *v) 83 { 84 unsigned long flags; 85 int val; 86 87 local_irq_save(flags); 88 val = v->counter; 89 v->counter = val += i; 90 local_irq_restore(flags); 91 92 return val < 0; 93 } 94 95 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) 96 { 97 unsigned long flags; 98 99 local_irq_save(flags); 100 *addr &= ~mask; 101 local_irq_restore(flags); 102 } 103 104 /* Atomic operations are already serializing on ARM */ 105 #define smp_mb__before_atomic_dec() barrier() 106 #define smp_mb__after_atomic_dec() barrier() 107 #define smp_mb__before_atomic_inc() barrier() 108 #define smp_mb__after_atomic_inc() barrier() 109 110 #endif 111 #endif 112