linux/arch/riscv/include/asm/bitops.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * Copyright (C) 2012 Regents of the University of California
   4 */
   5
   6#ifndef _ASM_RISCV_BITOPS_H
   7#define _ASM_RISCV_BITOPS_H
   8
   9#ifndef _LINUX_BITOPS_H
  10#error "Only <linux/bitops.h> can be included directly"
  11#endif /* _LINUX_BITOPS_H */
  12
  13#include <linux/compiler.h>
  14#include <linux/irqflags.h>
  15#include <asm/barrier.h>
  16#include <asm/bitsperlong.h>
  17
  18#include <asm-generic/bitops/__ffs.h>
  19#include <asm-generic/bitops/ffz.h>
  20#include <asm-generic/bitops/fls.h>
  21#include <asm-generic/bitops/__fls.h>
  22#include <asm-generic/bitops/fls64.h>
  23#include <asm-generic/bitops/find.h>
  24#include <asm-generic/bitops/sched.h>
  25#include <asm-generic/bitops/ffs.h>
  26
  27#include <asm-generic/bitops/hweight.h>
  28
  29#if (BITS_PER_LONG == 64)
  30#define __AMO(op)       "amo" #op ".d"
  31#elif (BITS_PER_LONG == 32)
  32#define __AMO(op)       "amo" #op ".w"
  33#else
  34#error "Unexpected BITS_PER_LONG"
  35#endif
  36
  37#define __test_and_op_bit_ord(op, mod, nr, addr, ord)           \
  38({                                                              \
  39        unsigned long __res, __mask;                            \
  40        __mask = BIT_MASK(nr);                                  \
  41        __asm__ __volatile__ (                                  \
  42                __AMO(op) #ord " %0, %2, %1"                    \
  43                : "=r" (__res), "+A" (addr[BIT_WORD(nr)])       \
  44                : "r" (mod(__mask))                             \
  45                : "memory");                                    \
  46        ((__res & __mask) != 0);                                \
  47})
  48
  49#define __op_bit_ord(op, mod, nr, addr, ord)                    \
  50        __asm__ __volatile__ (                                  \
  51                __AMO(op) #ord " zero, %1, %0"                  \
  52                : "+A" (addr[BIT_WORD(nr)])                     \
  53                : "r" (mod(BIT_MASK(nr)))                       \
  54                : "memory");
  55
  56#define __test_and_op_bit(op, mod, nr, addr)                    \
  57        __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
  58#define __op_bit(op, mod, nr, addr)                             \
  59        __op_bit_ord(op, mod, nr, addr, )
  60
  61/* Bitmask modifiers */
  62#define __NOP(x)        (x)
  63#define __NOT(x)        (~(x))
  64
  65/**
  66 * test_and_set_bit - Set a bit and return its old value
  67 * @nr: Bit to set
  68 * @addr: Address to count from
  69 *
  70 * This operation may be reordered on other architectures than x86.
  71 */
  72static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
  73{
  74        return __test_and_op_bit(or, __NOP, nr, addr);
  75}
  76
  77/**
  78 * test_and_clear_bit - Clear a bit and return its old value
  79 * @nr: Bit to clear
  80 * @addr: Address to count from
  81 *
  82 * This operation can be reordered on other architectures other than x86.
  83 */
  84static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
  85{
  86        return __test_and_op_bit(and, __NOT, nr, addr);
  87}
  88
  89/**
  90 * test_and_change_bit - Change a bit and return its old value
  91 * @nr: Bit to change
  92 * @addr: Address to count from
  93 *
  94 * This operation is atomic and cannot be reordered.
  95 * It also implies a memory barrier.
  96 */
  97static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
  98{
  99        return __test_and_op_bit(xor, __NOP, nr, addr);
 100}
 101
 102/**
 103 * set_bit - Atomically set a bit in memory
 104 * @nr: the bit to set
 105 * @addr: the address to start counting from
 106 *
 107 * Note: there are no guarantees that this function will not be reordered
 108 * on non x86 architectures, so if you are writing portable code,
 109 * make sure not to rely on its reordering guarantees.
 110 *
 111 * Note that @nr may be almost arbitrarily large; this function is not
 112 * restricted to acting on a single-word quantity.
 113 */
 114static inline void set_bit(int nr, volatile unsigned long *addr)
 115{
 116        __op_bit(or, __NOP, nr, addr);
 117}
 118
 119/**
 120 * clear_bit - Clears a bit in memory
 121 * @nr: Bit to clear
 122 * @addr: Address to start counting from
 123 *
 124 * Note: there are no guarantees that this function will not be reordered
 125 * on non x86 architectures, so if you are writing portable code,
 126 * make sure not to rely on its reordering guarantees.
 127 */
 128static inline void clear_bit(int nr, volatile unsigned long *addr)
 129{
 130        __op_bit(and, __NOT, nr, addr);
 131}
 132
 133/**
 134 * change_bit - Toggle a bit in memory
 135 * @nr: Bit to change
 136 * @addr: Address to start counting from
 137 *
 138 * change_bit()  may be reordered on other architectures than x86.
 139 * Note that @nr may be almost arbitrarily large; this function is not
 140 * restricted to acting on a single-word quantity.
 141 */
 142static inline void change_bit(int nr, volatile unsigned long *addr)
 143{
 144        __op_bit(xor, __NOP, nr, addr);
 145}
 146
 147/**
 148 * test_and_set_bit_lock - Set a bit and return its old value, for lock
 149 * @nr: Bit to set
 150 * @addr: Address to count from
 151 *
 152 * This operation is atomic and provides acquire barrier semantics.
 153 * It can be used to implement bit locks.
 154 */
 155static inline int test_and_set_bit_lock(
 156        unsigned long nr, volatile unsigned long *addr)
 157{
 158        return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq);
 159}
 160
 161/**
 162 * clear_bit_unlock - Clear a bit in memory, for unlock
 163 * @nr: the bit to set
 164 * @addr: the address to start counting from
 165 *
 166 * This operation is atomic and provides release barrier semantics.
 167 */
 168static inline void clear_bit_unlock(
 169        unsigned long nr, volatile unsigned long *addr)
 170{
 171        __op_bit_ord(and, __NOT, nr, addr, .rl);
 172}
 173
 174/**
 175 * __clear_bit_unlock - Clear a bit in memory, for unlock
 176 * @nr: the bit to set
 177 * @addr: the address to start counting from
 178 *
 179 * This operation is like clear_bit_unlock, however it is not atomic.
 180 * It does provide release barrier semantics so it can be used to unlock
 181 * a bit lock, however it would only be used if no other CPU can modify
 182 * any bits in the memory until the lock is released (a good example is
 183 * if the bit lock itself protects access to the other bits in the word).
 184 *
 185 * On RISC-V systems there seems to be no benefit to taking advantage of the
 186 * non-atomic property here: it's a lot more instructions and we still have to
 187 * provide release semantics anyway.
 188 */
 189static inline void __clear_bit_unlock(
 190        unsigned long nr, volatile unsigned long *addr)
 191{
 192        clear_bit_unlock(nr, addr);
 193}
 194
 195#undef __test_and_op_bit
 196#undef __op_bit
 197#undef __NOP
 198#undef __NOT
 199#undef __AMO
 200
 201#include <asm-generic/bitops/non-atomic.h>
 202#include <asm-generic/bitops/le.h>
 203#include <asm-generic/bitops/ext2-atomic.h>
 204
 205#endif /* _ASM_RISCV_BITOPS_H */
 206