/* * 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
/* * 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(unsignedlong nr, volatileunsignedlong *addr); void __mips_clear_bit(unsignedlong nr, volatileunsignedlong *addr); void __mips_change_bit(unsignedlong nr, volatileunsignedlong *addr); int __mips_test_and_set_bit_lock(unsignedlong nr, volatileunsignedlong *addr); int __mips_test_and_clear_bit(unsignedlong nr, volatileunsignedlong *addr); int __mips_test_and_change_bit(unsignedlong nr, volatileunsignedlong *addr); bool __mips_xor_is_negative_byte(unsignedlong mask, volatileunsignedlong *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.
*/ staticinlinevoid set_bit(unsignedlong nr, volatileunsignedlong *addr)
{ volatileunsignedlong *m = &addr[BIT_WORD(nr)]; int bit = nr % BITS_PER_LONG;
if (!kernel_uses_llsc) {
__mips_set_bit(nr, addr); return;
}
/* * 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.
*/ staticinlinevoid clear_bit(unsignedlong nr, volatileunsignedlong *addr)
{ volatileunsignedlong *m = &addr[BIT_WORD(nr)]; int bit = nr % BITS_PER_LONG;
if (!kernel_uses_llsc) {
__mips_clear_bit(nr, addr); return;
}
/* * 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.
*/ staticinlinevoid clear_bit_unlock(unsignedlong nr, volatileunsignedlong *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.
*/ staticinlinevoid change_bit(unsignedlong nr, volatileunsignedlong *addr)
{ volatileunsignedlong *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.
*/ staticinlineint test_and_set_bit_lock(unsignedlong nr, volatileunsignedlong *addr)
{ volatileunsignedlong *m = &addr[BIT_WORD(nr)]; int bit = nr % BITS_PER_LONG; unsignedlong 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.
*/ staticinlineint test_and_set_bit(unsignedlong nr, volatileunsignedlong *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.
*/ staticinlineint test_and_clear_bit(unsignedlong nr, volatileunsignedlong *addr)
{ volatileunsignedlong *m = &addr[BIT_WORD(nr)]; int bit = nr % BITS_PER_LONG; unsignedlong res, orig;
/* * 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.
*/ staticinlineint test_and_change_bit(unsignedlong nr, volatileunsignedlong *addr)
{ volatileunsignedlong *m = &addr[BIT_WORD(nr)]; int bit = nr % BITS_PER_LONG; unsignedlong 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;
}
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.
*/ staticinlinevoid __clear_bit_unlock(unsignedlong nr, volatileunsignedlong *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 unsignedlong __fls(unsignedlong word)
{ int num;
#if BITS_PER_LONG == 64 if (!(word & (~0ul << 32))) {
num -= 32;
word <<= 32;
} #endif if (!(word & (~0ul << (BITS_PER_LONG-16)))) {
num -= 16;
word <<= 16;
} if (!(word & (~0ul << (BITS_PER_LONG-8)))) {
num -= 8;
word <<= 8;
} if (!(word & (~0ul << (BITS_PER_LONG-4)))) {
num -= 4;
word <<= 4;
} if (!(word & (~0ul << (BITS_PER_LONG-2)))) {
num -= 2;
word <<= 2;
} if (!(word & (~0ul << (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 unsignedlong __ffs(unsignedlong 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(0x80000000) = 32.
*/ staticinlineint fls(unsignedint x)
{ int r;
r = 32; if (!x) return 0; if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
} if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
} if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
} if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
} if (!(x & 0x80000000u)) {
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).
*/ staticinlineint ffs(int word)
{ if (!word) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.