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 #ifndef __ASSEMBLY__ 17 18 #include <linux/types.h> 19 #include <linux/compiler.h> 20 #include <asm/barrier.h> 21 22 /* 23 * Hardware assisted read-modify-write using ARC700 LLOCK/SCOND insns. 24 * The Kconfig glue ensures that in SMP, this is only set if the container 25 * SoC/platform has cross-core coherent LLOCK/SCOND 26 */ 27 #if defined(CONFIG_ARC_HAS_LLSC) 28 29 static inline void set_bit(unsigned long nr, volatile unsigned long *m) 30 { 31 unsigned int temp; 32 33 m += nr >> 5; 34 35 /* 36 * ARC ISA micro-optimization: 37 * 38 * Instructions dealing with bitpos only consider lower 5 bits (0-31) 39 * e.g (x << 33) is handled like (x << 1) by ASL instruction 40 * (mem pointer still needs adjustment to point to next word) 41 * 42 * Hence the masking to clamp @nr arg can be elided in general. 43 * 44 * However if @nr is a constant (above assumed it in a register), 45 * and greater than 31, gcc can optimize away (x << 33) to 0, 46 * as overflow, given the 32-bit ISA. Thus masking needs to be done 47 * for constant @nr, but no code is generated due to const prop. 48 */ 49 if (__builtin_constant_p(nr)) 50 nr &= 0x1f; 51 52 __asm__ __volatile__( 53 "1: llock %0, [%1] \n" 54 " bset %0, %0, %2 \n" 55 " scond %0, [%1] \n" 56 " bnz 1b \n" 57 : "=&r"(temp) 58 : "r"(m), "ir"(nr) 59 : "cc"); 60 } 61 62 static inline void clear_bit(unsigned long nr, volatile unsigned long *m) 63 { 64 unsigned int temp; 65 66 m += nr >> 5; 67 68 if (__builtin_constant_p(nr)) 69 nr &= 0x1f; 70 71 __asm__ __volatile__( 72 "1: llock %0, [%1] \n" 73 " bclr %0, %0, %2 \n" 74 " scond %0, [%1] \n" 75 " bnz 1b \n" 76 : "=&r"(temp) 77 : "r"(m), "ir"(nr) 78 : "cc"); 79 } 80 81 static inline void change_bit(unsigned long nr, volatile unsigned long *m) 82 { 83 unsigned int temp; 84 85 m += nr >> 5; 86 87 if (__builtin_constant_p(nr)) 88 nr &= 0x1f; 89 90 __asm__ __volatile__( 91 "1: llock %0, [%1] \n" 92 " bxor %0, %0, %2 \n" 93 " scond %0, [%1] \n" 94 " bnz 1b \n" 95 : "=&r"(temp) 96 : "r"(m), "ir"(nr) 97 : "cc"); 98 } 99 100 /* 101 * Semantically: 102 * Test the bit 103 * if clear 104 * set it and return 0 (old value) 105 * else 106 * return 1 (old value). 107 * 108 * Since ARC lacks a equivalent h/w primitive, the bit is set unconditionally 109 * and the old value of bit is returned 110 */ 111 static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m) 112 { 113 unsigned long old, temp; 114 115 m += nr >> 5; 116 117 if (__builtin_constant_p(nr)) 118 nr &= 0x1f; 119 120 __asm__ __volatile__( 121 "1: llock %0, [%2] \n" 122 " bset %1, %0, %3 \n" 123 " scond %1, [%2] \n" 124 " bnz 1b \n" 125 : "=&r"(old), "=&r"(temp) 126 : "r"(m), "ir"(nr) 127 : "cc"); 128 129 return (old & (1 << nr)) != 0; 130 } 131 132 static inline int 133 test_and_clear_bit(unsigned long nr, volatile unsigned long *m) 134 { 135 unsigned int old, temp; 136 137 m += nr >> 5; 138 139 if (__builtin_constant_p(nr)) 140 nr &= 0x1f; 141 142 __asm__ __volatile__( 143 "1: llock %0, [%2] \n" 144 " bclr %1, %0, %3 \n" 145 " scond %1, [%2] \n" 146 " bnz 1b \n" 147 : "=&r"(old), "=&r"(temp) 148 : "r"(m), "ir"(nr) 149 : "cc"); 150 151 return (old & (1 << nr)) != 0; 152 } 153 154 static inline int 155 test_and_change_bit(unsigned long nr, volatile unsigned long *m) 156 { 157 unsigned int old, temp; 158 159 m += nr >> 5; 160 161 if (__builtin_constant_p(nr)) 162 nr &= 0x1f; 163 164 __asm__ __volatile__( 165 "1: llock %0, [%2] \n" 166 " bxor %1, %0, %3 \n" 167 " scond %1, [%2] \n" 168 " bnz 1b \n" 169 : "=&r"(old), "=&r"(temp) 170 : "r"(m), "ir"(nr) 171 : "cc"); 172 173 return (old & (1 << nr)) != 0; 174 } 175 176 #else /* !CONFIG_ARC_HAS_LLSC */ 177 178 #include <asm/smp.h> 179 180 /* 181 * Non hardware assisted Atomic-R-M-W 182 * Locking would change to irq-disabling only (UP) and spinlocks (SMP) 183 * 184 * There's "significant" micro-optimization in writing our own variants of 185 * bitops (over generic variants) 186 * 187 * (1) The generic APIs have "signed" @nr while we have it "unsigned" 188 * This avoids extra code to be generated for pointer arithmatic, since 189 * is "not sure" that index is NOT -ve 190 * (2) Utilize the fact that ARCompact bit fidding insn (BSET/BCLR/ASL) etc 191 * only consider bottom 5 bits of @nr, so NO need to mask them off. 192 * (GCC Quirk: however for constant @nr we still need to do the masking 193 * at compile time) 194 */ 195 196 static inline void set_bit(unsigned long nr, volatile unsigned long *m) 197 { 198 unsigned long temp, flags; 199 m += nr >> 5; 200 201 if (__builtin_constant_p(nr)) 202 nr &= 0x1f; 203 204 bitops_lock(flags); 205 206 temp = *m; 207 *m = temp | (1UL << nr); 208 209 bitops_unlock(flags); 210 } 211 212 static inline void clear_bit(unsigned long nr, volatile unsigned long *m) 213 { 214 unsigned long temp, flags; 215 m += nr >> 5; 216 217 if (__builtin_constant_p(nr)) 218 nr &= 0x1f; 219 220 bitops_lock(flags); 221 222 temp = *m; 223 *m = temp & ~(1UL << nr); 224 225 bitops_unlock(flags); 226 } 227 228 static inline void change_bit(unsigned long nr, volatile unsigned long *m) 229 { 230 unsigned long temp, flags; 231 m += nr >> 5; 232 233 if (__builtin_constant_p(nr)) 234 nr &= 0x1f; 235 236 bitops_lock(flags); 237 238 temp = *m; 239 *m = temp ^ (1UL << nr); 240 241 bitops_unlock(flags); 242 } 243 244 static inline int test_and_set_bit(unsigned long nr, volatile unsigned long *m) 245 { 246 unsigned long old, flags; 247 m += nr >> 5; 248 249 if (__builtin_constant_p(nr)) 250 nr &= 0x1f; 251 252 bitops_lock(flags); 253 254 old = *m; 255 *m = old | (1 << nr); 256 257 bitops_unlock(flags); 258 259 return (old & (1 << nr)) != 0; 260 } 261 262 static inline int 263 test_and_clear_bit(unsigned long nr, volatile unsigned long *m) 264 { 265 unsigned long old, flags; 266 m += nr >> 5; 267 268 if (__builtin_constant_p(nr)) 269 nr &= 0x1f; 270 271 bitops_lock(flags); 272 273 old = *m; 274 *m = old & ~(1 << nr); 275 276 bitops_unlock(flags); 277 278 return (old & (1 << nr)) != 0; 279 } 280 281 static inline int 282 test_and_change_bit(unsigned long nr, volatile unsigned long *m) 283 { 284 unsigned long old, flags; 285 m += nr >> 5; 286 287 if (__builtin_constant_p(nr)) 288 nr &= 0x1f; 289 290 bitops_lock(flags); 291 292 old = *m; 293 *m = old ^ (1 << nr); 294 295 bitops_unlock(flags); 296 297 return (old & (1 << nr)) != 0; 298 } 299 300 #endif /* CONFIG_ARC_HAS_LLSC */ 301 302 /*************************************** 303 * Non atomic variants 304 **************************************/ 305 306 static inline void __set_bit(unsigned long nr, volatile unsigned long *m) 307 { 308 unsigned long temp; 309 m += nr >> 5; 310 311 if (__builtin_constant_p(nr)) 312 nr &= 0x1f; 313 314 temp = *m; 315 *m = temp | (1UL << nr); 316 } 317 318 static inline void __clear_bit(unsigned long nr, volatile unsigned long *m) 319 { 320 unsigned long temp; 321 m += nr >> 5; 322 323 if (__builtin_constant_p(nr)) 324 nr &= 0x1f; 325 326 temp = *m; 327 *m = temp & ~(1UL << nr); 328 } 329 330 static inline void __change_bit(unsigned long nr, volatile unsigned long *m) 331 { 332 unsigned long temp; 333 m += nr >> 5; 334 335 if (__builtin_constant_p(nr)) 336 nr &= 0x1f; 337 338 temp = *m; 339 *m = temp ^ (1UL << nr); 340 } 341 342 static inline int 343 __test_and_set_bit(unsigned long nr, volatile unsigned long *m) 344 { 345 unsigned long old; 346 m += nr >> 5; 347 348 if (__builtin_constant_p(nr)) 349 nr &= 0x1f; 350 351 old = *m; 352 *m = old | (1 << nr); 353 354 return (old & (1 << nr)) != 0; 355 } 356 357 static inline int 358 __test_and_clear_bit(unsigned long nr, volatile unsigned long *m) 359 { 360 unsigned long old; 361 m += nr >> 5; 362 363 if (__builtin_constant_p(nr)) 364 nr &= 0x1f; 365 366 old = *m; 367 *m = old & ~(1 << nr); 368 369 return (old & (1 << nr)) != 0; 370 } 371 372 static inline int 373 __test_and_change_bit(unsigned long nr, volatile unsigned long *m) 374 { 375 unsigned long old; 376 m += nr >> 5; 377 378 if (__builtin_constant_p(nr)) 379 nr &= 0x1f; 380 381 old = *m; 382 *m = old ^ (1 << nr); 383 384 return (old & (1 << nr)) != 0; 385 } 386 387 /* 388 * This routine doesn't need to be atomic. 389 */ 390 static inline int 391 test_bit(unsigned int nr, const volatile unsigned long *addr) 392 { 393 unsigned long mask; 394 395 addr += nr >> 5; 396 397 if (__builtin_constant_p(nr)) 398 nr &= 0x1f; 399 400 mask = 1 << nr; 401 402 return ((mask & *addr) != 0); 403 } 404 405 /* 406 * Count the number of zeros, starting from MSB 407 * Helper for fls( ) friends 408 * This is a pure count, so (1-32) or (0-31) doesn't apply 409 * It could be 0 to 32, based on num of 0's in there 410 * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31 411 */ 412 static inline __attribute__ ((const)) int clz(unsigned int x) 413 { 414 unsigned int res; 415 416 __asm__ __volatile__( 417 " norm.f %0, %1 \n" 418 " mov.n %0, 0 \n" 419 " add.p %0, %0, 1 \n" 420 : "=r"(res) 421 : "r"(x) 422 : "cc"); 423 424 return res; 425 } 426 427 static inline int constant_fls(int x) 428 { 429 int r = 32; 430 431 if (!x) 432 return 0; 433 if (!(x & 0xffff0000u)) { 434 x <<= 16; 435 r -= 16; 436 } 437 if (!(x & 0xff000000u)) { 438 x <<= 8; 439 r -= 8; 440 } 441 if (!(x & 0xf0000000u)) { 442 x <<= 4; 443 r -= 4; 444 } 445 if (!(x & 0xc0000000u)) { 446 x <<= 2; 447 r -= 2; 448 } 449 if (!(x & 0x80000000u)) { 450 x <<= 1; 451 r -= 1; 452 } 453 return r; 454 } 455 456 /* 457 * fls = Find Last Set in word 458 * @result: [1-32] 459 * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0 460 */ 461 static inline __attribute__ ((const)) int fls(unsigned long x) 462 { 463 if (__builtin_constant_p(x)) 464 return constant_fls(x); 465 466 return 32 - clz(x); 467 } 468 469 /* 470 * __fls: Similar to fls, but zero based (0-31) 471 */ 472 static inline __attribute__ ((const)) int __fls(unsigned long x) 473 { 474 if (!x) 475 return 0; 476 else 477 return fls(x) - 1; 478 } 479 480 /* 481 * ffs = Find First Set in word (LSB to MSB) 482 * @result: [1-32], 0 if all 0's 483 */ 484 #define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) 485 486 /* 487 * __ffs: Similar to ffs, but zero based (0-31) 488 */ 489 static inline __attribute__ ((const)) int __ffs(unsigned long word) 490 { 491 if (!word) 492 return word; 493 494 return ffs(word) - 1; 495 } 496 497 /* 498 * ffz = Find First Zero in word. 499 * @return:[0-31], 32 if all 1's 500 */ 501 #define ffz(x) __ffs(~(x)) 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 515