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