xref: /openbmc/linux/arch/mips/lib/bitops.c (revision 0c81157b46c533139d6be721d41617020c59a2c3)
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>
1092d11594SJim Quinlan #include <linux/irqflags.h>
1192d11594SJim Quinlan #include <linux/export.h>
1292d11594SJim Quinlan 
1392d11594SJim Quinlan 
1492d11594SJim Quinlan /**
1592d11594SJim Quinlan  * __mips_set_bit - Atomically set a bit in memory.  This is called by
1692d11594SJim Quinlan  * set_bit() if it cannot find a faster solution.
1792d11594SJim Quinlan  * @nr: the bit to set
1892d11594SJim Quinlan  * @addr: the address to start counting from
1992d11594SJim Quinlan  */
2092d11594SJim Quinlan void __mips_set_bit(unsigned long nr, volatile unsigned long *addr)
2192d11594SJim Quinlan {
2292d11594SJim Quinlan 	volatile unsigned long *a = addr;
2392d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
2492d11594SJim Quinlan 	unsigned long mask;
2592d11594SJim Quinlan 	unsigned long flags;
2692d11594SJim Quinlan 
2792d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
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  */
4292d11594SJim Quinlan void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr)
4392d11594SJim Quinlan {
4492d11594SJim Quinlan 	volatile unsigned long *a = addr;
4592d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
4692d11594SJim Quinlan 	unsigned long mask;
4792d11594SJim Quinlan 	unsigned long flags;
4892d11594SJim Quinlan 
4992d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
5092d11594SJim Quinlan 	mask = 1UL << bit;
5192d11594SJim Quinlan 	raw_local_irq_save(flags);
5292d11594SJim Quinlan 	*a &= ~mask;
5392d11594SJim Quinlan 	raw_local_irq_restore(flags);
5492d11594SJim Quinlan }
5592d11594SJim Quinlan EXPORT_SYMBOL(__mips_clear_bit);
5692d11594SJim Quinlan 
5792d11594SJim Quinlan 
5892d11594SJim Quinlan /**
5992d11594SJim Quinlan  * __mips_change_bit - Toggle a bit in memory.	This is called by change_bit()
6092d11594SJim Quinlan  * if it cannot find a faster solution.
6192d11594SJim Quinlan  * @nr: Bit to change
6292d11594SJim Quinlan  * @addr: Address to start counting from
6392d11594SJim Quinlan  */
6492d11594SJim Quinlan void __mips_change_bit(unsigned long nr, volatile unsigned long *addr)
6592d11594SJim Quinlan {
6692d11594SJim Quinlan 	volatile unsigned long *a = addr;
6792d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
6892d11594SJim Quinlan 	unsigned long mask;
6992d11594SJim Quinlan 	unsigned long flags;
7092d11594SJim Quinlan 
7192d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
7292d11594SJim Quinlan 	mask = 1UL << bit;
7392d11594SJim Quinlan 	raw_local_irq_save(flags);
7492d11594SJim Quinlan 	*a ^= mask;
7592d11594SJim Quinlan 	raw_local_irq_restore(flags);
7692d11594SJim Quinlan }
7792d11594SJim Quinlan EXPORT_SYMBOL(__mips_change_bit);
7892d11594SJim Quinlan 
7992d11594SJim Quinlan 
8092d11594SJim Quinlan /**
8192d11594SJim Quinlan  * __mips_test_and_set_bit - Set a bit and return its old value.  This is
8292d11594SJim Quinlan  * called by test_and_set_bit() if it cannot find a faster solution.
8392d11594SJim Quinlan  * @nr: Bit to set
8492d11594SJim Quinlan  * @addr: Address to count from
8592d11594SJim Quinlan  */
8692d11594SJim Quinlan int __mips_test_and_set_bit(unsigned long nr,
8792d11594SJim Quinlan 			    volatile unsigned long *addr)
8892d11594SJim Quinlan {
8992d11594SJim Quinlan 	volatile unsigned long *a = addr;
9092d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
9192d11594SJim Quinlan 	unsigned long mask;
9292d11594SJim Quinlan 	unsigned long flags;
93*0c81157bSDavid Daney 	int res;
9492d11594SJim Quinlan 
9592d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
9692d11594SJim Quinlan 	mask = 1UL << bit;
9792d11594SJim Quinlan 	raw_local_irq_save(flags);
98*0c81157bSDavid Daney 	res = (mask & *a) != 0;
9992d11594SJim Quinlan 	*a |= mask;
10092d11594SJim Quinlan 	raw_local_irq_restore(flags);
10192d11594SJim Quinlan 	return res;
10292d11594SJim Quinlan }
10392d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_set_bit);
10492d11594SJim Quinlan 
10592d11594SJim Quinlan 
10692d11594SJim Quinlan /**
10792d11594SJim Quinlan  * __mips_test_and_set_bit_lock - Set a bit and return its old value.  This is
10892d11594SJim Quinlan  * called by test_and_set_bit_lock() if it cannot find a faster solution.
10992d11594SJim Quinlan  * @nr: Bit to set
11092d11594SJim Quinlan  * @addr: Address to count from
11192d11594SJim Quinlan  */
11292d11594SJim Quinlan int __mips_test_and_set_bit_lock(unsigned long nr,
11392d11594SJim Quinlan 				 volatile unsigned long *addr)
11492d11594SJim Quinlan {
11592d11594SJim Quinlan 	volatile unsigned long *a = addr;
11692d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
11792d11594SJim Quinlan 	unsigned long mask;
11892d11594SJim Quinlan 	unsigned long flags;
119*0c81157bSDavid Daney 	int res;
12092d11594SJim Quinlan 
12192d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
12292d11594SJim Quinlan 	mask = 1UL << bit;
12392d11594SJim Quinlan 	raw_local_irq_save(flags);
124*0c81157bSDavid Daney 	res = (mask & *a) != 0;
12592d11594SJim Quinlan 	*a |= mask;
12692d11594SJim Quinlan 	raw_local_irq_restore(flags);
12792d11594SJim Quinlan 	return res;
12892d11594SJim Quinlan }
12992d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_set_bit_lock);
13092d11594SJim Quinlan 
13192d11594SJim Quinlan 
13292d11594SJim Quinlan /**
13392d11594SJim Quinlan  * __mips_test_and_clear_bit - Clear a bit and return its old value.  This is
13492d11594SJim Quinlan  * called by test_and_clear_bit() if it cannot find a faster solution.
13592d11594SJim Quinlan  * @nr: Bit to clear
13692d11594SJim Quinlan  * @addr: Address to count from
13792d11594SJim Quinlan  */
13892d11594SJim Quinlan int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
13992d11594SJim Quinlan {
14092d11594SJim Quinlan 	volatile unsigned long *a = addr;
14192d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
14292d11594SJim Quinlan 	unsigned long mask;
14392d11594SJim Quinlan 	unsigned long flags;
144*0c81157bSDavid Daney 	int res;
14592d11594SJim Quinlan 
14692d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
14792d11594SJim Quinlan 	mask = 1UL << bit;
14892d11594SJim Quinlan 	raw_local_irq_save(flags);
149*0c81157bSDavid Daney 	res = (mask & *a) != 0;
15092d11594SJim Quinlan 	*a &= ~mask;
15192d11594SJim Quinlan 	raw_local_irq_restore(flags);
15292d11594SJim Quinlan 	return res;
15392d11594SJim Quinlan }
15492d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_clear_bit);
15592d11594SJim Quinlan 
15692d11594SJim Quinlan 
15792d11594SJim Quinlan /**
15892d11594SJim Quinlan  * __mips_test_and_change_bit - Change a bit and return its old value.	This is
15992d11594SJim Quinlan  * called by test_and_change_bit() if it cannot find a faster solution.
16092d11594SJim Quinlan  * @nr: Bit to change
16192d11594SJim Quinlan  * @addr: Address to count from
16292d11594SJim Quinlan  */
16392d11594SJim Quinlan int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
16492d11594SJim Quinlan {
16592d11594SJim Quinlan 	volatile unsigned long *a = addr;
16692d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
16792d11594SJim Quinlan 	unsigned long mask;
16892d11594SJim Quinlan 	unsigned long flags;
169*0c81157bSDavid Daney 	int res;
17092d11594SJim Quinlan 
17192d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
17292d11594SJim Quinlan 	mask = 1UL << bit;
17392d11594SJim Quinlan 	raw_local_irq_save(flags);
174*0c81157bSDavid Daney 	res = (mask & *a) != 0;
17592d11594SJim Quinlan 	*a ^= mask;
17692d11594SJim Quinlan 	raw_local_irq_restore(flags);
17792d11594SJim Quinlan 	return res;
17892d11594SJim Quinlan }
17992d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_change_bit);
180