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