Blame view

lib/atomic64.c 4.25 KB
09d4e0edd   Paul Mackerras   lib: Provide gene...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * Generic implementation of 64-bit atomics using spinlocks,
   * useful on processors that don't have 64-bit atomic instructions.
   *
   * Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  #include <linux/types.h>
  #include <linux/cache.h>
  #include <linux/spinlock.h>
  #include <linux/init.h>
3fc7b4b22   Roland Dreier   lib: export gener...
16
  #include <linux/module.h>
60063497a   Arun Sharma   atomic: use <linu...
17
  #include <linux/atomic.h>
09d4e0edd   Paul Mackerras   lib: Provide gene...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
  /*
   * We use a hashed array of spinlocks to provide exclusive access
   * to each atomic64_t variable.  Since this is expected to used on
   * systems with small numbers of CPUs (<= 4 or so), we use a
   * relatively small array of 16 spinlocks to avoid wasting too much
   * memory on the spinlock array.
   */
  #define NR_LOCKS	16
  
  /*
   * Ensure each lock is in a separate cacheline.
   */
  static union {
f59ca0587   Shan Hai   locking, lib/atom...
32
  	raw_spinlock_t lock;
09d4e0edd   Paul Mackerras   lib: Provide gene...
33
34
  	char pad[L1_CACHE_BYTES];
  } atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
35
  static inline raw_spinlock_t *lock_addr(const atomic64_t *v)
09d4e0edd   Paul Mackerras   lib: Provide gene...
36
37
38
39
40
41
42
43
44
45
46
  {
  	unsigned long addr = (unsigned long) v;
  
  	addr >>= L1_CACHE_SHIFT;
  	addr ^= (addr >> 8) ^ (addr >> 16);
  	return &atomic64_lock[addr & (NR_LOCKS - 1)].lock;
  }
  
  long long atomic64_read(const atomic64_t *v)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
47
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
48
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
49
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
50
  	val = v->counter;
f59ca0587   Shan Hai   locking, lib/atom...
51
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
52
53
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
54
  EXPORT_SYMBOL(atomic64_read);
09d4e0edd   Paul Mackerras   lib: Provide gene...
55
56
57
58
  
  void atomic64_set(atomic64_t *v, long long i)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
59
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
60

f59ca0587   Shan Hai   locking, lib/atom...
61
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
62
  	v->counter = i;
f59ca0587   Shan Hai   locking, lib/atom...
63
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
64
  }
3fc7b4b22   Roland Dreier   lib: export gener...
65
  EXPORT_SYMBOL(atomic64_set);
09d4e0edd   Paul Mackerras   lib: Provide gene...
66
67
68
69
  
  void atomic64_add(long long a, atomic64_t *v)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
70
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
71

f59ca0587   Shan Hai   locking, lib/atom...
72
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
73
  	v->counter += a;
f59ca0587   Shan Hai   locking, lib/atom...
74
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
75
  }
3fc7b4b22   Roland Dreier   lib: export gener...
76
  EXPORT_SYMBOL(atomic64_add);
09d4e0edd   Paul Mackerras   lib: Provide gene...
77
78
79
80
  
  long long atomic64_add_return(long long a, atomic64_t *v)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
81
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
82
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
83
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
84
  	val = v->counter += a;
f59ca0587   Shan Hai   locking, lib/atom...
85
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
86
87
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
88
  EXPORT_SYMBOL(atomic64_add_return);
09d4e0edd   Paul Mackerras   lib: Provide gene...
89
90
91
92
  
  void atomic64_sub(long long a, atomic64_t *v)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
93
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
94

f59ca0587   Shan Hai   locking, lib/atom...
95
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
96
  	v->counter -= a;
f59ca0587   Shan Hai   locking, lib/atom...
97
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
98
  }
3fc7b4b22   Roland Dreier   lib: export gener...
99
  EXPORT_SYMBOL(atomic64_sub);
09d4e0edd   Paul Mackerras   lib: Provide gene...
100
101
102
103
  
  long long atomic64_sub_return(long long a, atomic64_t *v)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
104
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
105
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
106
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
107
  	val = v->counter -= a;
f59ca0587   Shan Hai   locking, lib/atom...
108
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
109
110
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
111
  EXPORT_SYMBOL(atomic64_sub_return);
09d4e0edd   Paul Mackerras   lib: Provide gene...
112
113
114
115
  
  long long atomic64_dec_if_positive(atomic64_t *v)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
116
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
117
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
118
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
119
120
121
  	val = v->counter - 1;
  	if (val >= 0)
  		v->counter = val;
f59ca0587   Shan Hai   locking, lib/atom...
122
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
123
124
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
125
  EXPORT_SYMBOL(atomic64_dec_if_positive);
09d4e0edd   Paul Mackerras   lib: Provide gene...
126
127
128
129
  
  long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
130
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
131
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
132
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
133
134
135
  	val = v->counter;
  	if (val == o)
  		v->counter = n;
f59ca0587   Shan Hai   locking, lib/atom...
136
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
137
138
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
139
  EXPORT_SYMBOL(atomic64_cmpxchg);
09d4e0edd   Paul Mackerras   lib: Provide gene...
140
141
142
143
  
  long long atomic64_xchg(atomic64_t *v, long long new)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
144
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
145
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
146
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
147
148
  	val = v->counter;
  	v->counter = new;
f59ca0587   Shan Hai   locking, lib/atom...
149
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
150
151
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
152
  EXPORT_SYMBOL(atomic64_xchg);
09d4e0edd   Paul Mackerras   lib: Provide gene...
153
154
155
156
  
  int atomic64_add_unless(atomic64_t *v, long long a, long long u)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
157
  	raw_spinlock_t *lock = lock_addr(v);
97577896f   Luca Barbieri   lib: Fix atomic64...
158
  	int ret = 0;
09d4e0edd   Paul Mackerras   lib: Provide gene...
159

f59ca0587   Shan Hai   locking, lib/atom...
160
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
161
162
  	if (v->counter != u) {
  		v->counter += a;
97577896f   Luca Barbieri   lib: Fix atomic64...
163
  		ret = 1;
09d4e0edd   Paul Mackerras   lib: Provide gene...
164
  	}
f59ca0587   Shan Hai   locking, lib/atom...
165
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
166
167
  	return ret;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
168
  EXPORT_SYMBOL(atomic64_add_unless);
09d4e0edd   Paul Mackerras   lib: Provide gene...
169
170
171
172
173
174
  
  static int init_atomic64_lock(void)
  {
  	int i;
  
  	for (i = 0; i < NR_LOCKS; ++i)
f59ca0587   Shan Hai   locking, lib/atom...
175
  		raw_spin_lock_init(&atomic64_lock[i].lock);
09d4e0edd   Paul Mackerras   lib: Provide gene...
176
177
178
179
  	return 0;
  }
  
  pure_initcall(init_atomic64_lock);