xref: /openbmc/linux/arch/mips/lib/bitops.c (revision 92d11594f688c8b55b51e80f2eac4417396237a4)
1*92d11594SJim Quinlan /*
2*92d11594SJim Quinlan  * This file is subject to the terms and conditions of the GNU General Public
3*92d11594SJim Quinlan  * License.  See the file "COPYING" in the main directory of this archive
4*92d11594SJim Quinlan  * for more details.
5*92d11594SJim Quinlan  *
6*92d11594SJim Quinlan  * Copyright (c) 1994-1997, 99, 2000, 06, 07 Ralf Baechle (ralf@linux-mips.org)
7*92d11594SJim Quinlan  * Copyright (c) 1999, 2000  Silicon Graphics, Inc.
8*92d11594SJim Quinlan  */
9*92d11594SJim Quinlan #include <linux/bitops.h>
10*92d11594SJim Quinlan #include <linux/irqflags.h>
11*92d11594SJim Quinlan #include <linux/export.h>
12*92d11594SJim Quinlan 
13*92d11594SJim Quinlan 
14*92d11594SJim Quinlan /**
15*92d11594SJim Quinlan  * __mips_set_bit - Atomically set a bit in memory.  This is called by
16*92d11594SJim Quinlan  * set_bit() if it cannot find a faster solution.
17*92d11594SJim Quinlan  * @nr: the bit to set
18*92d11594SJim Quinlan  * @addr: the address to start counting from
19*92d11594SJim Quinlan  */
20*92d11594SJim Quinlan void __mips_set_bit(unsigned long nr, volatile unsigned long *addr)
21*92d11594SJim Quinlan {
22*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
23*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
24*92d11594SJim Quinlan 	unsigned long mask;
25*92d11594SJim Quinlan 	unsigned long flags;
26*92d11594SJim Quinlan 
27*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
28*92d11594SJim Quinlan 	mask = 1UL << bit;
29*92d11594SJim Quinlan 	raw_local_irq_save(flags);
30*92d11594SJim Quinlan 	*a |= mask;
31*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
32*92d11594SJim Quinlan }
33*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_set_bit);
34*92d11594SJim Quinlan 
35*92d11594SJim Quinlan 
36*92d11594SJim Quinlan /**
37*92d11594SJim Quinlan  * __mips_clear_bit - Clears a bit in memory.  This is called by clear_bit() if
38*92d11594SJim Quinlan  * it cannot find a faster solution.
39*92d11594SJim Quinlan  * @nr: Bit to clear
40*92d11594SJim Quinlan  * @addr: Address to start counting from
41*92d11594SJim Quinlan  */
42*92d11594SJim Quinlan void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr)
43*92d11594SJim Quinlan {
44*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
45*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
46*92d11594SJim Quinlan 	unsigned long mask;
47*92d11594SJim Quinlan 	unsigned long flags;
48*92d11594SJim Quinlan 
49*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
50*92d11594SJim Quinlan 	mask = 1UL << bit;
51*92d11594SJim Quinlan 	raw_local_irq_save(flags);
52*92d11594SJim Quinlan 	*a &= ~mask;
53*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
54*92d11594SJim Quinlan }
55*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_clear_bit);
56*92d11594SJim Quinlan 
57*92d11594SJim Quinlan 
58*92d11594SJim Quinlan /**
59*92d11594SJim Quinlan  * __mips_change_bit - Toggle a bit in memory.  This is called by change_bit()
60*92d11594SJim Quinlan  * if it cannot find a faster solution.
61*92d11594SJim Quinlan  * @nr: Bit to change
62*92d11594SJim Quinlan  * @addr: Address to start counting from
63*92d11594SJim Quinlan  */
64*92d11594SJim Quinlan void __mips_change_bit(unsigned long nr, volatile unsigned long *addr)
65*92d11594SJim Quinlan {
66*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
67*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
68*92d11594SJim Quinlan 	unsigned long mask;
69*92d11594SJim Quinlan 	unsigned long flags;
70*92d11594SJim Quinlan 
71*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
72*92d11594SJim Quinlan 	mask = 1UL << bit;
73*92d11594SJim Quinlan 	raw_local_irq_save(flags);
74*92d11594SJim Quinlan 	*a ^= mask;
75*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
76*92d11594SJim Quinlan }
77*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_change_bit);
78*92d11594SJim Quinlan 
79*92d11594SJim Quinlan 
80*92d11594SJim Quinlan /**
81*92d11594SJim Quinlan  * __mips_test_and_set_bit - Set a bit and return its old value.  This is
82*92d11594SJim Quinlan  * called by test_and_set_bit() if it cannot find a faster solution.
83*92d11594SJim Quinlan  * @nr: Bit to set
84*92d11594SJim Quinlan  * @addr: Address to count from
85*92d11594SJim Quinlan  */
86*92d11594SJim Quinlan int __mips_test_and_set_bit(unsigned long nr,
87*92d11594SJim Quinlan 			    volatile unsigned long *addr)
88*92d11594SJim Quinlan {
89*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
90*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
91*92d11594SJim Quinlan 	unsigned long mask;
92*92d11594SJim Quinlan 	unsigned long flags;
93*92d11594SJim Quinlan 	unsigned long res;
94*92d11594SJim Quinlan 
95*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
96*92d11594SJim Quinlan 	mask = 1UL << bit;
97*92d11594SJim Quinlan 	raw_local_irq_save(flags);
98*92d11594SJim Quinlan 	res = (mask & *a);
99*92d11594SJim Quinlan 	*a |= mask;
100*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
101*92d11594SJim Quinlan 	return res;
102*92d11594SJim Quinlan }
103*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_set_bit);
104*92d11594SJim Quinlan 
105*92d11594SJim Quinlan 
106*92d11594SJim Quinlan /**
107*92d11594SJim Quinlan  * __mips_test_and_set_bit_lock - Set a bit and return its old value.  This is
108*92d11594SJim Quinlan  * called by test_and_set_bit_lock() if it cannot find a faster solution.
109*92d11594SJim Quinlan  * @nr: Bit to set
110*92d11594SJim Quinlan  * @addr: Address to count from
111*92d11594SJim Quinlan  */
112*92d11594SJim Quinlan int __mips_test_and_set_bit_lock(unsigned long nr,
113*92d11594SJim Quinlan 				 volatile unsigned long *addr)
114*92d11594SJim Quinlan {
115*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
116*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
117*92d11594SJim Quinlan 	unsigned long mask;
118*92d11594SJim Quinlan 	unsigned long flags;
119*92d11594SJim Quinlan 	unsigned long res;
120*92d11594SJim Quinlan 
121*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
122*92d11594SJim Quinlan 	mask = 1UL << bit;
123*92d11594SJim Quinlan 	raw_local_irq_save(flags);
124*92d11594SJim Quinlan 	res = (mask & *a);
125*92d11594SJim Quinlan 	*a |= mask;
126*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
127*92d11594SJim Quinlan 	return res;
128*92d11594SJim Quinlan }
129*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_set_bit_lock);
130*92d11594SJim Quinlan 
131*92d11594SJim Quinlan 
132*92d11594SJim Quinlan /**
133*92d11594SJim Quinlan  * __mips_test_and_clear_bit - Clear a bit and return its old value.  This is
134*92d11594SJim Quinlan  * called by test_and_clear_bit() if it cannot find a faster solution.
135*92d11594SJim Quinlan  * @nr: Bit to clear
136*92d11594SJim Quinlan  * @addr: Address to count from
137*92d11594SJim Quinlan  */
138*92d11594SJim Quinlan int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
139*92d11594SJim Quinlan {
140*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
141*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
142*92d11594SJim Quinlan 	unsigned long mask;
143*92d11594SJim Quinlan 	unsigned long flags;
144*92d11594SJim Quinlan 	unsigned long res;
145*92d11594SJim Quinlan 
146*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
147*92d11594SJim Quinlan 	mask = 1UL << bit;
148*92d11594SJim Quinlan 	raw_local_irq_save(flags);
149*92d11594SJim Quinlan 	res = (mask & *a);
150*92d11594SJim Quinlan 	*a &= ~mask;
151*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
152*92d11594SJim Quinlan 	return res;
153*92d11594SJim Quinlan }
154*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_clear_bit);
155*92d11594SJim Quinlan 
156*92d11594SJim Quinlan 
157*92d11594SJim Quinlan /**
158*92d11594SJim Quinlan  * __mips_test_and_change_bit - Change a bit and return its old value.  This is
159*92d11594SJim Quinlan  * called by test_and_change_bit() if it cannot find a faster solution.
160*92d11594SJim Quinlan  * @nr: Bit to change
161*92d11594SJim Quinlan  * @addr: Address to count from
162*92d11594SJim Quinlan  */
163*92d11594SJim Quinlan int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
164*92d11594SJim Quinlan {
165*92d11594SJim Quinlan 	volatile unsigned long *a = addr;
166*92d11594SJim Quinlan 	unsigned bit = nr & SZLONG_MASK;
167*92d11594SJim Quinlan 	unsigned long mask;
168*92d11594SJim Quinlan 	unsigned long flags;
169*92d11594SJim Quinlan 	unsigned long res;
170*92d11594SJim Quinlan 
171*92d11594SJim Quinlan 	a += nr >> SZLONG_LOG;
172*92d11594SJim Quinlan 	mask = 1UL << bit;
173*92d11594SJim Quinlan 	raw_local_irq_save(flags);
174*92d11594SJim Quinlan 	res = (mask & *a);
175*92d11594SJim Quinlan 	*a ^= mask;
176*92d11594SJim Quinlan 	raw_local_irq_restore(flags);
177*92d11594SJim Quinlan 	return res;
178*92d11594SJim Quinlan }
179*92d11594SJim Quinlan EXPORT_SYMBOL(__mips_test_and_change_bit);
180