/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( c ) 1994 - 1997 , 99 , 2000 , 06 , 07 Ralf Baechle ( ralf @ linux - mips . org )
* Copyright ( c ) 1999 , 2000 Silicon Graphics , Inc .
*/
#ifndef _ASM_BITOPS_H
#define _ASM_BITOPS_H
#ifndef _LINUX_BITOPS_H
#error only <linux/bitops.h> can be included directly
#endif
#include <linux/bits.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <asm /asm .h>
#include <asm /barrier.h>
#include <asm /byteorder.h> /* sigh ... */
#include <asm /compiler.h>
#include <asm /cpu-features.h>
#include <asm /sgidefs.h>
#define __bit_op(mem, insn, inputs...) do { \
unsigned long __temp; \
\
asm volatile ( \
" .set push \n" \
" .set " MIPS_ISA_LEVEL " \n" \
" " __SYNC(full, loongson3_war) " \n" \
"1: " __stringify(LONG_LL) " %0, %1 \n" \
" " insn " \n" \
" " __stringify(LONG_SC) " %0, %1 \n" \
" " __stringify(SC_BEQZ) " %0, 1b \n" \
" .set pop \n" \
: "=&r" (__temp), "+" GCC_OFF_SMALL_ASM()(mem) \
: inputs \
: __LLSC_CLOBBER); \
} while (0 )
#define __test_bit_op(mem, ll_dst, insn, inputs...) ({ \
unsigned long __orig, __temp; \
\
asm volatile ( \
" .set push \n" \
" .set " MIPS_ISA_LEVEL " \n" \
" " __SYNC(full, loongson3_war) " \n" \
"1: " __stringify(LONG_LL) " " ll_dst ", %2\n" \
" " insn " \n" \
" " __stringify(LONG_SC) " %1, %2 \n" \
" " __stringify(SC_BEQZ) " %1, 1b \n" \
" .set pop \n" \
: "=&r" (__orig), "=&r" (__temp), \
"+" GCC_OFF_SMALL_ASM()(mem) \
: inputs \
: __LLSC_CLOBBER); \
\
__orig; \
})
/*
* These are the " slower " versions of the functions and are in bitops . c .
* These functions call raw_local_irq_ { save , restore } ( ) .
*/
void __mips_set_bit(unsigned long nr, volatile unsigned long *addr);
void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr);
void __mips_change_bit(unsigned long nr, volatile unsigned long *addr);
int __mips_test_and_set_bit_lock(unsigned long nr,
volatile unsigned long *addr);
int __mips_test_and_clear_bit(unsigned long nr,
volatile unsigned long *addr);
int __mips_test_and_change_bit(unsigned long nr,
volatile unsigned long *addr);
bool __mips_xor_is_negative_byte(unsigned long mask,
volatile unsigned long *addr);
/*
* set_bit - Atomically set a bit in memory
* @ nr : the bit to set
* @ addr : the address to start counting from
*
* This function is atomic and may not be reordered . See _ _ set_bit ( )
* if you do not require the atomic guarantees .
* Note that @ nr may be almost arbitrarily large ; this function is not
* restricted to acting on a single - word quantity .
*/
static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
{
volatile unsigned long *m = &addr[BIT_WORD(nr)];
int bit = nr % BITS_PER_LONG;
if (!kernel_uses_llsc) {
__mips_set_bit(nr, addr);
return ;
}
if ((MIPS_ISA_REV >= 2 ) && __builtin_constant_p(bit) && (bit >= 16 )) {
__bit_op(*m, __stringify(LONG_INS) " %0, %3, %2, 1" , "i" (bit), "r" (~0 ));
return ;
}
__bit_op(*m, "or\t%0, %2" , "ir" (BIT(bit)));
}
/*
* clear_bit - Clears a bit in memory
* @ nr : Bit to clear
* @ addr : Address to start counting from
*
* clear_bit ( ) is atomic and may not be reordered . However , it does
* not contain a memory barrier , so if it is used for locking purposes ,
* you should call smp_mb__before_atomic ( ) and / or smp_mb__after_atomic ( )
* in order to ensure changes are visible on other processors .
*/
static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
{
volatile unsigned long *m = &addr[BIT_WORD(nr)];
int bit = nr % BITS_PER_LONG;
if (!kernel_uses_llsc) {
__mips_clear_bit(nr, addr);
return ;
}
if ((MIPS_ISA_REV >= 2 ) && __builtin_constant_p(bit)) {
__bit_op(*m, __stringify(LONG_INS) " %0, $0, %2, 1" , "i" (bit));
return ;
}
__bit_op(*m, "and\t%0, %2" , "ir" (~BIT(bit)));
}
/*
* clear_bit_unlock - Clears a bit in memory
* @ nr : Bit to clear
* @ addr : Address to start counting from
*
* clear_bit ( ) is atomic and implies release semantics before the memory
* operation . It can be used for an unlock .
*/
static inline void clear_bit_unlock(unsigned long nr, volatile unsigned long *addr)
{
smp_mb__before_atomic();
clear_bit(nr, addr);
}
/*
* change_bit - Toggle a bit in memory
* @ nr : Bit to change
* @ addr : Address to start counting from
*
* change_bit ( ) is atomic and may not be reordered .
* Note that @ nr may be almost arbitrarily large ; this function is not
* restricted to acting on a single - word quantity .
*/
static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
{
volatile unsigned long *m = &addr[BIT_WORD(nr)];
int bit = nr % BITS_PER_LONG;
if (!kernel_uses_llsc) {
__mips_change_bit(nr, addr);
return ;
}
__bit_op(*m, "xor\t%0, %2" , "ir" (BIT(bit)));
}
/*
* test_and_set_bit_lock - Set a bit and return its old value
* @ nr : Bit to set
* @ addr : Address to count from
*
* This operation is atomic and implies acquire ordering semantics
* after the memory operation .
*/
static inline int test_and_set_bit_lock(unsigned long nr,
volatile unsigned long *addr)
{
volatile unsigned long *m = &addr[BIT_WORD(nr)];
int bit = nr % BITS_PER_LONG;
unsigned long res, orig;
if (!kernel_uses_llsc) {
res = __mips_test_and_set_bit_lock(nr, addr);
} else {
orig = __test_bit_op(*m, "%0" ,
"or\t%1, %0, %3" ,
"ir" (BIT(bit)));
res = (orig & BIT(bit)) != 0 ;
}
smp_llsc_mb();
return res;
}
/*
* test_and_set_bit - Set a bit and return its old value
* @ nr : Bit to set
* @ addr : Address to count from
*
* This operation is atomic and cannot be reordered .
* It also implies a memory barrier .
*/
static inline int test_and_set_bit(unsigned long nr,
volatile unsigned long *addr)
{
smp_mb__before_atomic();
return test_and_set_bit_lock(nr, addr);
}
/*
* test_and_clear_bit - Clear a bit and return its old value
* @ nr : Bit to clear
* @ addr : Address to count from
*
* This operation is atomic and cannot be reordered .
* It also implies a memory barrier .
*/
static inline int test_and_clear_bit(unsigned long nr,
volatile unsigned long *addr)
{
volatile unsigned long *m = &addr[BIT_WORD(nr)];
int bit = nr % BITS_PER_LONG;
unsigned long res, orig;
smp_mb__before_atomic();
if (!kernel_uses_llsc) {
res = __mips_test_and_clear_bit(nr, addr);
} else if ((MIPS_ISA_REV >= 2 ) && __builtin_constant_p(nr)) {
res = __test_bit_op(*m, "%1" ,
__stringify(LONG_EXT) " %0, %1, %3, 1;"
__stringify(LONG_INS) " %1, $0, %3, 1" ,
"i" (bit));
} else {
orig = __test_bit_op(*m, "%0" ,
"or\t%1, %0, %3;"
"xor\t%1, %1, %3" ,
"ir" (BIT(bit)));
res = (orig & BIT(bit)) != 0 ;
}
smp_llsc_mb();
return res;
}
/*
* test_and_change_bit - Change a bit and return its old value
* @ nr : Bit to change
* @ addr : Address to count from
*
* This operation is atomic and cannot be reordered .
* It also implies a memory barrier .
*/
static inline int test_and_change_bit(unsigned long nr,
volatile unsigned long *addr)
{
volatile unsigned long *m = &addr[BIT_WORD(nr)];
int bit = nr % BITS_PER_LONG;
unsigned long res, orig;
smp_mb__before_atomic();
if (!kernel_uses_llsc) {
res = __mips_test_and_change_bit(nr, addr);
} else {
orig = __test_bit_op(*m, "%0" ,
"xor\t%1, %0, %3" ,
"ir" (BIT(bit)));
res = (orig & BIT(bit)) != 0 ;
}
smp_llsc_mb();
return res;
}
static inline bool xor_unlock_is_negative_byte(unsigned long mask,
volatile unsigned long *p)
{
unsigned long orig;
bool res;
smp_mb__before_atomic();
if (!kernel_uses_llsc) {
res = __mips_xor_is_negative_byte(mask, p);
} else {
orig = __test_bit_op(*p, "%0" ,
"xor\t%1, %0, %3" ,
"ir" (mask));
res = (orig & BIT(7 )) != 0 ;
}
smp_llsc_mb();
return res;
}
#undef __bit_op
#undef __test_bit_op
#include <asm -generic/bitops/non-atomic.h>
/*
* _ _ clear_bit_unlock - Clears a bit in memory
* @ nr : Bit to clear
* @ addr : Address to start counting from
*
* _ _ clear_bit ( ) is non - atomic and implies release semantics before the memory
* operation . It can be used for an unlock if no other CPUs can concurrently
* modify other bits in the word .
*/
static inline void __clear_bit_unlock(unsigned long nr, volatile unsigned long *addr)
{
smp_mb__before_llsc();
__clear_bit(nr, addr);
nudge_writes();
}
/*
* Return the bit position ( 0 . . 63 ) of the most significant 1 bit in a word
* Returns - 1 if no 1 bit exists
*/
static __always_inline unsigned long __fls(unsigned long word)
{
int num;
if (BITS_PER_LONG == 32 && !__builtin_constant_p(word) &&
__builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
__asm__(
" .set push \n"
" .set " MIPS_ISA_LEVEL" \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (num)
: "r" (word));
return 31 - num;
}
if (BITS_PER_LONG == 64 && !__builtin_constant_p(word) &&
__builtin_constant_p(cpu_has_mips64) && cpu_has_mips64) {
__asm__(
" .set push \n"
" .set " MIPS_ISA_LEVEL" \n"
" dclz %0, %1 \n"
" .set pop \n"
: "=r" (num)
: "r" (word));
return 63 - num;
}
num = BITS_PER_LONG - 1 ;
#if BITS_PER_LONG == 64
if (!(word & (~0 ul << 32 ))) {
num -= 32 ;
word <<= 32 ;
}
#endif
if (!(word & (~0 ul << (BITS_PER_LONG-16 )))) {
num -= 16 ;
word <<= 16 ;
}
if (!(word & (~0 ul << (BITS_PER_LONG-8 )))) {
num -= 8 ;
word <<= 8 ;
}
if (!(word & (~0 ul << (BITS_PER_LONG-4 )))) {
num -= 4 ;
word <<= 4 ;
}
if (!(word & (~0 ul << (BITS_PER_LONG-2 )))) {
num -= 2 ;
word <<= 2 ;
}
if (!(word & (~0 ul << (BITS_PER_LONG-1 ))))
num -= 1 ;
return num;
}
/*
* _ _ ffs - find first bit in word .
* @ word : The word to search
*
* Returns 0 . . SZLONG - 1
* Undefined if no bit exists , so code should check against 0 first .
*/
static __always_inline unsigned long __ffs(unsigned long word)
{
return __fls(word & -word);
}
/*
* fls - find last bit set .
* @ word : The word to search
*
* This is defined the same way as ffs .
* Note fls ( 0 ) = 0 , fls ( 1 ) = 1 , fls ( 0 x80000000 ) = 32 .
*/
static inline int fls(unsigned int x)
{
int r;
if (!__builtin_constant_p(x) &&
__builtin_constant_p(cpu_has_clo_clz) && cpu_has_clo_clz) {
__asm__(
" .set push \n"
" .set " MIPS_ISA_LEVEL" \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
: "r" (x));
return 32 - x;
}
r = 32 ;
if (!x)
return 0 ;
if (!(x & 0 xffff0000u)) {
x <<= 16 ;
r -= 16 ;
}
if (!(x & 0 xff000000u)) {
x <<= 8 ;
r -= 8 ;
}
if (!(x & 0 xf0000000u)) {
x <<= 4 ;
r -= 4 ;
}
if (!(x & 0 xc0000000u)) {
x <<= 2 ;
r -= 2 ;
}
if (!(x & 0 x80000000u)) {
x <<= 1 ;
r -= 1 ;
}
return r;
}
#include <asm -generic/bitops/fls64.h>
/*
* ffs - find first bit set .
* @ word : The word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines , therefore
* differs in spirit from the below ffz ( man ffs ) .
*/
static inline int ffs(int word)
{
if (!word)
return 0 ;
return fls(word & -word);
}
#include <asm -generic/bitops/ffz.h>
#ifdef __KERNEL__
#include <asm -generic/bitops/sched.h>
#include <asm /arch_hweight.h>
#include <asm -generic/bitops/const_hweight.h>
#include <asm -generic/bitops/le.h>
#include <asm -generic/bitops/ext2-atomic.h>
#endif /* __KERNEL__ */
#endif /* _ASM_BITOPS_H */
Messung V0.5 in Prozent C=83 H=91 G=86
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland