mirror of
https://github.com/Fishwaldo/opensbi.git
synced 2025-06-28 09:08:24 +00:00
lib: Add atomic bit set/clear operations.
Add addtional functionlities for set/clear bits atomically. Signed-off-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
parent
784a4657c0
commit
312b6bf32f
5 changed files with 179 additions and 0 deletions
|
@ -30,6 +30,7 @@
|
||||||
#define LGREG __REG_SEL(3, 2)
|
#define LGREG __REG_SEL(3, 2)
|
||||||
|
|
||||||
#if __SIZEOF_POINTER__ == 8
|
#if __SIZEOF_POINTER__ == 8
|
||||||
|
#define BITS_PER_LONG 64
|
||||||
#ifdef __ASSEMBLY__
|
#ifdef __ASSEMBLY__
|
||||||
#define RISCV_PTR .dword
|
#define RISCV_PTR .dword
|
||||||
#define RISCV_SZPTR 8
|
#define RISCV_SZPTR 8
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
#define RISCV_LGPTR "3"
|
#define RISCV_LGPTR "3"
|
||||||
#endif
|
#endif
|
||||||
#elif __SIZEOF_POINTER__ == 4
|
#elif __SIZEOF_POINTER__ == 4
|
||||||
|
#define BITS_PER_LONG 32
|
||||||
#ifdef __ASSEMBLY__
|
#ifdef __ASSEMBLY__
|
||||||
#define RISCV_PTR .word
|
#define RISCV_PTR .word
|
||||||
#define RISCV_SZPTR 4
|
#define RISCV_SZPTR 4
|
||||||
|
|
|
@ -34,5 +34,33 @@ long arch_atomic_xchg(atomic_t *atom, long newval);
|
||||||
|
|
||||||
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||||
unsigned int newval);
|
unsigned int newval);
|
||||||
|
/**
|
||||||
|
* Set a bit in an atomic variable and return the new value.
|
||||||
|
* @nr : Bit to set.
|
||||||
|
* @atom: atomic variable to modify
|
||||||
|
*/
|
||||||
|
int atomic_set_bit(int nr, atomic_t *atom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear a bit in an atomic variable and return the new value.
|
||||||
|
* @nr : Bit to set.
|
||||||
|
* @atom: atomic variable to modify
|
||||||
|
*/
|
||||||
|
|
||||||
|
int atomic_clear_bit(int nr, atomic_t *atom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a bit in any address and return the new value .
|
||||||
|
* @nr : Bit to set.
|
||||||
|
* @addr: Address to modify
|
||||||
|
*/
|
||||||
|
int atomic_raw_set_bit(int nr, volatile unsigned long *addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear a bit in any address and return the new value .
|
||||||
|
* @nr : Bit to set.
|
||||||
|
* @addr: Address to modify
|
||||||
|
*/
|
||||||
|
int atomic_raw_clear_bit(int nr, volatile unsigned long *addr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
98
include/sbi/sbi_bitops.h
Normal file
98
include/sbi/sbi_bitops.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Western Digital Corporation or its affiliates.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atish Patra<atish.patra@wdc.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SBI_BITOPS_H__
|
||||||
|
#define __SBI_BITOPS_H__
|
||||||
|
|
||||||
|
#include <sbi/sbi_bits.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ffs - Find first bit set
|
||||||
|
* @x: the word to search
|
||||||
|
*
|
||||||
|
* This is defined the same way as
|
||||||
|
* the libc and compiler builtin ffs routines, therefore
|
||||||
|
* differs in spirit from the above ffz (man ffs).
|
||||||
|
*/
|
||||||
|
static inline int ffs(int x)
|
||||||
|
{
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if (!x)
|
||||||
|
return 0;
|
||||||
|
if (!(x & 0xffff)) {
|
||||||
|
x >>= 16;
|
||||||
|
r += 16;
|
||||||
|
}
|
||||||
|
if (!(x & 0xff)) {
|
||||||
|
x >>= 8;
|
||||||
|
r += 8;
|
||||||
|
}
|
||||||
|
if (!(x & 0xf)) {
|
||||||
|
x >>= 4;
|
||||||
|
r += 4;
|
||||||
|
}
|
||||||
|
if (!(x & 3)) {
|
||||||
|
x >>= 2;
|
||||||
|
r += 2;
|
||||||
|
}
|
||||||
|
if (!(x & 1)) {
|
||||||
|
x >>= 1;
|
||||||
|
r += 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __ffs - find first bit in word.
|
||||||
|
* @word: The word to search
|
||||||
|
*
|
||||||
|
* Undefined if no bit exists, so code should check against 0 first.
|
||||||
|
*/
|
||||||
|
static inline int __ffs(unsigned long word)
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
#if BITS_PER_LONG == 64
|
||||||
|
if ((word & 0xffffffff) == 0) {
|
||||||
|
num += 32;
|
||||||
|
word >>= 32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ((word & 0xffff) == 0) {
|
||||||
|
num += 16;
|
||||||
|
word >>= 16;
|
||||||
|
}
|
||||||
|
if ((word & 0xff) == 0) {
|
||||||
|
num += 8;
|
||||||
|
word >>= 8;
|
||||||
|
}
|
||||||
|
if ((word & 0xf) == 0) {
|
||||||
|
num += 4;
|
||||||
|
word >>= 4;
|
||||||
|
}
|
||||||
|
if ((word & 0x3) == 0) {
|
||||||
|
num += 2;
|
||||||
|
word >>= 2;
|
||||||
|
}
|
||||||
|
if ((word & 0x1) == 0)
|
||||||
|
num += 1;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ffz - find first zero in word.
|
||||||
|
* @word: The word to search
|
||||||
|
*
|
||||||
|
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||||
|
*/
|
||||||
|
#define ffz(x) __ffs(~(x))
|
||||||
|
|
||||||
|
#endif
|
|
@ -26,4 +26,6 @@
|
||||||
#define STR(x) XSTR(x)
|
#define STR(x) XSTR(x)
|
||||||
#define XSTR(x) #x
|
#define XSTR(x) #x
|
||||||
|
|
||||||
|
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
|
||||||
|
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sbi/sbi_types.h>
|
#include <sbi/sbi_types.h>
|
||||||
|
#include <sbi/riscv_asm.h>
|
||||||
#include <sbi/riscv_atomic.h>
|
#include <sbi/riscv_atomic.h>
|
||||||
#include <sbi/riscv_barrier.h>
|
#include <sbi/riscv_barrier.h>
|
||||||
|
#include <sbi/sbi_bits.h>
|
||||||
|
|
||||||
long atomic_read(atomic_t *atom)
|
long atomic_read(atomic_t *atom)
|
||||||
{
|
{
|
||||||
|
@ -174,3 +176,50 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
|
||||||
return xchg(ptr, newval);
|
return xchg(ptr, newval);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (BITS_PER_LONG == 64)
|
||||||
|
#define __AMO(op) "amo" #op ".d"
|
||||||
|
#elif (BITS_PER_LONG == 32)
|
||||||
|
#define __AMO(op) "amo" #op ".w"
|
||||||
|
#else
|
||||||
|
#error "Unexpected BITS_PER_LONG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __atomic_op_bit_ord(op, mod, nr, addr, ord) \
|
||||||
|
({ \
|
||||||
|
unsigned long __res, __mask; \
|
||||||
|
__mask = BIT_MASK(nr); \
|
||||||
|
__asm__ __volatile__ ( \
|
||||||
|
__AMO(op) #ord " %0, %2, %1" \
|
||||||
|
: "=r" (__res), "+A" (addr[BIT_WORD(nr)]) \
|
||||||
|
: "r" (mod(__mask)) \
|
||||||
|
: "memory"); \
|
||||||
|
__res; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define __atomic_op_bit(op, mod, nr, addr) \
|
||||||
|
__atomic_op_bit_ord(op, mod, nr, addr, .aqrl)
|
||||||
|
|
||||||
|
/* Bitmask modifiers */
|
||||||
|
#define __NOP(x) (x)
|
||||||
|
#define __NOT(x) (~(x))
|
||||||
|
|
||||||
|
inline int atomic_raw_set_bit(int nr, volatile unsigned long *addr)
|
||||||
|
{
|
||||||
|
return __atomic_op_bit(or, __NOP, nr, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int atomic_raw_clear_bit(int nr, volatile unsigned long *addr)
|
||||||
|
{
|
||||||
|
return __atomic_op_bit(and, __NOT, nr, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int atomic_set_bit(int nr, atomic_t *atom)
|
||||||
|
{
|
||||||
|
return atomic_raw_set_bit(nr, (unsigned long *)&atom->counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int atomic_clear_bit(int nr, atomic_t *atom)
|
||||||
|
{
|
||||||
|
return atomic_raw_clear_bit(nr, (unsigned long *)&atom->counter);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue