Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: Atomic/bitops/cmpxchg/barriers

This covers the UP / SMP (with no hardware assist for atomic r-m-w) as
well as ARC700 LLOCK/SCOND insns based.

Signed-off-by: Vineet Gupta <vgupta@synopsys.com>

+967
+232
arch/arc/include/asm/atomic.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _ASM_ARC_ATOMIC_H 10 + #define _ASM_ARC_ATOMIC_H 11 + 12 + #ifdef __KERNEL__ 13 + 14 + #ifndef __ASSEMBLY__ 15 + 16 + #include <linux/types.h> 17 + #include <linux/compiler.h> 18 + #include <asm/cmpxchg.h> 19 + #include <asm/barrier.h> 20 + #include <asm/smp.h> 21 + 22 + #define atomic_read(v) ((v)->counter) 23 + 24 + #ifdef CONFIG_ARC_HAS_LLSC 25 + 26 + #define atomic_set(v, i) (((v)->counter) = (i)) 27 + 28 + static inline void atomic_add(int i, atomic_t *v) 29 + { 30 + unsigned int temp; 31 + 32 + __asm__ __volatile__( 33 + "1: llock %0, [%1] \n" 34 + " add %0, %0, %2 \n" 35 + " scond %0, [%1] \n" 36 + " bnz 1b \n" 37 + : "=&r"(temp) /* Early clobber, to prevent reg reuse */ 38 + : "r"(&v->counter), "ir"(i) 39 + : "cc"); 40 + } 41 + 42 + static inline void atomic_sub(int i, atomic_t *v) 43 + { 44 + unsigned int temp; 45 + 46 + __asm__ __volatile__( 47 + "1: llock %0, [%1] \n" 48 + " sub %0, %0, %2 \n" 49 + " scond %0, [%1] \n" 50 + " bnz 1b \n" 51 + : "=&r"(temp) 52 + : "r"(&v->counter), "ir"(i) 53 + : "cc"); 54 + } 55 + 56 + /* add and also return the new value */ 57 + static inline int atomic_add_return(int i, atomic_t *v) 58 + { 59 + unsigned int temp; 60 + 61 + __asm__ __volatile__( 62 + "1: llock %0, [%1] \n" 63 + " add %0, %0, %2 \n" 64 + " scond %0, [%1] \n" 65 + " bnz 1b \n" 66 + : "=&r"(temp) 67 + : "r"(&v->counter), "ir"(i) 68 + : "cc"); 69 + 70 + return temp; 71 + } 72 + 73 + static inline int atomic_sub_return(int i, atomic_t *v) 74 + { 75 + unsigned int temp; 76 + 77 + __asm__ __volatile__( 78 + "1: llock %0, [%1] \n" 79 + " sub %0, %0, %2 \n" 80 + " scond %0, [%1] \n" 81 + " bnz 1b \n" 82 + : "=&r"(temp) 83 + : "r"(&v->counter), "ir"(i) 84 + : "cc"); 85 + 86 + return temp; 87 + } 88 + 89 + static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) 90 + { 91 + unsigned int temp; 92 + 93 + __asm__ __volatile__( 94 + "1: llock %0, [%1] \n" 95 + " bic %0, %0, %2 \n" 96 + " scond %0, [%1] \n" 97 + " bnz 1b \n" 98 + : "=&r"(temp) 99 + : "r"(addr), "ir"(mask) 100 + : "cc"); 101 + } 102 + 103 + #else /* !CONFIG_ARC_HAS_LLSC */ 104 + 105 + #ifndef CONFIG_SMP 106 + 107 + /* violating atomic_xxx API locking protocol in UP for optimization sake */ 108 + #define atomic_set(v, i) (((v)->counter) = (i)) 109 + 110 + #else 111 + 112 + static inline void atomic_set(atomic_t *v, int i) 113 + { 114 + /* 115 + * Independent of hardware support, all of the atomic_xxx() APIs need 116 + * to follow the same locking rules to make sure that a "hardware" 117 + * atomic insn (e.g. LD) doesn't clobber an "emulated" atomic insn 118 + * sequence 119 + * 120 + * Thus atomic_set() despite being 1 insn (and seemingly atomic) 121 + * requires the locking. 122 + */ 123 + unsigned long flags; 124 + 125 + atomic_ops_lock(flags); 126 + v->counter = i; 127 + atomic_ops_unlock(flags); 128 + } 129 + #endif 130 + 131 + /* 132 + * Non hardware assisted Atomic-R-M-W 133 + * Locking would change to irq-disabling only (UP) and spinlocks (SMP) 134 + */ 135 + 136 + static inline void atomic_add(int i, atomic_t *v) 137 + { 138 + unsigned long flags; 139 + 140 + atomic_ops_lock(flags); 141 + v->counter += i; 142 + atomic_ops_unlock(flags); 143 + } 144 + 145 + static inline void atomic_sub(int i, atomic_t *v) 146 + { 147 + unsigned long flags; 148 + 149 + atomic_ops_lock(flags); 150 + v->counter -= i; 151 + atomic_ops_unlock(flags); 152 + } 153 + 154 + static inline int atomic_add_return(int i, atomic_t *v) 155 + { 156 + unsigned long flags; 157 + unsigned long temp; 158 + 159 + atomic_ops_lock(flags); 160 + temp = v->counter; 161 + temp += i; 162 + v->counter = temp; 163 + atomic_ops_unlock(flags); 164 + 165 + return temp; 166 + } 167 + 168 + static inline int atomic_sub_return(int i, atomic_t *v) 169 + { 170 + unsigned long flags; 171 + unsigned long temp; 172 + 173 + atomic_ops_lock(flags); 174 + temp = v->counter; 175 + temp -= i; 176 + v->counter = temp; 177 + atomic_ops_unlock(flags); 178 + 179 + return temp; 180 + } 181 + 182 + static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) 183 + { 184 + unsigned long flags; 185 + 186 + atomic_ops_lock(flags); 187 + *addr &= ~mask; 188 + atomic_ops_unlock(flags); 189 + } 190 + 191 + #endif /* !CONFIG_ARC_HAS_LLSC */ 192 + 193 + /** 194 + * __atomic_add_unless - add unless the number is a given value 195 + * @v: pointer of type atomic_t 196 + * @a: the amount to add to v... 197 + * @u: ...unless v is equal to u. 198 + * 199 + * Atomically adds @a to @v, so long as it was not @u. 200 + * Returns the old value of @v 201 + */ 202 + #define __atomic_add_unless(v, a, u) \ 203 + ({ \ 204 + int c, old; \ 205 + c = atomic_read(v); \ 206 + while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c)\ 207 + c = old; \ 208 + c; \ 209 + }) 210 + 211 + #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 212 + 213 + #define atomic_inc(v) atomic_add(1, v) 214 + #define atomic_dec(v) atomic_sub(1, v) 215 + 216 + #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) 217 + #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) 218 + #define atomic_inc_return(v) atomic_add_return(1, (v)) 219 + #define atomic_dec_return(v) atomic_sub_return(1, (v)) 220 + #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) 221 + 222 + #define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) 223 + 224 + #define ATOMIC_INIT(i) { (i) } 225 + 226 + #include <asm-generic/atomic64.h> 227 + 228 + #endif 229 + 230 + #endif 231 + 232 + #endif
+42
arch/arc/include/asm/barrier.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef __ASM_BARRIER_H 10 + #define __ASM_BARRIER_H 11 + 12 + #ifndef __ASSEMBLY__ 13 + 14 + /* TODO-vineetg: Need to see what this does, don't we need sync anywhere */ 15 + #define mb() __asm__ __volatile__ ("" : : : "memory") 16 + #define rmb() mb() 17 + #define wmb() mb() 18 + #define set_mb(var, value) do { var = value; mb(); } while (0) 19 + #define set_wmb(var, value) do { var = value; wmb(); } while (0) 20 + #define read_barrier_depends() mb() 21 + 22 + /* TODO-vineetg verify the correctness of macros here */ 23 + #ifdef CONFIG_SMP 24 + #define smp_mb() mb() 25 + #define smp_rmb() rmb() 26 + #define smp_wmb() wmb() 27 + #else 28 + #define smp_mb() barrier() 29 + #define smp_rmb() barrier() 30 + #define smp_wmb() barrier() 31 + #endif 32 + 33 + #define smp_mb__before_atomic_dec() barrier() 34 + #define smp_mb__after_atomic_dec() barrier() 35 + #define smp_mb__before_atomic_inc() barrier() 36 + #define smp_mb__after_atomic_inc() barrier() 37 + 38 + #define smp_read_barrier_depends() do { } while (0) 39 + 40 + #endif 41 + 42 + #endif
+516
arch/arc/include/asm/bitops.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef _ASM_BITOPS_H 10 + #define _ASM_BITOPS_H 11 + 12 + #ifndef _LINUX_BITOPS_H 13 + #error only <linux/bitops.h> can be included directly 14 + #endif 15 + 16 + #ifdef __KERNEL__ 17 + 18 + #ifndef __ASSEMBLY__ 19 + 20 + #include <linux/types.h> 21 + #include <linux/compiler.h> 22 + 23 + /* 24 + * Hardware assisted read-modify-write using ARC700 LLOCK/SCOND insns. 25 + * The Kconfig glue ensures that in SMP, this is only set if the container 26 + * SoC/platform has cross-core coherent LLOCK/SCOND 27 + */ 28 + #if defined(CONFIG_ARC_HAS_LLSC) 29 + 30 + static inline void set_bit(unsigned long nr, volatile unsigned long *m) 31 + { 32 + unsigned int temp; 33 + 34 + m += nr >> 5; 35 + 36 + if (__builtin_constant_p(nr)) 37 + nr &= 0x1f; 38 + 39 + __asm__ __volatile__( 40 + "1: llock %0, [%1] \n" 41 + " bset %0, %0, %2 \n" 42 + " scond %0, [%1] \n" 43 + " bnz 1b \n" 44 + : "=&r"(temp) 45 + : "r"(m), "ir"(nr) 46 + : "cc"); 47 + } 48 + 49 + static inline void clear_bit(unsigned long nr, volatile unsigned long *m) 50 + { 51 + unsigned int temp; 52 + 53 + m += nr >> 5; 54 + 55 + if (__builtin_constant_p(nr)) 56 + nr &= 0x1f; 57 + 58 + __asm__ __volatile__( 59 + "1: llock %0, [%1] \n" 60 + " bclr %0, %0, %2 \n" 61 + " scond %0, [%1] \n" 62 + " bnz 1b \n" 63 + : "=&r"(temp) 64 + : "r"(m), "ir"(nr) 65 + : "cc"); 66 + } 67 + 68 + static inline void change_bit(unsigned long nr, volatile unsigned long *m) 69 + { 70 + unsigned int temp; 71 + 72 + m += nr >> 5; 73 + 74 + if (__builtin_constant_p(nr)) 75 + nr &= 0x1f; 76 + 77 + __asm__ __volatile__( 78 + "1: llock %0, [%1] \n" 79 + " bxor %0, %0, %2 \n" 80 + " scond %0, [%1] \n" 81 + " bnz 1b \n" 82 + : "=&r"(temp) 83 + : "r"(m), "ir"(nr) 84 + : "cc"); 85 + } 86 + 87 + /* 88 + * Semantically: 89 + * Test the bit 90 + * if clear 91 + * set it and return 0 (old value) 92 + * else 93 + * return 1 (old value). 94 + * 95 + * Since ARC lacks a equivalent h/w primitive, the bit is set unconditionally 96 + * and the old value of bit is returned 97 + */ 98 + static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m) 99 + { 100 + unsigned long old, temp; 101 + 102 + m += nr >> 5; 103 + 104 + if (__builtin_constant_p(nr)) 105 + nr &= 0x1f; 106 + 107 + __asm__ __volatile__( 108 + "1: llock %0, [%2] \n" 109 + " bset %1, %0, %3 \n" 110 + " scond %1, [%2] \n" 111 + " bnz 1b \n" 112 + : "=&r"(old), "=&r"(temp) 113 + : "r"(m), "ir"(nr) 114 + : "cc"); 115 + 116 + return (old & (1 << nr)) != 0; 117 + } 118 + 119 + static inline int 120 + test_and_clear_bit(unsigned long nr, volatile unsigned long *m) 121 + { 122 + unsigned int old, temp; 123 + 124 + m += nr >> 5; 125 + 126 + if (__builtin_constant_p(nr)) 127 + nr &= 0x1f; 128 + 129 + __asm__ __volatile__( 130 + "1: llock %0, [%2] \n" 131 + " bclr %1, %0, %3 \n" 132 + " scond %1, [%2] \n" 133 + " bnz 1b \n" 134 + : "=&r"(old), "=&r"(temp) 135 + : "r"(m), "ir"(nr) 136 + : "cc"); 137 + 138 + return (old & (1 << nr)) != 0; 139 + } 140 + 141 + static inline int 142 + test_and_change_bit(unsigned long nr, volatile unsigned long *m) 143 + { 144 + unsigned int old, temp; 145 + 146 + m += nr >> 5; 147 + 148 + if (__builtin_constant_p(nr)) 149 + nr &= 0x1f; 150 + 151 + __asm__ __volatile__( 152 + "1: llock %0, [%2] \n" 153 + " bxor %1, %0, %3 \n" 154 + " scond %1, [%2] \n" 155 + " bnz 1b \n" 156 + : "=&r"(old), "=&r"(temp) 157 + : "r"(m), "ir"(nr) 158 + : "cc"); 159 + 160 + return (old & (1 << nr)) != 0; 161 + } 162 + 163 + #else /* !CONFIG_ARC_HAS_LLSC */ 164 + 165 + #include <asm/smp.h> 166 + 167 + /* 168 + * Non hardware assisted Atomic-R-M-W 169 + * Locking would change to irq-disabling only (UP) and spinlocks (SMP) 170 + * 171 + * There's "significant" micro-optimization in writing our own variants of 172 + * bitops (over generic variants) 173 + * 174 + * (1) The generic APIs have "signed" @nr while we have it "unsigned" 175 + * This avoids extra code to be generated for pointer arithmatic, since 176 + * is "not sure" that index is NOT -ve 177 + * (2) Utilize the fact that ARCompact bit fidding insn (BSET/BCLR/ASL) etc 178 + * only consider bottom 5 bits of @nr, so NO need to mask them off. 179 + * (GCC Quirk: however for constant @nr we still need to do the masking 180 + * at compile time) 181 + */ 182 + 183 + static inline void set_bit(unsigned long nr, volatile unsigned long *m) 184 + { 185 + unsigned long temp, flags; 186 + m += nr >> 5; 187 + 188 + if (__builtin_constant_p(nr)) 189 + nr &= 0x1f; 190 + 191 + bitops_lock(flags); 192 + 193 + temp = *m; 194 + *m = temp | (1UL << nr); 195 + 196 + bitops_unlock(flags); 197 + } 198 + 199 + static inline void clear_bit(unsigned long nr, volatile unsigned long *m) 200 + { 201 + unsigned long temp, flags; 202 + m += nr >> 5; 203 + 204 + if (__builtin_constant_p(nr)) 205 + nr &= 0x1f; 206 + 207 + bitops_lock(flags); 208 + 209 + temp = *m; 210 + *m = temp & ~(1UL << nr); 211 + 212 + bitops_unlock(flags); 213 + } 214 + 215 + static inline void change_bit(unsigned long nr, volatile unsigned long *m) 216 + { 217 + unsigned long temp, flags; 218 + m += nr >> 5; 219 + 220 + if (__builtin_constant_p(nr)) 221 + nr &= 0x1f; 222 + 223 + bitops_lock(flags); 224 + 225 + temp = *m; 226 + *m = temp ^ (1UL << nr); 227 + 228 + bitops_unlock(flags); 229 + } 230 + 231 + static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m) 232 + { 233 + unsigned long old, flags; 234 + m += nr >> 5; 235 + 236 + if (__builtin_constant_p(nr)) 237 + nr &= 0x1f; 238 + 239 + bitops_lock(flags); 240 + 241 + old = *m; 242 + *m = old | (1 << nr); 243 + 244 + bitops_unlock(flags); 245 + 246 + return (old & (1 << nr)) != 0; 247 + } 248 + 249 + static inline int 250 + test_and_clear_bit(unsigned long nr, volatile unsigned long *m) 251 + { 252 + unsigned long old, flags; 253 + m += nr >> 5; 254 + 255 + if (__builtin_constant_p(nr)) 256 + nr &= 0x1f; 257 + 258 + bitops_lock(flags); 259 + 260 + old = *m; 261 + *m = old & ~(1 << nr); 262 + 263 + bitops_unlock(flags); 264 + 265 + return (old & (1 << nr)) != 0; 266 + } 267 + 268 + static inline int 269 + test_and_change_bit(unsigned long nr, volatile unsigned long *m) 270 + { 271 + unsigned long old, flags; 272 + m += nr >> 5; 273 + 274 + if (__builtin_constant_p(nr)) 275 + nr &= 0x1f; 276 + 277 + bitops_lock(flags); 278 + 279 + old = *m; 280 + *m = old ^ (1 << nr); 281 + 282 + bitops_unlock(flags); 283 + 284 + return (old & (1 << nr)) != 0; 285 + } 286 + 287 + #endif /* CONFIG_ARC_HAS_LLSC */ 288 + 289 + /*************************************** 290 + * Non atomic variants 291 + **************************************/ 292 + 293 + static inline void __set_bit(unsigned long nr, volatile unsigned long *m) 294 + { 295 + unsigned long temp; 296 + m += nr >> 5; 297 + 298 + if (__builtin_constant_p(nr)) 299 + nr &= 0x1f; 300 + 301 + temp = *m; 302 + *m = temp | (1UL << nr); 303 + } 304 + 305 + static inline void __clear_bit(unsigned long nr, volatile unsigned long *m) 306 + { 307 + unsigned long temp; 308 + m += nr >> 5; 309 + 310 + if (__builtin_constant_p(nr)) 311 + nr &= 0x1f; 312 + 313 + temp = *m; 314 + *m = temp & ~(1UL << nr); 315 + } 316 + 317 + static inline void __change_bit(unsigned long nr, volatile unsigned long *m) 318 + { 319 + unsigned long temp; 320 + m += nr >> 5; 321 + 322 + if (__builtin_constant_p(nr)) 323 + nr &= 0x1f; 324 + 325 + temp = *m; 326 + *m = temp ^ (1UL << nr); 327 + } 328 + 329 + static inline int 330 + __test_and_set_bit(unsigned long nr, volatile unsigned long *m) 331 + { 332 + unsigned long old; 333 + m += nr >> 5; 334 + 335 + if (__builtin_constant_p(nr)) 336 + nr &= 0x1f; 337 + 338 + old = *m; 339 + *m = old | (1 << nr); 340 + 341 + return (old & (1 << nr)) != 0; 342 + } 343 + 344 + static inline int 345 + __test_and_clear_bit(unsigned long nr, volatile unsigned long *m) 346 + { 347 + unsigned long old; 348 + m += nr >> 5; 349 + 350 + if (__builtin_constant_p(nr)) 351 + nr &= 0x1f; 352 + 353 + old = *m; 354 + *m = old & ~(1 << nr); 355 + 356 + return (old & (1 << nr)) != 0; 357 + } 358 + 359 + static inline int 360 + __test_and_change_bit(unsigned long nr, volatile unsigned long *m) 361 + { 362 + unsigned long old; 363 + m += nr >> 5; 364 + 365 + if (__builtin_constant_p(nr)) 366 + nr &= 0x1f; 367 + 368 + old = *m; 369 + *m = old ^ (1 << nr); 370 + 371 + return (old & (1 << nr)) != 0; 372 + } 373 + 374 + /* 375 + * This routine doesn't need to be atomic. 376 + */ 377 + static inline int 378 + __constant_test_bit(unsigned int nr, const volatile unsigned long *addr) 379 + { 380 + return ((1UL << (nr & 31)) & 381 + (((const volatile unsigned int *)addr)[nr >> 5])) != 0; 382 + } 383 + 384 + static inline int 385 + __test_bit(unsigned int nr, const volatile unsigned long *addr) 386 + { 387 + unsigned long mask; 388 + 389 + addr += nr >> 5; 390 + 391 + /* ARC700 only considers 5 bits in bit-fiddling insn */ 392 + mask = 1 << nr; 393 + 394 + return ((mask & *addr) != 0); 395 + } 396 + 397 + #define test_bit(nr, addr) (__builtin_constant_p(nr) ? \ 398 + __constant_test_bit((nr), (addr)) : \ 399 + __test_bit((nr), (addr))) 400 + 401 + /* 402 + * Count the number of zeros, starting from MSB 403 + * Helper for fls( ) friends 404 + * This is a pure count, so (1-32) or (0-31) doesn't apply 405 + * It could be 0 to 32, based on num of 0's in there 406 + * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31 407 + */ 408 + static inline __attribute__ ((const)) int clz(unsigned int x) 409 + { 410 + unsigned int res; 411 + 412 + __asm__ __volatile__( 413 + " norm.f %0, %1 \n" 414 + " mov.n %0, 0 \n" 415 + " add.p %0, %0, 1 \n" 416 + : "=r"(res) 417 + : "r"(x) 418 + : "cc"); 419 + 420 + return res; 421 + } 422 + 423 + static inline int constant_fls(int x) 424 + { 425 + int r = 32; 426 + 427 + if (!x) 428 + return 0; 429 + if (!(x & 0xffff0000u)) { 430 + x <<= 16; 431 + r -= 16; 432 + } 433 + if (!(x & 0xff000000u)) { 434 + x <<= 8; 435 + r -= 8; 436 + } 437 + if (!(x & 0xf0000000u)) { 438 + x <<= 4; 439 + r -= 4; 440 + } 441 + if (!(x & 0xc0000000u)) { 442 + x <<= 2; 443 + r -= 2; 444 + } 445 + if (!(x & 0x80000000u)) { 446 + x <<= 1; 447 + r -= 1; 448 + } 449 + return r; 450 + } 451 + 452 + /* 453 + * fls = Find Last Set in word 454 + * @result: [1-32] 455 + * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0 456 + */ 457 + static inline __attribute__ ((const)) int fls(unsigned long x) 458 + { 459 + if (__builtin_constant_p(x)) 460 + return constant_fls(x); 461 + 462 + return 32 - clz(x); 463 + } 464 + 465 + /* 466 + * __fls: Similar to fls, but zero based (0-31) 467 + */ 468 + static inline __attribute__ ((const)) int __fls(unsigned long x) 469 + { 470 + if (!x) 471 + return 0; 472 + else 473 + return fls(x) - 1; 474 + } 475 + 476 + /* 477 + * ffs = Find First Set in word (LSB to MSB) 478 + * @result: [1-32], 0 if all 0's 479 + */ 480 + #define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) 481 + 482 + /* 483 + * __ffs: Similar to ffs, but zero based (0-31) 484 + */ 485 + static inline __attribute__ ((const)) int __ffs(unsigned long word) 486 + { 487 + if (!word) 488 + return word; 489 + 490 + return ffs(word) - 1; 491 + } 492 + 493 + /* 494 + * ffz = Find First Zero in word. 495 + * @return:[0-31], 32 if all 1's 496 + */ 497 + #define ffz(x) __ffs(~(x)) 498 + 499 + /* TODO does this affect uni-processor code */ 500 + #define smp_mb__before_clear_bit() barrier() 501 + #define smp_mb__after_clear_bit() barrier() 502 + 503 + #include <asm-generic/bitops/hweight.h> 504 + #include <asm-generic/bitops/fls64.h> 505 + #include <asm-generic/bitops/sched.h> 506 + #include <asm-generic/bitops/lock.h> 507 + 508 + #include <asm-generic/bitops/find.h> 509 + #include <asm-generic/bitops/le.h> 510 + #include <asm-generic/bitops/ext2-atomic-setbit.h> 511 + 512 + #endif /* !__ASSEMBLY__ */ 513 + 514 + #endif /* __KERNEL__ */ 515 + 516 + #endif
+143
arch/arc/include/asm/cmpxchg.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef __ASM_ARC_CMPXCHG_H 10 + #define __ASM_ARC_CMPXCHG_H 11 + 12 + #include <linux/types.h> 13 + #include <asm/smp.h> 14 + 15 + #ifdef CONFIG_ARC_HAS_LLSC 16 + 17 + static inline unsigned long 18 + __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) 19 + { 20 + unsigned long prev; 21 + 22 + __asm__ __volatile__( 23 + "1: llock %0, [%1] \n" 24 + " brne %0, %2, 2f \n" 25 + " scond %3, [%1] \n" 26 + " bnz 1b \n" 27 + "2: \n" 28 + : "=&r"(prev) 29 + : "r"(ptr), "ir"(expected), 30 + "r"(new) /* can't be "ir". scond can't take limm for "b" */ 31 + : "cc"); 32 + 33 + return prev; 34 + } 35 + 36 + #else 37 + 38 + static inline unsigned long 39 + __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) 40 + { 41 + unsigned long flags; 42 + int prev; 43 + volatile unsigned long *p = ptr; 44 + 45 + atomic_ops_lock(flags); 46 + prev = *p; 47 + if (prev == expected) 48 + *p = new; 49 + atomic_ops_unlock(flags); 50 + return prev; 51 + } 52 + 53 + #endif /* CONFIG_ARC_HAS_LLSC */ 54 + 55 + #define cmpxchg(ptr, o, n) ((typeof(*(ptr)))__cmpxchg((ptr), \ 56 + (unsigned long)(o), (unsigned long)(n))) 57 + 58 + /* 59 + * Since not supported natively, ARC cmpxchg() uses atomic_ops_lock (UP/SMP) 60 + * just to gaurantee semantics. 61 + * atomic_cmpxchg() needs to use the same locks as it's other atomic siblings 62 + * which also happens to be atomic_ops_lock. 63 + * 64 + * Thus despite semantically being different, implementation of atomic_cmpxchg() 65 + * is same as cmpxchg(). 66 + */ 67 + #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 68 + 69 + 70 + /* 71 + * xchg (reg with memory) based on "Native atomic" EX insn 72 + */ 73 + static inline unsigned long __xchg(unsigned long val, volatile void *ptr, 74 + int size) 75 + { 76 + extern unsigned long __xchg_bad_pointer(void); 77 + 78 + switch (size) { 79 + case 4: 80 + __asm__ __volatile__( 81 + " ex %0, [%1] \n" 82 + : "+r"(val) 83 + : "r"(ptr) 84 + : "memory"); 85 + 86 + return val; 87 + } 88 + return __xchg_bad_pointer(); 89 + } 90 + 91 + #define _xchg(ptr, with) ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), \ 92 + sizeof(*(ptr)))) 93 + 94 + /* 95 + * On ARC700, EX insn is inherently atomic, so by default "vanilla" xchg() need 96 + * not require any locking. However there's a quirk. 97 + * ARC lacks native CMPXCHG, thus emulated (see above), using external locking - 98 + * incidently it "reuses" the same atomic_ops_lock used by atomic APIs. 99 + * Now, llist code uses cmpxchg() and xchg() on same data, so xchg() needs to 100 + * abide by same serializing rules, thus ends up using atomic_ops_lock as well. 101 + * 102 + * This however is only relevant if SMP and/or ARC lacks LLSC 103 + * if (UP or LLSC) 104 + * xchg doesn't need serialization 105 + * else <==> !(UP or LLSC) <==> (!UP and !LLSC) <==> (SMP and !LLSC) 106 + * xchg needs serialization 107 + */ 108 + 109 + #if !defined(CONFIG_ARC_HAS_LLSC) && defined(CONFIG_SMP) 110 + 111 + #define xchg(ptr, with) \ 112 + ({ \ 113 + unsigned long flags; \ 114 + typeof(*(ptr)) old_val; \ 115 + \ 116 + atomic_ops_lock(flags); \ 117 + old_val = _xchg(ptr, with); \ 118 + atomic_ops_unlock(flags); \ 119 + old_val; \ 120 + }) 121 + 122 + #else 123 + 124 + #define xchg(ptr, with) _xchg(ptr, with) 125 + 126 + #endif 127 + 128 + /* 129 + * "atomic" variant of xchg() 130 + * REQ: It needs to follow the same serialization rules as other atomic_xxx() 131 + * Since xchg() doesn't always do that, it would seem that following defintion 132 + * is incorrect. But here's the rationale: 133 + * SMP : Even xchg() takes the atomic_ops_lock, so OK. 134 + * LLSC: atomic_ops_lock are not relevent at all (even if SMP, since LLSC 135 + * is natively "SMP safe", no serialization required). 136 + * UP : other atomics disable IRQ, so no way a difft ctxt atomic_xchg() 137 + * could clobber them. atomic_xchg() itself would be 1 insn, so it 138 + * can't be clobbered by others. Thus no serialization required when 139 + * atomic_xchg is involved. 140 + */ 141 + #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 142 + 143 + #endif
+34
arch/arc/include/asm/smp.h
··· 1 + /* 2 + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef __ASM_ARC_SMP_H 10 + #define __ASM_ARC_SMP_H 11 + 12 + /* 13 + * ARC700 doesn't support atomic Read-Modify-Write ops. 14 + * Originally Interrupts had to be disabled around code to gaurantee atomicity. 15 + * The LLOCK/SCOND insns allow writing interrupt-hassle-free based atomic ops 16 + * based on retry-if-irq-in-atomic (with hardware assist). 17 + * However despite these, we provide the IRQ disabling variant 18 + * 19 + * (1) These insn were introduced only in 4.10 release. So for older released 20 + * support needed. 21 + */ 22 + #ifndef CONFIG_ARC_HAS_LLSC 23 + 24 + #include <linux/irqflags.h> 25 + 26 + #define atomic_ops_lock(flags) local_irq_save(flags) 27 + #define atomic_ops_unlock(flags) local_irq_restore(flags) 28 + 29 + #define bitops_lock(flags) local_irq_save(flags) 30 + #define bitops_unlock(flags) local_irq_restore(flags) 31 + 32 + #endif /* !CONFIG_ARC_HAS_LLSC */ 33 + 34 + #endif