Blame view

lib/atomic64.c 4.17 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>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
16
  #include <linux/export.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
  	char pad[L1_CACHE_BYTES];
fcc16882a   Stephen Boyd   lib: atomic64: In...
34
35
36
37
38
  } atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp = {
  	[0 ... (NR_LOCKS - 1)] = {
  		.lock =  __RAW_SPIN_LOCK_UNLOCKED(atomic64_lock.lock),
  	},
  };
09d4e0edd   Paul Mackerras   lib: Provide gene...
39

cb475de3d   Yong Zhang   lib: atomic64: Ch...
40
  static inline raw_spinlock_t *lock_addr(const atomic64_t *v)
09d4e0edd   Paul Mackerras   lib: Provide gene...
41
42
43
44
45
46
47
48
49
50
51
  {
  	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...
52
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
53
  	long long val;
f59ca0587   Shan Hai   locking, lib/atom...
54
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
55
  	val = v->counter;
f59ca0587   Shan Hai   locking, lib/atom...
56
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
57
58
  	return val;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
59
  EXPORT_SYMBOL(atomic64_read);
09d4e0edd   Paul Mackerras   lib: Provide gene...
60
61
62
63
  
  void atomic64_set(atomic64_t *v, long long i)
  {
  	unsigned long flags;
cb475de3d   Yong Zhang   lib: atomic64: Ch...
64
  	raw_spinlock_t *lock = lock_addr(v);
09d4e0edd   Paul Mackerras   lib: Provide gene...
65

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

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

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

f59ca0587   Shan Hai   locking, lib/atom...
165
  	raw_spin_lock_irqsave(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
166
167
  	if (v->counter != u) {
  		v->counter += a;
97577896f   Luca Barbieri   lib: Fix atomic64...
168
  		ret = 1;
09d4e0edd   Paul Mackerras   lib: Provide gene...
169
  	}
f59ca0587   Shan Hai   locking, lib/atom...
170
  	raw_spin_unlock_irqrestore(lock, flags);
09d4e0edd   Paul Mackerras   lib: Provide gene...
171
172
  	return ret;
  }
3fc7b4b22   Roland Dreier   lib: export gener...
173
  EXPORT_SYMBOL(atomic64_add_unless);