forked from Mirrors/opensbi
		
	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:
		@@ -30,6 +30,7 @@
 | 
			
		||||
#define LGREG		__REG_SEL(3, 2)
 | 
			
		||||
 | 
			
		||||
#if __SIZEOF_POINTER__ == 8
 | 
			
		||||
#define BITS_PER_LONG		64
 | 
			
		||||
#ifdef __ASSEMBLY__
 | 
			
		||||
#define RISCV_PTR		.dword
 | 
			
		||||
#define RISCV_SZPTR		8
 | 
			
		||||
@@ -40,6 +41,7 @@
 | 
			
		||||
#define RISCV_LGPTR		"3"
 | 
			
		||||
#endif
 | 
			
		||||
#elif __SIZEOF_POINTER__ == 4
 | 
			
		||||
#define BITS_PER_LONG		32
 | 
			
		||||
#ifdef __ASSEMBLY__
 | 
			
		||||
#define RISCV_PTR		.word
 | 
			
		||||
#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 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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 XSTR(x) #x
 | 
			
		||||
 | 
			
		||||
#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
 | 
			
		||||
#define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,10 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sbi/sbi_types.h>
 | 
			
		||||
#include <sbi/riscv_asm.h>
 | 
			
		||||
#include <sbi/riscv_atomic.h>
 | 
			
		||||
#include <sbi/riscv_barrier.h>
 | 
			
		||||
#include <sbi/sbi_bits.h>
 | 
			
		||||
 | 
			
		||||
long atomic_read(atomic_t *atom)
 | 
			
		||||
{
 | 
			
		||||
@@ -174,3 +176,50 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr,
 | 
			
		||||
	return xchg(ptr, newval);
 | 
			
		||||
#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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user