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 #include <linux/config.h>
20 
21 #ifdef CONFIG_SMP
22 #error SMP not supported
23 #endif
24 
25 typedef struct { volatile int counter; } atomic_t;
26 
27 #define ATOMIC_INIT(i)	{ (i) }
28 
29 #ifdef __KERNEL__
30 #include <asm/proc/system.h>
31 
32 #define atomic_read(v)	((v)->counter)
33 #define atomic_set(v,i)	(((v)->counter) = (i))
34 
atomic_add(int i,volatile atomic_t * v)35 static inline void atomic_add(int i, volatile atomic_t *v)
36 {
37 	unsigned long flags;
38 
39 	local_irq_save(flags);
40 	v->counter += i;
41 	local_irq_restore(flags);
42 }
43 
atomic_sub(int i,volatile atomic_t * v)44 static inline void atomic_sub(int i, volatile atomic_t *v)
45 {
46 	unsigned long flags;
47 
48 	local_irq_save(flags);
49 	v->counter -= i;
50 	local_irq_restore(flags);
51 }
52 
atomic_inc(volatile atomic_t * v)53 static inline void atomic_inc(volatile atomic_t *v)
54 {
55 	unsigned long flags;
56 
57 	local_irq_save(flags);
58 	v->counter += 1;
59 	local_irq_restore(flags);
60 }
61 
atomic_dec(volatile atomic_t * v)62 static inline void atomic_dec(volatile atomic_t *v)
63 {
64 	unsigned long flags;
65 
66 	local_irq_save(flags);
67 	v->counter -= 1;
68 	local_irq_restore(flags);
69 }
70 
atomic_dec_and_test(volatile atomic_t * v)71 static inline int atomic_dec_and_test(volatile atomic_t *v)
72 {
73 	unsigned long flags;
74 	int val;
75 
76 	local_irq_save(flags);
77 	val = v->counter;
78 	v->counter = val -= 1;
79 	local_irq_restore(flags);
80 
81 	return val == 0;
82 }
83 
atomic_add_negative(int i,volatile atomic_t * v)84 static inline int atomic_add_negative(int i, volatile atomic_t *v)
85 {
86 	unsigned long flags;
87 	int val;
88 
89 	local_irq_save(flags);
90 	val = v->counter;
91 	v->counter = val += i;
92 	local_irq_restore(flags);
93 
94 	return val < 0;
95 }
96 
atomic_clear_mask(unsigned long mask,unsigned long * addr)97 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
98 {
99 	unsigned long flags;
100 
101 	local_irq_save(flags);
102 	*addr &= ~mask;
103 	local_irq_restore(flags);
104 }
105 
106 /* Atomic operations are already serializing on ARM */
107 #define smp_mb__before_atomic_dec()	barrier()
108 #define smp_mb__after_atomic_dec()	barrier()
109 #define smp_mb__before_atomic_inc()	barrier()
110 #define smp_mb__after_atomic_inc()	barrier()
111 
112 #endif
113 #endif
114