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