Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
atomic_32.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010 Tilera Corporation. All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, version 2.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  * NON INFRINGEMENT. See the GNU General Public License for
12  * more details.
13  */
14 
15 #include <linux/cache.h>
16 #include <linux/delay.h>
17 #include <linux/uaccess.h>
18 #include <linux/module.h>
19 #include <linux/mm.h>
20 #include <linux/atomic.h>
21 #include <arch/chip.h>
22 
23 /* See <asm/atomic_32.h> */
24 #if ATOMIC_LOCKS_FOUND_VIA_TABLE()
25 
26 /*
27  * A block of memory containing locks for atomic ops. Each instance of this
28  * struct will be homed on a different CPU.
29  */
30 struct atomic_locks_on_cpu {
31  int lock[ATOMIC_HASH_L2_SIZE];
32 } __attribute__((aligned(ATOMIC_HASH_L2_SIZE * 4)));
33 
34 static DEFINE_PER_CPU(struct atomic_locks_on_cpu, atomic_lock_pool);
35 
36 /* The locks we'll use until __init_atomic_per_cpu is called. */
37 static struct atomic_locks_on_cpu __initdata initial_atomic_locks;
38 
39 /* Hash into this vector to get a pointer to lock for the given atomic. */
40 struct atomic_locks_on_cpu *atomic_lock_ptr[ATOMIC_HASH_L1_SIZE]
41  __write_once = {
42  [0 ... ATOMIC_HASH_L1_SIZE-1] (&initial_atomic_locks)
43 };
44 
45 #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
46 
47 /* This page is remapped on startup to be hash-for-home. */
49 
50 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
51 
52 int *__atomic_hashed_lock(volatile void *v)
53 {
54  /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */
55 #if ATOMIC_LOCKS_FOUND_VIA_TABLE()
56  unsigned long i =
57  (unsigned long) v & ((PAGE_SIZE-1) & -sizeof(long long));
58  unsigned long n = __insn_crc32_32(0, i);
59 
60  /* Grab high bits for L1 index. */
61  unsigned long l1_index = n >> ((sizeof(n) * 8) - ATOMIC_HASH_L1_SHIFT);
62  /* Grab low bits for L2 index. */
63  unsigned long l2_index = n & (ATOMIC_HASH_L2_SIZE - 1);
64 
65  return &atomic_lock_ptr[l1_index]->lock[l2_index];
66 #else
67  /*
68  * Use bits [3, 3 + ATOMIC_HASH_SHIFT) as the lock index.
69  * Using mm works here because atomic_locks is page aligned.
70  */
71  unsigned long ptr = __insn_mm((unsigned long)v >> 1,
72  (unsigned long)atomic_locks,
73  2, (ATOMIC_HASH_SHIFT + 2) - 1);
74  return (int *)ptr;
75 #endif
76 }
77 
78 #ifdef CONFIG_SMP
79 /* Return whether the passed pointer is a valid atomic lock pointer. */
80 static int is_atomic_lock(int *p)
81 {
82 #if ATOMIC_LOCKS_FOUND_VIA_TABLE()
83  int i;
84  for (i = 0; i < ATOMIC_HASH_L1_SIZE; ++i) {
85 
86  if (p >= &atomic_lock_ptr[i]->lock[0] &&
87  p < &atomic_lock_ptr[i]->lock[ATOMIC_HASH_L2_SIZE]) {
88  return 1;
89  }
90  }
91  return 0;
92 #else
93  return p >= &atomic_locks[0] && p < &atomic_locks[ATOMIC_HASH_SIZE];
94 #endif
95 }
96 
97 void __atomic_fault_unlock(int *irqlock_word)
98 {
99  BUG_ON(!is_atomic_lock(irqlock_word));
100  BUG_ON(*irqlock_word != 1);
101  *irqlock_word = 0;
102 }
103 
104 #endif /* CONFIG_SMP */
105 
106 static inline int *__atomic_setup(volatile void *v)
107 {
108  /* Issue a load to the target to bring it into cache. */
109  *(volatile int *)v;
110  return __atomic_hashed_lock(v);
111 }
112 
114 {
115  return __atomic_xchg(&v->counter, __atomic_setup(v), n).val;
116 }
118 
120 {
121  return __atomic_xchg_add(&v->counter, __atomic_setup(v), i).val;
122 }
124 
126 {
127  /*
128  * Note: argument order is switched here since it is easier
129  * to use the first argument consistently as the "old value"
130  * in the assembly, as is done for _atomic_cmpxchg().
131  */
132  return __atomic_xchg_add_unless(&v->counter, __atomic_setup(v), u, a)
133  .val;
134 }
136 
137 int _atomic_cmpxchg(atomic_t *v, int o, int n)
138 {
139  return __atomic_cmpxchg(&v->counter, __atomic_setup(v), o, n).val;
140 }
142 
143 unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask)
144 {
145  return __atomic_or((int *)p, __atomic_setup(p), mask).val;
146 }
148 
149 unsigned long _atomic_andn(volatile unsigned long *p, unsigned long mask)
150 {
151  return __atomic_andn((int *)p, __atomic_setup(p), mask).val;
152 }
154 
155 unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask)
156 {
157  return __atomic_xor((int *)p, __atomic_setup(p), mask).val;
158 }
160 
161 
163 {
164  return __atomic64_xchg(&v->counter, __atomic_setup(v), n);
165 }
167 
169 {
170  return __atomic64_xchg_add(&v->counter, __atomic_setup(v), i);
171 }
173 
175 {
176  /*
177  * Note: argument order is switched here since it is easier
178  * to use the first argument consistently as the "old value"
179  * in the assembly, as is done for _atomic_cmpxchg().
180  */
181  return __atomic64_xchg_add_unless(&v->counter, __atomic_setup(v),
182  u, a);
183 }
185 
187 {
188  return __atomic64_cmpxchg(&v->counter, __atomic_setup(v), o, n);
189 }
191 
192 
193 /*
194  * If any of the atomic or futex routines hit a bad address (not in
195  * the page tables at kernel PL) this routine is called. The futex
196  * routines are never used on kernel space, and the normal atomics and
197  * bitops are never used on user space. So a fault on kernel space
198  * must be fatal, but a fault on userspace is a futex fault and we
199  * need to return -EFAULT. Note that the context this routine is
200  * invoked in is the context of the "_atomic_xxx()" routines called
201  * by the functions in this file.
202  */
204 {
205  if (unlikely(!access_ok(VERIFY_WRITE, addr, sizeof(int))))
206  panic("Bad address used for kernel atomic op: %p\n", addr);
207  return (struct __get_user) { .err = -EFAULT };
208 }
209 
210 
211 #if CHIP_HAS_CBOX_HOME_MAP()
212 static int __init noatomichash(char *str)
213 {
214  pr_warning("noatomichash is deprecated.\n");
215  return 1;
216 }
217 __setup("noatomichash", noatomichash);
218 #endif
219 
221 {
222 #if ATOMIC_LOCKS_FOUND_VIA_TABLE()
223 
224  unsigned int i;
225  int actual_cpu;
226 
227  /*
228  * Before this is called from setup, we just have one lock for
229  * all atomic objects/operations. Here we replace the
230  * elements of atomic_lock_ptr so that they point at per_cpu
231  * integers. This seemingly over-complex approach stems from
232  * the fact that DEFINE_PER_CPU defines an entry for each cpu
233  * in the grid, not each cpu from 0..ATOMIC_HASH_SIZE-1. But
234  * for efficient hashing of atomics to their locks we want a
235  * compile time constant power of 2 for the size of this
236  * table, so we use ATOMIC_HASH_SIZE.
237  *
238  * Here we populate atomic_lock_ptr from the per cpu
239  * atomic_lock_pool, interspersing by actual cpu so that
240  * subsequent elements are homed on consecutive cpus.
241  */
242 
243  actual_cpu = cpumask_first(cpu_possible_mask);
244 
245  for (i = 0; i < ATOMIC_HASH_L1_SIZE; ++i) {
246  /*
247  * Preincrement to slightly bias against using cpu 0,
248  * which has plenty of stuff homed on it already.
249  */
250  actual_cpu = cpumask_next(actual_cpu, cpu_possible_mask);
251  if (actual_cpu >= nr_cpu_ids)
252  actual_cpu = cpumask_first(cpu_possible_mask);
253 
254  atomic_lock_ptr[i] = &per_cpu(atomic_lock_pool, actual_cpu);
255  }
256 
257 #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
258 
259  /* Validate power-of-two and "bigger than cpus" assumption */
262 
263  /*
264  * On TILEPro we prefer to use a single hash-for-home
265  * page, since this means atomic operations are less
266  * likely to encounter a TLB fault and thus should
267  * in general perform faster. You may wish to disable
268  * this in situations where few hash-for-home tiles
269  * are configured.
270  */
271  BUG_ON((unsigned long)atomic_locks % PAGE_SIZE != 0);
272 
273  /* The locks must all fit on one page. */
274  BUILD_BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
275 
276  /*
277  * We use the page offset of the atomic value's address as
278  * an index into atomic_locks, excluding the low 3 bits.
279  * That should not produce more indices than ATOMIC_HASH_SIZE.
280  */
282 
283 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
284 }