at v4.9-rc2 437 lines 10 kB view raw
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#ifndef CONFIG_ARC_HAS_LLSC 22#include <asm/smp.h> 23#endif 24 25#ifdef CONFIG_ARC_HAS_LLSC 26 27/* 28 * Hardware assisted Atomic-R-M-W 29 */ 30 31#define BIT_OP(op, c_op, asm_op) \ 32static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\ 33{ \ 34 unsigned int temp; \ 35 \ 36 m += nr >> 5; \ 37 \ 38 nr &= 0x1f; \ 39 \ 40 __asm__ __volatile__( \ 41 "1: llock %0, [%1] \n" \ 42 " " #asm_op " %0, %0, %2 \n" \ 43 " scond %0, [%1] \n" \ 44 " bnz 1b \n" \ 45 : "=&r"(temp) /* Early clobber, to prevent reg reuse */ \ 46 : "r"(m), /* Not "m": llock only supports reg direct addr mode */ \ 47 "ir"(nr) \ 48 : "cc"); \ 49} 50 51/* 52 * Semantically: 53 * Test the bit 54 * if clear 55 * set it and return 0 (old value) 56 * else 57 * return 1 (old value). 58 * 59 * Since ARC lacks a equivalent h/w primitive, the bit is set unconditionally 60 * and the old value of bit is returned 61 */ 62#define TEST_N_BIT_OP(op, c_op, asm_op) \ 63static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\ 64{ \ 65 unsigned long old, temp; \ 66 \ 67 m += nr >> 5; \ 68 \ 69 nr &= 0x1f; \ 70 \ 71 /* \ 72 * Explicit full memory barrier needed before/after as \ 73 * LLOCK/SCOND themselves don't provide any such smenatic \ 74 */ \ 75 smp_mb(); \ 76 \ 77 __asm__ __volatile__( \ 78 "1: llock %0, [%2] \n" \ 79 " " #asm_op " %1, %0, %3 \n" \ 80 " scond %1, [%2] \n" \ 81 " bnz 1b \n" \ 82 : "=&r"(old), "=&r"(temp) \ 83 : "r"(m), "ir"(nr) \ 84 : "cc"); \ 85 \ 86 smp_mb(); \ 87 \ 88 return (old & (1 << nr)) != 0; \ 89} 90 91#elif !defined(CONFIG_ARC_PLAT_EZNPS) 92 93/* 94 * Non hardware assisted Atomic-R-M-W 95 * Locking would change to irq-disabling only (UP) and spinlocks (SMP) 96 * 97 * There's "significant" micro-optimization in writing our own variants of 98 * bitops (over generic variants) 99 * 100 * (1) The generic APIs have "signed" @nr while we have it "unsigned" 101 * This avoids extra code to be generated for pointer arithmatic, since 102 * is "not sure" that index is NOT -ve 103 * (2) Utilize the fact that ARCompact bit fidding insn (BSET/BCLR/ASL) etc 104 * only consider bottom 5 bits of @nr, so NO need to mask them off. 105 * (GCC Quirk: however for constant @nr we still need to do the masking 106 * at compile time) 107 */ 108 109#define BIT_OP(op, c_op, asm_op) \ 110static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\ 111{ \ 112 unsigned long temp, flags; \ 113 m += nr >> 5; \ 114 \ 115 /* \ 116 * spin lock/unlock provide the needed smp_mb() before/after \ 117 */ \ 118 bitops_lock(flags); \ 119 \ 120 temp = *m; \ 121 *m = temp c_op (1UL << (nr & 0x1f)); \ 122 \ 123 bitops_unlock(flags); \ 124} 125 126#define TEST_N_BIT_OP(op, c_op, asm_op) \ 127static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\ 128{ \ 129 unsigned long old, flags; \ 130 m += nr >> 5; \ 131 \ 132 bitops_lock(flags); \ 133 \ 134 old = *m; \ 135 *m = old c_op (1UL << (nr & 0x1f)); \ 136 \ 137 bitops_unlock(flags); \ 138 \ 139 return (old & (1UL << (nr & 0x1f))) != 0; \ 140} 141 142#else /* CONFIG_ARC_PLAT_EZNPS */ 143 144#define BIT_OP(op, c_op, asm_op) \ 145static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\ 146{ \ 147 m += nr >> 5; \ 148 \ 149 nr = (1UL << (nr & 0x1f)); \ 150 if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \ 151 nr = ~nr; \ 152 \ 153 __asm__ __volatile__( \ 154 " mov r2, %0\n" \ 155 " mov r3, %1\n" \ 156 " .word %2\n" \ 157 : \ 158 : "r"(nr), "r"(m), "i"(asm_op) \ 159 : "r2", "r3", "memory"); \ 160} 161 162#define TEST_N_BIT_OP(op, c_op, asm_op) \ 163static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\ 164{ \ 165 unsigned long old; \ 166 \ 167 m += nr >> 5; \ 168 \ 169 nr = old = (1UL << (nr & 0x1f)); \ 170 if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \ 171 old = ~old; \ 172 \ 173 /* Explicit full memory barrier needed before/after */ \ 174 smp_mb(); \ 175 \ 176 __asm__ __volatile__( \ 177 " mov r2, %0\n" \ 178 " mov r3, %1\n" \ 179 " .word %2\n" \ 180 " mov %0, r2" \ 181 : "+r"(old) \ 182 : "r"(m), "i"(asm_op) \ 183 : "r2", "r3", "memory"); \ 184 \ 185 smp_mb(); \ 186 \ 187 return (old & nr) != 0; \ 188} 189 190#endif /* CONFIG_ARC_PLAT_EZNPS */ 191 192/*************************************** 193 * Non atomic variants 194 **************************************/ 195 196#define __BIT_OP(op, c_op, asm_op) \ 197static inline void __##op##_bit(unsigned long nr, volatile unsigned long *m) \ 198{ \ 199 unsigned long temp; \ 200 m += nr >> 5; \ 201 \ 202 temp = *m; \ 203 *m = temp c_op (1UL << (nr & 0x1f)); \ 204} 205 206#define __TEST_N_BIT_OP(op, c_op, asm_op) \ 207static inline int __test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\ 208{ \ 209 unsigned long old; \ 210 m += nr >> 5; \ 211 \ 212 old = *m; \ 213 *m = old c_op (1UL << (nr & 0x1f)); \ 214 \ 215 return (old & (1UL << (nr & 0x1f))) != 0; \ 216} 217 218#define BIT_OPS(op, c_op, asm_op) \ 219 \ 220 /* set_bit(), clear_bit(), change_bit() */ \ 221 BIT_OP(op, c_op, asm_op) \ 222 \ 223 /* test_and_set_bit(), test_and_clear_bit(), test_and_change_bit() */\ 224 TEST_N_BIT_OP(op, c_op, asm_op) \ 225 \ 226 /* __set_bit(), __clear_bit(), __change_bit() */ \ 227 __BIT_OP(op, c_op, asm_op) \ 228 \ 229 /* __test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit() */\ 230 __TEST_N_BIT_OP(op, c_op, asm_op) 231 232#ifndef CONFIG_ARC_PLAT_EZNPS 233BIT_OPS(set, |, bset) 234BIT_OPS(clear, & ~, bclr) 235BIT_OPS(change, ^, bxor) 236#else 237BIT_OPS(set, |, CTOP_INST_AOR_DI_R2_R2_R3) 238BIT_OPS(clear, & ~, CTOP_INST_AAND_DI_R2_R2_R3) 239BIT_OPS(change, ^, CTOP_INST_AXOR_DI_R2_R2_R3) 240#endif 241 242/* 243 * This routine doesn't need to be atomic. 244 */ 245static inline int 246test_bit(unsigned int nr, const volatile unsigned long *addr) 247{ 248 unsigned long mask; 249 250 addr += nr >> 5; 251 252 mask = 1UL << (nr & 0x1f); 253 254 return ((mask & *addr) != 0); 255} 256 257#ifdef CONFIG_ISA_ARCOMPACT 258 259/* 260 * Count the number of zeros, starting from MSB 261 * Helper for fls( ) friends 262 * This is a pure count, so (1-32) or (0-31) doesn't apply 263 * It could be 0 to 32, based on num of 0's in there 264 * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31 265 */ 266static inline __attribute__ ((const)) int clz(unsigned int x) 267{ 268 unsigned int res; 269 270 __asm__ __volatile__( 271 " norm.f %0, %1 \n" 272 " mov.n %0, 0 \n" 273 " add.p %0, %0, 1 \n" 274 : "=r"(res) 275 : "r"(x) 276 : "cc"); 277 278 return res; 279} 280 281static inline int constant_fls(int x) 282{ 283 int r = 32; 284 285 if (!x) 286 return 0; 287 if (!(x & 0xffff0000u)) { 288 x <<= 16; 289 r -= 16; 290 } 291 if (!(x & 0xff000000u)) { 292 x <<= 8; 293 r -= 8; 294 } 295 if (!(x & 0xf0000000u)) { 296 x <<= 4; 297 r -= 4; 298 } 299 if (!(x & 0xc0000000u)) { 300 x <<= 2; 301 r -= 2; 302 } 303 if (!(x & 0x80000000u)) { 304 x <<= 1; 305 r -= 1; 306 } 307 return r; 308} 309 310/* 311 * fls = Find Last Set in word 312 * @result: [1-32] 313 * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0 314 */ 315static inline __attribute__ ((const)) int fls(unsigned long x) 316{ 317 if (__builtin_constant_p(x)) 318 return constant_fls(x); 319 320 return 32 - clz(x); 321} 322 323/* 324 * __fls: Similar to fls, but zero based (0-31) 325 */ 326static inline __attribute__ ((const)) int __fls(unsigned long x) 327{ 328 if (!x) 329 return 0; 330 else 331 return fls(x) - 1; 332} 333 334/* 335 * ffs = Find First Set in word (LSB to MSB) 336 * @result: [1-32], 0 if all 0's 337 */ 338#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) 339 340/* 341 * __ffs: Similar to ffs, but zero based (0-31) 342 */ 343static inline __attribute__ ((const)) int __ffs(unsigned long word) 344{ 345 if (!word) 346 return word; 347 348 return ffs(word) - 1; 349} 350 351#else /* CONFIG_ISA_ARCV2 */ 352 353/* 354 * fls = Find Last Set in word 355 * @result: [1-32] 356 * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0 357 */ 358static inline __attribute__ ((const)) int fls(unsigned long x) 359{ 360 int n; 361 362 asm volatile( 363 " fls.f %0, %1 \n" /* 0:31; 0(Z) if src 0 */ 364 " add.nz %0, %0, 1 \n" /* 0:31 -> 1:32 */ 365 : "=r"(n) /* Early clobber not needed */ 366 : "r"(x) 367 : "cc"); 368 369 return n; 370} 371 372/* 373 * __fls: Similar to fls, but zero based (0-31). Also 0 if no bit set 374 */ 375static inline __attribute__ ((const)) int __fls(unsigned long x) 376{ 377 /* FLS insn has exactly same semantics as the API */ 378 return __builtin_arc_fls(x); 379} 380 381/* 382 * ffs = Find First Set in word (LSB to MSB) 383 * @result: [1-32], 0 if all 0's 384 */ 385static inline __attribute__ ((const)) int ffs(unsigned long x) 386{ 387 int n; 388 389 asm volatile( 390 " ffs.f %0, %1 \n" /* 0:31; 31(Z) if src 0 */ 391 " add.nz %0, %0, 1 \n" /* 0:31 -> 1:32 */ 392 " mov.z %0, 0 \n" /* 31(Z)-> 0 */ 393 : "=r"(n) /* Early clobber not needed */ 394 : "r"(x) 395 : "cc"); 396 397 return n; 398} 399 400/* 401 * __ffs: Similar to ffs, but zero based (0-31) 402 */ 403static inline __attribute__ ((const)) int __ffs(unsigned long x) 404{ 405 int n; 406 407 asm volatile( 408 " ffs.f %0, %1 \n" /* 0:31; 31(Z) if src 0 */ 409 " mov.z %0, 0 \n" /* 31(Z)-> 0 */ 410 : "=r"(n) 411 : "r"(x) 412 : "cc"); 413 414 return n; 415 416} 417 418#endif /* CONFIG_ISA_ARCOMPACT */ 419 420/* 421 * ffz = Find First Zero in word. 422 * @return:[0-31], 32 if all 1's 423 */ 424#define ffz(x) __ffs(~(x)) 425 426#include <asm-generic/bitops/hweight.h> 427#include <asm-generic/bitops/fls64.h> 428#include <asm-generic/bitops/sched.h> 429#include <asm-generic/bitops/lock.h> 430 431#include <asm-generic/bitops/find.h> 432#include <asm-generic/bitops/le.h> 433#include <asm-generic/bitops/ext2-atomic-setbit.h> 434 435#endif /* !__ASSEMBLY__ */ 436 437#endif