root/arch/arc/include/asm/bitops.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. BIT_OPS
  2. clz
  3. constant_fls
  4. fls
  5. __fls
  6. __ffs
  7. fls
  8. __fls
  9. ffs
  10. __ffs

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

/* [<][>][^][v][top][bottom][index][help] */