1#ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_ 2#define _ASM_GENERIC_BITOPS_ATOMIC_H_ 3 4#include <asm/types.h> 5 6#define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) 7#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) 8 9#ifdef CONFIG_SMP 10#include <asm/spinlock.h> 11#include <asm/cache.h> /* we use L1_CACHE_BYTES */ 12 13/* Use an array of spinlocks for our atomic_ts. 14 * Hash function to index into a different SPINLOCK. 15 * Since "a" is usually an address, use one spinlock per cacheline. 16 */ 17# define ATOMIC_HASH_SIZE 4 18# define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ])) 19 20extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; 21 22/* Can't use raw_spin_lock_irq because of #include problems, so 23 * this is the substitute */ 24#define _atomic_spin_lock_irqsave(l,f) do { \ 25 raw_spinlock_t *s = ATOMIC_HASH(l); \ 26 local_irq_save(f); \ 27 __raw_spin_lock(s); \ 28} while(0) 29 30#define _atomic_spin_unlock_irqrestore(l,f) do { \ 31 raw_spinlock_t *s = ATOMIC_HASH(l); \ 32 __raw_spin_unlock(s); \ 33 local_irq_restore(f); \ 34} while(0) 35 36 37#else 38# define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0) 39# define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0) 40#endif 41 42/* 43 * NMI events can occur at any time, including when interrupts have been 44 * disabled by *_irqsave(). So you can get NMI events occurring while a 45 * *_bit function is holding a spin lock. If the NMI handler also wants 46 * to do bit manipulation (and they do) then you can get a deadlock 47 * between the original caller of *_bit() and the NMI handler. 48 * 49 * by Keith Owens 50 */ 51 52/** 53 * set_bit - Atomically set a bit in memory 54 * @nr: the bit to set 55 * @addr: the address to start counting from 56 * 57 * This function is atomic and may not be reordered. See __set_bit() 58 * if you do not require the atomic guarantees. 59 * 60 * Note: there are no guarantees that this function will not be reordered 61 * on non x86 architectures, so if you are writting portable code, 62 * make sure not to rely on its reordering guarantees. 63 * 64 * Note that @nr may be almost arbitrarily large; this function is not 65 * restricted to acting on a single-word quantity. 66 */ 67static inline void set_bit(int nr, volatile unsigned long *addr) 68{ 69 unsigned long mask = BITOP_MASK(nr); 70 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 71 unsigned long flags; 72 73 _atomic_spin_lock_irqsave(p, flags); 74 *p |= mask; 75 _atomic_spin_unlock_irqrestore(p, flags); 76} 77 78/** 79 * clear_bit - Clears a bit in memory 80 * @nr: Bit to clear 81 * @addr: Address to start counting from 82 * 83 * clear_bit() is atomic and may not be reordered. However, it does 84 * not contain a memory barrier, so if it is used for locking purposes, 85 * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit() 86 * in order to ensure changes are visible on other processors. 87 */ 88static inline void clear_bit(int nr, volatile unsigned long *addr) 89{ 90 unsigned long mask = BITOP_MASK(nr); 91 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 92 unsigned long flags; 93 94 _atomic_spin_lock_irqsave(p, flags); 95 *p &= ~mask; 96 _atomic_spin_unlock_irqrestore(p, flags); 97} 98 99/** 100 * change_bit - Toggle a bit in memory 101 * @nr: Bit to change 102 * @addr: Address to start counting from 103 * 104 * change_bit() is atomic and may not be reordered. It may be 105 * reordered on other architectures than x86. 106 * Note that @nr may be almost arbitrarily large; this function is not 107 * restricted to acting on a single-word quantity. 108 */ 109static inline void change_bit(int nr, volatile unsigned long *addr) 110{ 111 unsigned long mask = BITOP_MASK(nr); 112 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 113 unsigned long flags; 114 115 _atomic_spin_lock_irqsave(p, flags); 116 *p ^= mask; 117 _atomic_spin_unlock_irqrestore(p, flags); 118} 119 120/** 121 * test_and_set_bit - Set a bit and return its old value 122 * @nr: Bit to set 123 * @addr: Address to count from 124 * 125 * This operation is atomic and cannot be reordered. 126 * It may be reordered on other architectures than x86. 127 * It also implies a memory barrier. 128 */ 129static inline int test_and_set_bit(int nr, volatile unsigned long *addr) 130{ 131 unsigned long mask = BITOP_MASK(nr); 132 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 133 unsigned long old; 134 unsigned long flags; 135 136 _atomic_spin_lock_irqsave(p, flags); 137 old = *p; 138 *p = old | mask; 139 _atomic_spin_unlock_irqrestore(p, flags); 140 141 return (old & mask) != 0; 142} 143 144/** 145 * test_and_clear_bit - Clear a bit and return its old value 146 * @nr: Bit to clear 147 * @addr: Address to count from 148 * 149 * This operation is atomic and cannot be reordered. 150 * It can be reorderdered on other architectures other than x86. 151 * It also implies a memory barrier. 152 */ 153static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) 154{ 155 unsigned long mask = BITOP_MASK(nr); 156 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 157 unsigned long old; 158 unsigned long flags; 159 160 _atomic_spin_lock_irqsave(p, flags); 161 old = *p; 162 *p = old & ~mask; 163 _atomic_spin_unlock_irqrestore(p, flags); 164 165 return (old & mask) != 0; 166} 167 168/** 169 * test_and_change_bit - Change a bit and return its old value 170 * @nr: Bit to change 171 * @addr: Address to count from 172 * 173 * This operation is atomic and cannot be reordered. 174 * It also implies a memory barrier. 175 */ 176static inline int test_and_change_bit(int nr, volatile unsigned long *addr) 177{ 178 unsigned long mask = BITOP_MASK(nr); 179 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 180 unsigned long old; 181 unsigned long flags; 182 183 _atomic_spin_lock_irqsave(p, flags); 184 old = *p; 185 *p = old ^ mask; 186 _atomic_spin_unlock_irqrestore(p, flags); 187 188 return (old & mask) != 0; 189} 190 191#endif /* _ASM_GENERIC_BITOPS_ATOMIC_H */ 192