linux/arch/arc/include/asm/bitops.h
<<
>>
Prefs
   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)                                        \
  29static 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)                                 \
  60static 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#else /* !CONFIG_ARC_HAS_LLSC */
  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)                                        \
 107static 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)                                 \
 124static 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#endif
 140
 141/***************************************
 142 * Non atomic variants
 143 **************************************/
 144
 145#define __BIT_OP(op, c_op, asm_op)                                      \
 146static inline void __##op##_bit(unsigned long nr, volatile unsigned long *m)    \
 147{                                                                       \
 148        unsigned long temp;                                             \
 149        m += nr >> 5;                                                   \
 150                                                                        \
 151        temp = *m;                                                      \
 152        *m = temp c_op (1UL << (nr & 0x1f));                            \
 153}
 154
 155#define __TEST_N_BIT_OP(op, c_op, asm_op)                               \
 156static inline int __test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\
 157{                                                                       \
 158        unsigned long old;                                              \
 159        m += nr >> 5;                                                   \
 160                                                                        \
 161        old = *m;                                                       \
 162        *m = old c_op (1UL << (nr & 0x1f));                             \
 163                                                                        \
 164        return (old & (1UL << (nr & 0x1f))) != 0;                       \
 165}
 166
 167#define BIT_OPS(op, c_op, asm_op)                                       \
 168                                                                        \
 169        /* set_bit(), clear_bit(), change_bit() */                      \
 170        BIT_OP(op, c_op, asm_op)                                        \
 171                                                                        \
 172        /* test_and_set_bit(), test_and_clear_bit(), test_and_change_bit() */\
 173        TEST_N_BIT_OP(op, c_op, asm_op)                                 \
 174                                                                        \
 175        /* __set_bit(), __clear_bit(), __change_bit() */                \
 176        __BIT_OP(op, c_op, asm_op)                                      \
 177                                                                        \
 178        /* __test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit() */\
 179        __TEST_N_BIT_OP(op, c_op, asm_op)
 180
 181BIT_OPS(set, |, bset)
 182BIT_OPS(clear, & ~, bclr)
 183BIT_OPS(change, ^, bxor)
 184
 185/*
 186 * This routine doesn't need to be atomic.
 187 */
 188static inline int
 189test_bit(unsigned int nr, const volatile unsigned long *addr)
 190{
 191        unsigned long mask;
 192
 193        addr += nr >> 5;
 194
 195        mask = 1UL << (nr & 0x1f);
 196
 197        return ((mask & *addr) != 0);
 198}
 199
 200#ifdef CONFIG_ISA_ARCOMPACT
 201
 202/*
 203 * Count the number of zeros, starting from MSB
 204 * Helper for fls( ) friends
 205 * This is a pure count, so (1-32) or (0-31) doesn't apply
 206 * It could be 0 to 32, based on num of 0's in there
 207 * clz(0x8000_0000) = 0, clz(0xFFFF_FFFF)=0, clz(0) = 32, clz(1) = 31
 208 */
 209static inline __attribute__ ((const)) int clz(unsigned int x)
 210{
 211        unsigned int res;
 212
 213        __asm__ __volatile__(
 214        "       norm.f  %0, %1          \n"
 215        "       mov.n   %0, 0           \n"
 216        "       add.p   %0, %0, 1       \n"
 217        : "=r"(res)
 218        : "r"(x)
 219        : "cc");
 220
 221        return res;
 222}
 223
 224static inline int constant_fls(unsigned int x)
 225{
 226        int r = 32;
 227
 228        if (!x)
 229                return 0;
 230        if (!(x & 0xffff0000u)) {
 231                x <<= 16;
 232                r -= 16;
 233        }
 234        if (!(x & 0xff000000u)) {
 235                x <<= 8;
 236                r -= 8;
 237        }
 238        if (!(x & 0xf0000000u)) {
 239                x <<= 4;
 240                r -= 4;
 241        }
 242        if (!(x & 0xc0000000u)) {
 243                x <<= 2;
 244                r -= 2;
 245        }
 246        if (!(x & 0x80000000u))
 247                r -= 1;
 248        return r;
 249}
 250
 251/*
 252 * fls = Find Last Set in word
 253 * @result: [1-32]
 254 * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0
 255 */
 256static inline __attribute__ ((const)) int fls(unsigned int x)
 257{
 258        if (__builtin_constant_p(x))
 259               return constant_fls(x);
 260
 261        return 32 - clz(x);
 262}
 263
 264/*
 265 * __fls: Similar to fls, but zero based (0-31)
 266 */
 267static inline __attribute__ ((const)) int __fls(unsigned long x)
 268{
 269        if (!x)
 270                return 0;
 271        else
 272                return fls(x) - 1;
 273}
 274
 275/*
 276 * ffs = Find First Set in word (LSB to MSB)
 277 * @result: [1-32], 0 if all 0's
 278 */
 279#define ffs(x)  ({ unsigned long __t = (x); fls(__t & -__t); })
 280
 281/*
 282 * __ffs: Similar to ffs, but zero based (0-31)
 283 */
 284static inline __attribute__ ((const)) unsigned long __ffs(unsigned long word)
 285{
 286        if (!word)
 287                return word;
 288
 289        return ffs(word) - 1;
 290}
 291
 292#else   /* CONFIG_ISA_ARCV2 */
 293
 294/*
 295 * fls = Find Last Set in word
 296 * @result: [1-32]
 297 * fls(1) = 1, fls(0x80000000) = 32, fls(0) = 0
 298 */
 299static inline __attribute__ ((const)) int fls(unsigned long x)
 300{
 301        int n;
 302
 303        asm volatile(
 304        "       fls.f   %0, %1          \n"  /* 0:31; 0(Z) if src 0 */
 305        "       add.nz  %0, %0, 1       \n"  /* 0:31 -> 1:32 */
 306        : "=r"(n)       /* Early clobber not needed */
 307        : "r"(x)
 308        : "cc");
 309
 310        return n;
 311}
 312
 313/*
 314 * __fls: Similar to fls, but zero based (0-31). Also 0 if no bit set
 315 */
 316static inline __attribute__ ((const)) int __fls(unsigned long x)
 317{
 318        /* FLS insn has exactly same semantics as the API */
 319        return  __builtin_arc_fls(x);
 320}
 321
 322/*
 323 * ffs = Find First Set in word (LSB to MSB)
 324 * @result: [1-32], 0 if all 0's
 325 */
 326static inline __attribute__ ((const)) int ffs(unsigned long x)
 327{
 328        int n;
 329
 330        asm volatile(
 331        "       ffs.f   %0, %1          \n"  /* 0:31; 31(Z) if src 0 */
 332        "       add.nz  %0, %0, 1       \n"  /* 0:31 -> 1:32 */
 333        "       mov.z   %0, 0           \n"  /* 31(Z)-> 0 */
 334        : "=r"(n)       /* Early clobber not needed */
 335        : "r"(x)
 336        : "cc");
 337
 338        return n;
 339}
 340
 341/*
 342 * __ffs: Similar to ffs, but zero based (0-31)
 343 */
 344static inline __attribute__ ((const)) unsigned long __ffs(unsigned long x)
 345{
 346        unsigned long n;
 347
 348        asm volatile(
 349        "       ffs.f   %0, %1          \n"  /* 0:31; 31(Z) if src 0 */
 350        "       mov.z   %0, 0           \n"  /* 31(Z)-> 0 */
 351        : "=r"(n)
 352        : "r"(x)
 353        : "cc");
 354
 355        return n;
 356
 357}
 358
 359#endif  /* CONFIG_ISA_ARCOMPACT */
 360
 361/*
 362 * ffz = Find First Zero in word.
 363 * @return:[0-31], 32 if all 1's
 364 */
 365#define ffz(x)  __ffs(~(x))
 366
 367#include <asm-generic/bitops/hweight.h>
 368#include <asm-generic/bitops/fls64.h>
 369#include <asm-generic/bitops/sched.h>
 370#include <asm-generic/bitops/lock.h>
 371
 372#include <asm-generic/bitops/find.h>
 373#include <asm-generic/bitops/le.h>
 374#include <asm-generic/bitops/ext2-atomic-setbit.h>
 375
 376#endif /* !__ASSEMBLY__ */
 377
 378#endif
 379