1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _PARISC_BITOPS_H 3 #define _PARISC_BITOPS_H 4 5 #ifndef _LINUX_BITOPS_H 6 #error only <linux/bitops.h> can be included directly 7 #endif 8 9 #include <linux/compiler.h> 10 #include <asm/types.h> 11 #include <asm/byteorder.h> 12 #include <asm/barrier.h> 13 #include <linux/atomic.h> 14 15 /* 16 * HP-PARISC specific bit operations 17 * for a detailed description of the functions please refer 18 * to include/asm-i386/bitops.h or kerneldoc 19 */ 20 21 #if __BITS_PER_LONG == 64 22 #define SHIFT_PER_LONG 6 23 #else 24 #define SHIFT_PER_LONG 5 25 #endif 26 27 #define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1)) 28 29 30 /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion 31 * on use of volatile and __*_bit() (set/clear/change): 32 * *_bit() want use of volatile. 33 * __*_bit() are "relaxed" and don't use spinlock or volatile. 34 */ 35 36 static __inline__ void set_bit(int nr, volatile unsigned long * addr) 37 { 38 unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); 39 unsigned long flags; 40 41 addr += (nr >> SHIFT_PER_LONG); 42 _atomic_spin_lock_irqsave(addr, flags); 43 *addr |= mask; 44 _atomic_spin_unlock_irqrestore(addr, flags); 45 } 46 47 static __inline__ void clear_bit(int nr, volatile unsigned long * addr) 48 { 49 unsigned long mask = ~(1UL << CHOP_SHIFTCOUNT(nr)); 50 unsigned long flags; 51 52 addr += (nr >> SHIFT_PER_LONG); 53 _atomic_spin_lock_irqsave(addr, flags); 54 *addr &= mask; 55 _atomic_spin_unlock_irqrestore(addr, flags); 56 } 57 58 static __inline__ void change_bit(int nr, volatile unsigned long * addr) 59 { 60 unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); 61 unsigned long flags; 62 63 addr += (nr >> SHIFT_PER_LONG); 64 _atomic_spin_lock_irqsave(addr, flags); 65 *addr ^= mask; 66 _atomic_spin_unlock_irqrestore(addr, flags); 67 } 68 69 static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr) 70 { 71 unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); 72 unsigned long old; 73 unsigned long flags; 74 int set; 75 76 addr += (nr >> SHIFT_PER_LONG); 77 _atomic_spin_lock_irqsave(addr, flags); 78 old = *addr; 79 set = (old & mask) ? 1 : 0; 80 if (!set) 81 *addr = old | mask; 82 _atomic_spin_unlock_irqrestore(addr, flags); 83 84 return set; 85 } 86 87 static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr) 88 { 89 unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); 90 unsigned long old; 91 unsigned long flags; 92 int set; 93 94 addr += (nr >> SHIFT_PER_LONG); 95 _atomic_spin_lock_irqsave(addr, flags); 96 old = *addr; 97 set = (old & mask) ? 1 : 0; 98 if (set) 99 *addr = old & ~mask; 100 _atomic_spin_unlock_irqrestore(addr, flags); 101 102 return set; 103 } 104 105 static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr) 106 { 107 unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); 108 unsigned long oldbit; 109 unsigned long flags; 110 111 addr += (nr >> SHIFT_PER_LONG); 112 _atomic_spin_lock_irqsave(addr, flags); 113 oldbit = *addr; 114 *addr = oldbit ^ mask; 115 _atomic_spin_unlock_irqrestore(addr, flags); 116 117 return (oldbit & mask) ? 1 : 0; 118 } 119 120 #include <asm-generic/bitops/non-atomic.h> 121 122 #ifdef __KERNEL__ 123 124 /** 125 * __ffs - find first bit in word. returns 0 to "BITS_PER_LONG-1". 126 * @word: The word to search 127 * 128 * __ffs() return is undefined if no bit is set. 129 * 130 * 32-bit fast __ffs by LaMont Jones "lamont At hp com". 131 * 64-bit enhancement by Grant Grundler "grundler At parisc-linux org". 132 * (with help from willy/jejb to get the semantics right) 133 * 134 * This algorithm avoids branches by making use of nullification. 135 * One side effect of "extr" instructions is it sets PSW[N] bit. 136 * How PSW[N] (nullify next insn) gets set is determined by the 137 * "condition" field (eg "<>" or "TR" below) in the extr* insn. 138 * Only the 1st and one of either the 2cd or 3rd insn will get executed. 139 * Each set of 3 insn will get executed in 2 cycles on PA8x00 vs 16 or so 140 * cycles for each mispredicted branch. 141 */ 142 143 static __inline__ unsigned long __ffs(unsigned long x) 144 { 145 unsigned long ret; 146 147 __asm__( 148 #ifdef CONFIG_64BIT 149 " ldi 63,%1\n" 150 " extrd,u,*<> %0,63,32,%%r0\n" 151 " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */ 152 " addi -32,%1,%1\n" 153 #else 154 " ldi 31,%1\n" 155 #endif 156 " extru,<> %0,31,16,%%r0\n" 157 " extru,TR %0,15,16,%0\n" /* xxxx0000 -> 0000xxxx */ 158 " addi -16,%1,%1\n" 159 " extru,<> %0,31,8,%%r0\n" 160 " extru,TR %0,23,8,%0\n" /* 0000xx00 -> 000000xx */ 161 " addi -8,%1,%1\n" 162 " extru,<> %0,31,4,%%r0\n" 163 " extru,TR %0,27,4,%0\n" /* 000000x0 -> 0000000x */ 164 " addi -4,%1,%1\n" 165 " extru,<> %0,31,2,%%r0\n" 166 " extru,TR %0,29,2,%0\n" /* 0000000y, 1100b -> 0011b */ 167 " addi -2,%1,%1\n" 168 " extru,= %0,31,1,%%r0\n" /* check last bit */ 169 " addi -1,%1,%1\n" 170 : "+r" (x), "=r" (ret) ); 171 return ret; 172 } 173 174 #include <asm-generic/bitops/ffz.h> 175 176 /* 177 * ffs: find first bit set. returns 1 to BITS_PER_LONG or 0 (if none set) 178 * This is defined the same way as the libc and compiler builtin 179 * ffs routines, therefore differs in spirit from the above ffz (man ffs). 180 */ 181 static __inline__ int ffs(int x) 182 { 183 return x ? (__ffs((unsigned long)x) + 1) : 0; 184 } 185 186 /* 187 * fls: find last (most significant) bit set. 188 * fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 189 */ 190 191 static __inline__ int fls(unsigned int x) 192 { 193 int ret; 194 if (!x) 195 return 0; 196 197 __asm__( 198 " ldi 1,%1\n" 199 " extru,<> %0,15,16,%%r0\n" 200 " zdep,TR %0,15,16,%0\n" /* xxxx0000 */ 201 " addi 16,%1,%1\n" 202 " extru,<> %0,7,8,%%r0\n" 203 " zdep,TR %0,23,24,%0\n" /* xx000000 */ 204 " addi 8,%1,%1\n" 205 " extru,<> %0,3,4,%%r0\n" 206 " zdep,TR %0,27,28,%0\n" /* x0000000 */ 207 " addi 4,%1,%1\n" 208 " extru,<> %0,1,2,%%r0\n" 209 " zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0) */ 210 " addi 2,%1,%1\n" 211 " extru,= %0,0,1,%%r0\n" 212 " addi 1,%1,%1\n" /* if y & 8, add 1 */ 213 : "+r" (x), "=r" (ret) ); 214 215 return ret; 216 } 217 218 #include <asm-generic/bitops/__fls.h> 219 #include <asm-generic/bitops/fls64.h> 220 #include <asm-generic/bitops/hweight.h> 221 #include <asm-generic/bitops/lock.h> 222 #include <asm-generic/bitops/sched.h> 223 224 #endif /* __KERNEL__ */ 225 226 #include <asm-generic/bitops/find.h> 227 228 #ifdef __KERNEL__ 229 230 #include <asm-generic/bitops/le.h> 231 #include <asm-generic/bitops/ext2-atomic-setbit.h> 232 233 #endif /* __KERNEL__ */ 234 235 #endif /* _PARISC_BITOPS_H */ 236