xref: /openbmc/linux/arch/mips/lib/bitops.c (revision c95baf12f5077419db01313ab61c2aac007d40cd)
192d11594SJim Quinlan /*
292d11594SJim Quinlan  * This file is subject to the terms and conditions of the GNU General Public
392d11594SJim Quinlan  * License.  See the file "COPYING" in the main directory of this archive
492d11594SJim Quinlan  * for more details.
592d11594SJim Quinlan  *
692d11594SJim Quinlan  * Copyright (c) 1994-1997, 99, 2000, 06, 07 Ralf Baechle (ralf@linux-mips.org)
792d11594SJim Quinlan  * Copyright (c) 1999, 2000  Silicon Graphics, Inc.
892d11594SJim Quinlan  */
992d11594SJim Quinlan #include <linux/bitops.h>
10*c042be02SPaul Burton #include <linux/bits.h>
1192d11594SJim Quinlan #include <linux/irqflags.h>
1292d11594SJim Quinlan #include <linux/export.h>
1392d11594SJim Quinlan 
1492d11594SJim Quinlan 
1592d11594SJim Quinlan /**
1692d11594SJim Quinlan  * __mips_set_bit - Atomically set a bit in memory.  This is called by
1792d11594SJim Quinlan  * set_bit() if it cannot find a faster solution.
1892d11594SJim Quinlan  * @nr: the bit to set
1992d11594SJim Quinlan  * @addr: the address to start counting from
2092d11594SJim Quinlan  */
__mips_set_bit(unsigned long nr,volatile unsigned long * addr)2192d11594SJim Quinlan void __mips_set_bit(unsigned long nr, volatile unsigned long *addr)
2292d11594SJim Quinlan {
23*c042be02SPaul Burton 	volatile unsigned long *a = &addr[BIT_WORD(nr)];
24*c042be02SPaul Burton 	unsigned int bit = nr % BITS_PER_LONG;
2592d11594SJim Quinlan 	unsigned long mask;
2692d11594SJim Quinlan 	unsigned long flags;
2792d11594SJim Quinlan 
2892d11594SJim Quinlan 	mask = 1UL << bit;
2992d11594SJim Quinlan 	raw_local_irq_save(flags);
3092d11594SJim Quinlan 	*a |= mask;
3192d11594SJim Quinlan 	raw_local_irq_restore(flags);
3292d11594SJim Quinlan }
3392d11594SJim Quinlan EXPORT_SYMBOL(__mips_set_bit);
3492d11594SJim Quinlan 
3592d11594SJim Quinlan 
3692d11594SJim Quinlan /**
3792d11594SJim Quinlan  * __mips_clear_bit - Clears a bit in memory.  This is called by clear_bit() if
3892d11594SJim Quinlan  * it cannot find a faster solution.
3992d11594SJim Quinlan  * @nr: Bit to clear
4092d11594SJim Quinlan  * @addr: Address to start counting from
4192d11594SJim Quinlan  */
__mips_clear_bit(unsigned long nr,volatile unsigned long * addr)4292d11594SJim Quinlan void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr)
4392d11594SJim Quinlan {
44*c042be02SPaul Burton 	volatile unsigned long *a = &addr[BIT_WORD(nr)];
45*c042be02SPaul Burton 	unsigned int bit = nr % BITS_PER_LONG;
4692d11594SJim Quinlan 	unsigned long mask;
4792d11594SJim Quinlan 	unsigned long flags;
4892d11594SJim Quinlan 
4992d11594SJim Quinlan 	mask = 1UL << bit;
5092d11594SJim Quinlan 	raw_local_irq_save(flags);
5192d11594SJim Quinlan 	*a &= ~mask;
5292d11594SJim Quinlan 	raw_local_irq_restore(flags);
5392d11594SJim Quinlan }
5492d11594SJim Quinlan EXPORT_SYMBOL(__mips_clear_bit);
5592d11594SJim Quinlan 
5692d11594SJim Quinlan 
5792d11594SJim Quinlan /**
5892d11594SJim Quinlan  * __mips_change_bit - Toggle a bit in memory.	This is called by change_bit()
5992d11594SJim Quinlan  * if it cannot find a faster solution.
6092d11594SJim Quinlan  * @nr: Bit to change
6192d11594SJim Quinlan  * @addr: Address to start counting from
6292d11594SJim Quinlan  */
__mips_change_bit(unsigned long nr,volatile unsigned long * addr)6392d11594SJim Quinlan void __mips_change_bit(unsigned long nr, volatile unsigned long *addr)
6492d11594SJim Quinlan {
65*c042be02SPaul Burton 	volatile unsigned long *a = &addr[BIT_WORD(nr)];
66*c042be02SPaul Burton 	unsigned int bit = nr % BITS_PER_LONG;
6792d11594SJim Quinlan 	unsigned long mask;
6892d11594SJim Quinlan 	unsigned long flags;
6992d11594SJim Quinlan 
7092d11594SJim Quinlan 	mask = 1UL << bit;
7192d11594SJim Quinlan 	raw_local_irq_save(flags);
7292d11594SJim Quinlan 	*a ^= mask;
7392d11594SJim Quinlan 	raw_local_irq_restore(flags);
7492d11594SJim Quinlan }
7592d11594SJim Quinlan EXPORT_SYMBOL(__mips_change_bit);
7692d11594SJim Quinlan 
7792d11594SJim Quinlan 
7892d11594SJim Quinlan /**
7992d11594SJim Quinlan  * __mips_test_and_set_bit_lock - Set a bit and return its old value.  This is
8092d11594SJim Quinlan  * called by test_and_set_bit_lock() if it cannot find a faster solution.
8192d11594SJim Quinlan  * @nr: Bit to set
8292d11594SJim Quinlan  * @addr: Address to count from
8392d11594SJim Quinlan  */
__mips_test_and_set_bit_lock(unsigned long nr,volatile unsigned long * addr)8492d11594SJim Quinlan int __mips_test_and_set_bit_lock(unsigned long nr,
8592d11594SJim Quinlan 				 volatile unsigned long *addr)
8692d11594SJim Quinlan {
87*c042be02SPaul Burton 	volatile unsigned long *a = &addr[BIT_WORD(nr)];
88*c042be02SPaul Burton 	unsigned int bit = nr % BITS_PER_LONG;
8992d11594SJim Quinlan 	unsigned long mask;
9092d11594SJim Quinlan 	unsigned long flags;
910c81157bSDavid Daney 	int res;
9292d11594SJim Quinlan 
9392d11594SJim Quinlan 	mask = 1UL << bit;
9492d11594SJim Quinlan 	raw_local_irq_save(flags);
950c81157bSDavid Daney 	res = (mask & *a) != 0;
9692d11594SJim Quinlan 	*a |= mask;
9792d11594SJim Quinlan 	raw_local_irq_restore(flags);
9892d11594SJim Quinlan 	return res;
9992d11594SJim Quinlan }
10092d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_set_bit_lock);
10192d11594SJim Quinlan 
10292d11594SJim Quinlan 
10392d11594SJim Quinlan /**
10492d11594SJim Quinlan  * __mips_test_and_clear_bit - Clear a bit and return its old value.  This is
10592d11594SJim Quinlan  * called by test_and_clear_bit() if it cannot find a faster solution.
10692d11594SJim Quinlan  * @nr: Bit to clear
10792d11594SJim Quinlan  * @addr: Address to count from
10892d11594SJim Quinlan  */
__mips_test_and_clear_bit(unsigned long nr,volatile unsigned long * addr)10992d11594SJim Quinlan int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
11092d11594SJim Quinlan {
111*c042be02SPaul Burton 	volatile unsigned long *a = &addr[BIT_WORD(nr)];
112*c042be02SPaul Burton 	unsigned int bit = nr % BITS_PER_LONG;
11392d11594SJim Quinlan 	unsigned long mask;
11492d11594SJim Quinlan 	unsigned long flags;
1150c81157bSDavid Daney 	int res;
11692d11594SJim Quinlan 
11792d11594SJim Quinlan 	mask = 1UL << bit;
11892d11594SJim Quinlan 	raw_local_irq_save(flags);
1190c81157bSDavid Daney 	res = (mask & *a) != 0;
12092d11594SJim Quinlan 	*a &= ~mask;
12192d11594SJim Quinlan 	raw_local_irq_restore(flags);
12292d11594SJim Quinlan 	return res;
12392d11594SJim Quinlan }
12492d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_clear_bit);
12592d11594SJim Quinlan 
12692d11594SJim Quinlan 
12792d11594SJim Quinlan /**
12892d11594SJim Quinlan  * __mips_test_and_change_bit - Change a bit and return its old value.	This is
12992d11594SJim Quinlan  * called by test_and_change_bit() if it cannot find a faster solution.
13092d11594SJim Quinlan  * @nr: Bit to change
13192d11594SJim Quinlan  * @addr: Address to count from
13292d11594SJim Quinlan  */
__mips_test_and_change_bit(unsigned long nr,volatile unsigned long * addr)13392d11594SJim Quinlan int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
13492d11594SJim Quinlan {
135*c042be02SPaul Burton 	volatile unsigned long *a = &addr[BIT_WORD(nr)];
136*c042be02SPaul Burton 	unsigned int bit = nr % BITS_PER_LONG;
13792d11594SJim Quinlan 	unsigned long mask;
13892d11594SJim Quinlan 	unsigned long flags;
1390c81157bSDavid Daney 	int res;
14092d11594SJim Quinlan 
14192d11594SJim Quinlan 	mask = 1UL << bit;
14292d11594SJim Quinlan 	raw_local_irq_save(flags);
1430c81157bSDavid Daney 	res = (mask & *a) != 0;
14492d11594SJim Quinlan 	*a ^= mask;
14592d11594SJim Quinlan 	raw_local_irq_restore(flags);
14692d11594SJim Quinlan 	return res;
14792d11594SJim Quinlan }
14892d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_change_bit);
149