• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/sparc/lib/
1/*
2 * atomic32.c: 32-bit atomic_t implementation
3 *
4 * Copyright (C) 2004 Keith M Wesolowski
5 * Copyright (C) 2007 Kyle McMartin
6 *
7 * Based on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf
8 */
9
10#include <asm/atomic.h>
11#include <linux/spinlock.h>
12#include <linux/module.h>
13
14#ifdef CONFIG_SMP
15#define ATOMIC_HASH_SIZE	4
16#define ATOMIC_HASH(a)	(&__atomic_hash[(((unsigned long)a)>>8) & (ATOMIC_HASH_SIZE-1)])
17
18spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = {
19	[0 ... (ATOMIC_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED
20};
21
22#else /* SMP */
23
24static DEFINE_SPINLOCK(dummy);
25#define ATOMIC_HASH_SIZE	1
26#define ATOMIC_HASH(a)		(&dummy)
27
28#endif /* SMP */
29
30int __atomic_add_return(int i, atomic_t *v)
31{
32	int ret;
33	unsigned long flags;
34	spin_lock_irqsave(ATOMIC_HASH(v), flags);
35
36	ret = (v->counter += i);
37
38	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
39	return ret;
40}
41EXPORT_SYMBOL(__atomic_add_return);
42
43int atomic_cmpxchg(atomic_t *v, int old, int new)
44{
45	int ret;
46	unsigned long flags;
47
48	spin_lock_irqsave(ATOMIC_HASH(v), flags);
49	ret = v->counter;
50	if (likely(ret == old))
51		v->counter = new;
52
53	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
54	return ret;
55}
56EXPORT_SYMBOL(atomic_cmpxchg);
57
58int atomic_add_unless(atomic_t *v, int a, int u)
59{
60	int ret;
61	unsigned long flags;
62
63	spin_lock_irqsave(ATOMIC_HASH(v), flags);
64	ret = v->counter;
65	if (ret != u)
66		v->counter += a;
67	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
68	return ret != u;
69}
70EXPORT_SYMBOL(atomic_add_unless);
71
72/* Atomic operations are already serializing */
73void atomic_set(atomic_t *v, int i)
74{
75	unsigned long flags;
76
77	spin_lock_irqsave(ATOMIC_HASH(v), flags);
78	v->counter = i;
79	spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
80}
81EXPORT_SYMBOL(atomic_set);
82
83unsigned long ___set_bit(unsigned long *addr, unsigned long mask)
84{
85	unsigned long old, flags;
86
87	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
88	old = *addr;
89	*addr = old | mask;
90	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
91
92	return old & mask;
93}
94EXPORT_SYMBOL(___set_bit);
95
96unsigned long ___clear_bit(unsigned long *addr, unsigned long mask)
97{
98	unsigned long old, flags;
99
100	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
101	old = *addr;
102	*addr = old & ~mask;
103	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
104
105	return old & mask;
106}
107EXPORT_SYMBOL(___clear_bit);
108
109unsigned long ___change_bit(unsigned long *addr, unsigned long mask)
110{
111	unsigned long old, flags;
112
113	spin_lock_irqsave(ATOMIC_HASH(addr), flags);
114	old = *addr;
115	*addr = old ^ mask;
116	spin_unlock_irqrestore(ATOMIC_HASH(addr), flags);
117
118	return old & mask;
119}
120EXPORT_SYMBOL(___change_bit);
121
122unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new)
123{
124	unsigned long flags;
125	u32 prev;
126
127	spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
128	if ((prev = *ptr) == old)
129		*ptr = new;
130	spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
131
132	return (unsigned long)prev;
133}
134EXPORT_SYMBOL(__cmpxchg_u32);
135