1 /* 2 * include/asm-xtensa/bitops.h 3 * 4 * Atomic operations that C can't guarantee us.Useful for resource counting etc. 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 * 10 * Copyright (C) 2001 - 2007 Tensilica Inc. 11 */ 12 13 #ifndef _XTENSA_BITOPS_H 14 #define _XTENSA_BITOPS_H 15 16 #ifndef _LINUX_BITOPS_H 17 #error only <linux/bitops.h> can be included directly 18 #endif 19 20 #include <asm/processor.h> 21 #include <asm/byteorder.h> 22 #include <asm/barrier.h> 23 24 #include <asm-generic/bitops/non-atomic.h> 25 26 #if XCHAL_HAVE_NSA 27 28 static inline unsigned long __cntlz (unsigned long x) 29 { 30 int lz; 31 asm ("nsau %0, %1" : "=r" (lz) : "r" (x)); 32 return lz; 33 } 34 35 /* 36 * ffz: Find first zero in word. Undefined if no zero exists. 37 * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). 38 */ 39 40 static inline int ffz(unsigned long x) 41 { 42 return 31 - __cntlz(~x & -~x); 43 } 44 45 /* 46 * __ffs: Find first bit set in word. Return 0 for bit 0 47 */ 48 49 static inline unsigned long __ffs(unsigned long x) 50 { 51 return 31 - __cntlz(x & -x); 52 } 53 54 /* 55 * ffs: Find first bit set in word. This is defined the same way as 56 * the libc and compiler builtin ffs routines, therefore 57 * differs in spirit from the above ffz (man ffs). 58 */ 59 60 static inline int ffs(unsigned long x) 61 { 62 return 32 - __cntlz(x & -x); 63 } 64 65 /* 66 * fls: Find last (most-significant) bit set in word. 67 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 68 */ 69 70 static inline int fls (unsigned int x) 71 { 72 return 32 - __cntlz(x); 73 } 74 75 /** 76 * __fls - find last (most-significant) set bit in a long word 77 * @word: the word to search 78 * 79 * Undefined if no set bit exists, so code should check against 0 first. 80 */ 81 static inline unsigned long __fls(unsigned long word) 82 { 83 return 31 - __cntlz(word); 84 } 85 #else 86 87 /* Use the generic implementation if we don't have the nsa/nsau instructions. */ 88 89 # include <asm-generic/bitops/ffs.h> 90 # include <asm-generic/bitops/__ffs.h> 91 # include <asm-generic/bitops/ffz.h> 92 # include <asm-generic/bitops/fls.h> 93 # include <asm-generic/bitops/__fls.h> 94 95 #endif 96 97 #include <asm-generic/bitops/fls64.h> 98 99 #if XCHAL_HAVE_S32C1I 100 101 static inline void set_bit(unsigned int bit, volatile unsigned long *p) 102 { 103 unsigned long tmp, value; 104 unsigned long mask = 1UL << (bit & 31); 105 106 p += bit >> 5; 107 108 __asm__ __volatile__( 109 "1: l32i %1, %3, 0\n" 110 " wsr %1, scompare1\n" 111 " or %0, %1, %2\n" 112 " s32c1i %0, %3, 0\n" 113 " bne %0, %1, 1b\n" 114 : "=&a" (tmp), "=&a" (value) 115 : "a" (mask), "a" (p) 116 : "memory"); 117 } 118 119 static inline void clear_bit(unsigned int bit, volatile unsigned long *p) 120 { 121 unsigned long tmp, value; 122 unsigned long mask = 1UL << (bit & 31); 123 124 p += bit >> 5; 125 126 __asm__ __volatile__( 127 "1: l32i %1, %3, 0\n" 128 " wsr %1, scompare1\n" 129 " and %0, %1, %2\n" 130 " s32c1i %0, %3, 0\n" 131 " bne %0, %1, 1b\n" 132 : "=&a" (tmp), "=&a" (value) 133 : "a" (~mask), "a" (p) 134 : "memory"); 135 } 136 137 static inline void change_bit(unsigned int bit, volatile unsigned long *p) 138 { 139 unsigned long tmp, value; 140 unsigned long mask = 1UL << (bit & 31); 141 142 p += bit >> 5; 143 144 __asm__ __volatile__( 145 "1: l32i %1, %3, 0\n" 146 " wsr %1, scompare1\n" 147 " xor %0, %1, %2\n" 148 " s32c1i %0, %3, 0\n" 149 " bne %0, %1, 1b\n" 150 : "=&a" (tmp), "=&a" (value) 151 : "a" (mask), "a" (p) 152 : "memory"); 153 } 154 155 static inline int 156 test_and_set_bit(unsigned int bit, volatile unsigned long *p) 157 { 158 unsigned long tmp, value; 159 unsigned long mask = 1UL << (bit & 31); 160 161 p += bit >> 5; 162 163 __asm__ __volatile__( 164 "1: l32i %1, %3, 0\n" 165 " wsr %1, scompare1\n" 166 " or %0, %1, %2\n" 167 " s32c1i %0, %3, 0\n" 168 " bne %0, %1, 1b\n" 169 : "=&a" (tmp), "=&a" (value) 170 : "a" (mask), "a" (p) 171 : "memory"); 172 173 return tmp & mask; 174 } 175 176 static inline int 177 test_and_clear_bit(unsigned int bit, volatile unsigned long *p) 178 { 179 unsigned long tmp, value; 180 unsigned long mask = 1UL << (bit & 31); 181 182 p += bit >> 5; 183 184 __asm__ __volatile__( 185 "1: l32i %1, %3, 0\n" 186 " wsr %1, scompare1\n" 187 " and %0, %1, %2\n" 188 " s32c1i %0, %3, 0\n" 189 " bne %0, %1, 1b\n" 190 : "=&a" (tmp), "=&a" (value) 191 : "a" (~mask), "a" (p) 192 : "memory"); 193 194 return tmp & mask; 195 } 196 197 static inline int 198 test_and_change_bit(unsigned int bit, volatile unsigned long *p) 199 { 200 unsigned long tmp, value; 201 unsigned long mask = 1UL << (bit & 31); 202 203 p += bit >> 5; 204 205 __asm__ __volatile__( 206 "1: l32i %1, %3, 0\n" 207 " wsr %1, scompare1\n" 208 " xor %0, %1, %2\n" 209 " s32c1i %0, %3, 0\n" 210 " bne %0, %1, 1b\n" 211 : "=&a" (tmp), "=&a" (value) 212 : "a" (mask), "a" (p) 213 : "memory"); 214 215 return tmp & mask; 216 } 217 218 #else 219 220 #include <asm-generic/bitops/atomic.h> 221 222 #endif /* XCHAL_HAVE_S32C1I */ 223 224 #include <asm-generic/bitops/find.h> 225 #include <asm-generic/bitops/le.h> 226 227 #include <asm-generic/bitops/ext2-atomic-setbit.h> 228 229 #include <asm-generic/bitops/hweight.h> 230 #include <asm-generic/bitops/lock.h> 231 #include <asm-generic/bitops/sched.h> 232 233 #endif /* _XTENSA_BITOPS_H */ 234