~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to lib/atomic64.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Generic implementation of 64-bit atomics using spinlocks,
 
3
 * useful on processors that don't have 64-bit atomic instructions.
 
4
 *
 
5
 * Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License
 
9
 * as published by the Free Software Foundation; either version
 
10
 * 2 of the License, or (at your option) any later version.
 
11
 */
 
12
#include <linux/types.h>
 
13
#include <linux/cache.h>
 
14
#include <linux/spinlock.h>
 
15
#include <linux/init.h>
 
16
#include <linux/module.h>
 
17
#include <asm/atomic.h>
 
18
 
 
19
/*
 
20
 * We use a hashed array of spinlocks to provide exclusive access
 
21
 * to each atomic64_t variable.  Since this is expected to used on
 
22
 * systems with small numbers of CPUs (<= 4 or so), we use a
 
23
 * relatively small array of 16 spinlocks to avoid wasting too much
 
24
 * memory on the spinlock array.
 
25
 */
 
26
#define NR_LOCKS        16
 
27
 
 
28
/*
 
29
 * Ensure each lock is in a separate cacheline.
 
30
 */
 
31
static union {
 
32
        spinlock_t lock;
 
33
        char pad[L1_CACHE_BYTES];
 
34
} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp;
 
35
 
 
36
static inline spinlock_t *lock_addr(const atomic64_t *v)
 
37
{
 
38
        unsigned long addr = (unsigned long) v;
 
39
 
 
40
        addr >>= L1_CACHE_SHIFT;
 
41
        addr ^= (addr >> 8) ^ (addr >> 16);
 
42
        return &atomic64_lock[addr & (NR_LOCKS - 1)].lock;
 
43
}
 
44
 
 
45
long long atomic64_read(const atomic64_t *v)
 
46
{
 
47
        unsigned long flags;
 
48
        spinlock_t *lock = lock_addr(v);
 
49
        long long val;
 
50
 
 
51
        spin_lock_irqsave(lock, flags);
 
52
        val = v->counter;
 
53
        spin_unlock_irqrestore(lock, flags);
 
54
        return val;
 
55
}
 
56
EXPORT_SYMBOL(atomic64_read);
 
57
 
 
58
void atomic64_set(atomic64_t *v, long long i)
 
59
{
 
60
        unsigned long flags;
 
61
        spinlock_t *lock = lock_addr(v);
 
62
 
 
63
        spin_lock_irqsave(lock, flags);
 
64
        v->counter = i;
 
65
        spin_unlock_irqrestore(lock, flags);
 
66
}
 
67
EXPORT_SYMBOL(atomic64_set);
 
68
 
 
69
void atomic64_add(long long a, atomic64_t *v)
 
70
{
 
71
        unsigned long flags;
 
72
        spinlock_t *lock = lock_addr(v);
 
73
 
 
74
        spin_lock_irqsave(lock, flags);
 
75
        v->counter += a;
 
76
        spin_unlock_irqrestore(lock, flags);
 
77
}
 
78
EXPORT_SYMBOL(atomic64_add);
 
79
 
 
80
long long atomic64_add_return(long long a, atomic64_t *v)
 
81
{
 
82
        unsigned long flags;
 
83
        spinlock_t *lock = lock_addr(v);
 
84
        long long val;
 
85
 
 
86
        spin_lock_irqsave(lock, flags);
 
87
        val = v->counter += a;
 
88
        spin_unlock_irqrestore(lock, flags);
 
89
        return val;
 
90
}
 
91
EXPORT_SYMBOL(atomic64_add_return);
 
92
 
 
93
void atomic64_sub(long long a, atomic64_t *v)
 
94
{
 
95
        unsigned long flags;
 
96
        spinlock_t *lock = lock_addr(v);
 
97
 
 
98
        spin_lock_irqsave(lock, flags);
 
99
        v->counter -= a;
 
100
        spin_unlock_irqrestore(lock, flags);
 
101
}
 
102
EXPORT_SYMBOL(atomic64_sub);
 
103
 
 
104
long long atomic64_sub_return(long long a, atomic64_t *v)
 
105
{
 
106
        unsigned long flags;
 
107
        spinlock_t *lock = lock_addr(v);
 
108
        long long val;
 
109
 
 
110
        spin_lock_irqsave(lock, flags);
 
111
        val = v->counter -= a;
 
112
        spin_unlock_irqrestore(lock, flags);
 
113
        return val;
 
114
}
 
115
EXPORT_SYMBOL(atomic64_sub_return);
 
116
 
 
117
long long atomic64_dec_if_positive(atomic64_t *v)
 
118
{
 
119
        unsigned long flags;
 
120
        spinlock_t *lock = lock_addr(v);
 
121
        long long val;
 
122
 
 
123
        spin_lock_irqsave(lock, flags);
 
124
        val = v->counter - 1;
 
125
        if (val >= 0)
 
126
                v->counter = val;
 
127
        spin_unlock_irqrestore(lock, flags);
 
128
        return val;
 
129
}
 
130
EXPORT_SYMBOL(atomic64_dec_if_positive);
 
131
 
 
132
long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
 
133
{
 
134
        unsigned long flags;
 
135
        spinlock_t *lock = lock_addr(v);
 
136
        long long val;
 
137
 
 
138
        spin_lock_irqsave(lock, flags);
 
139
        val = v->counter;
 
140
        if (val == o)
 
141
                v->counter = n;
 
142
        spin_unlock_irqrestore(lock, flags);
 
143
        return val;
 
144
}
 
145
EXPORT_SYMBOL(atomic64_cmpxchg);
 
146
 
 
147
long long atomic64_xchg(atomic64_t *v, long long new)
 
148
{
 
149
        unsigned long flags;
 
150
        spinlock_t *lock = lock_addr(v);
 
151
        long long val;
 
152
 
 
153
        spin_lock_irqsave(lock, flags);
 
154
        val = v->counter;
 
155
        v->counter = new;
 
156
        spin_unlock_irqrestore(lock, flags);
 
157
        return val;
 
158
}
 
159
EXPORT_SYMBOL(atomic64_xchg);
 
160
 
 
161
int atomic64_add_unless(atomic64_t *v, long long a, long long u)
 
162
{
 
163
        unsigned long flags;
 
164
        spinlock_t *lock = lock_addr(v);
 
165
        int ret = 1;
 
166
 
 
167
        spin_lock_irqsave(lock, flags);
 
168
        if (v->counter != u) {
 
169
                v->counter += a;
 
170
                ret = 0;
 
171
        }
 
172
        spin_unlock_irqrestore(lock, flags);
 
173
        return ret;
 
174
}
 
175
EXPORT_SYMBOL(atomic64_add_unless);
 
176
 
 
177
static int init_atomic64_lock(void)
 
178
{
 
179
        int i;
 
180
 
 
181
        for (i = 0; i < NR_LOCKS; ++i)
 
182
                spin_lock_init(&atomic64_lock[i].lock);
 
183
        return 0;
 
184
}
 
185
 
 
186
pure_initcall(init_atomic64_lock);