root/include/asm-sparc/bitops.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. set_bit
  2. clear_bit
  3. change_bit
  4. test_bit
  5. ffz
  6. find_next_zero_bit

   1 #ifndef _SPARC_BITOPS_H
   2 #define _SPARC_BITOPS_H
   3 
   4 #include <linux/kernel.h>
   5 #include <asm/system.h>
   6 
   7 /*
   8  * Copyright 1995, David S. Miller (davem@caip.rutgers.edu).
   9  */
  10 
  11 
  12 /* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
  13  * is in the highest of the four bytes and bit '31' is the high bit
  14  * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
  15  * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
  16  */
  17 
  18 /* For now, the sun4c implementation will disable and enable traps
  19  * in order to insure atomicity. Things will have to be different
  20  * for sun4m (ie. SMP) no doubt.
  21  */
  22 
  23 /* These routines now do things in little endian byte order. */
  24 
  25 /* Our unsigned long accesses on the Sparc look like this:
  26  * Big Endian:
  27  *    byte 0    byte 1      byte 2    byte 3
  28  *  0000 0000  0000 0000  0000 0000  0000 0000
  29  *  31     24  23     16  15      8  7       0
  30  *
  31  * We want to set the bits in a little-endian fashion:
  32  * Little Endian:
  33  *    byte 3    byte 2      byte 1    byte 0
  34  *  0000 0000  0000 0000  0000 0000  0000 0000
  35  *  31     24  23     16  15      8  7       0
  36  */
  37 
  38 /* #define __LITTLE_ENDIAN_BITOPS */
  39 
  40 extern __inline__ unsigned int set_bit(unsigned int nr, void *vaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42 
  43 
  44 #ifdef __LITTLE_ENDIAN_BITOPS
  45 
  46 
  47         int retval;
  48         unsigned char *addr = (unsigned char *)vaddr;
  49         unsigned char mask;
  50 #ifndef TEST_BITOPS
  51         unsigned long flags;
  52 #endif
  53 
  54         addr += nr >> 3;
  55         mask = 1 << (nr & 0x7);
  56 
  57 #ifndef TEST_BITOPS
  58         save_flags(flags);
  59         cli();
  60 #endif
  61 
  62         retval = (mask & *addr) != 0;
  63         *addr |= mask;
  64 
  65 #ifndef TEST_BITOPS
  66         restore_flags(flags);
  67 #endif
  68 
  69         return retval;
  70 
  71 #else  /* BIG ENDIAN BITOPS */
  72 
  73 
  74         int retval;
  75         unsigned long *addr = vaddr;
  76         unsigned long mask;
  77 #ifndef TEST_BITOPS
  78         unsigned long flags;
  79 #endif
  80 
  81         addr += nr>>5;
  82         mask = 1 << (nr&31);
  83 
  84 #ifndef TEST_BITOPS
  85         save_flags(flags);
  86         cli();
  87 #endif
  88 
  89         retval = (mask & *addr) != 0;
  90         *addr |= mask;
  91 
  92 #ifndef TEST_BITOPS
  93         restore_flags(flags);
  94 #endif
  95 
  96         return retval;
  97 
  98 
  99 #endif
 100 }
 101 
 102 extern __inline__ unsigned int clear_bit(unsigned int nr, void *vaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104 #ifdef __LITTLE_ENDIAN_BITOPS
 105 
 106 
 107         int retval;
 108         unsigned char *addr = (unsigned char *)vaddr;
 109         unsigned char mask;
 110 #ifndef TEST_BITOPS
 111         unsigned long flags;
 112 #endif
 113 
 114         addr += nr >> 3;
 115         mask = 1 << (nr & 7);
 116 
 117 #ifndef TEST_BITOPS
 118         save_flags(flags);
 119         cli();
 120 #endif
 121 
 122         retval = (mask & *addr) != 0;
 123         *addr &= ~mask;
 124 
 125 #ifndef TEST_BITOPS
 126         restore_flags(flags);
 127 #endif
 128 
 129         return retval;
 130 
 131 
 132 #else   /* BIG ENDIAN BITOPS */
 133 
 134 
 135         int retval;
 136         unsigned long *addr = vaddr;
 137         unsigned long mask;
 138 #ifndef TEST_BITOPS
 139         unsigned long flags;
 140 #endif
 141 
 142         addr += nr>>5;
 143         mask = 1 << (nr&31);
 144 
 145 #ifndef TEST_BITOPS
 146         save_flags(flags);
 147         cli();
 148 #endif
 149 
 150         retval = (mask & *addr) != 0;
 151         *addr &= ~mask;
 152 
 153 #ifndef TEST_BITOPS
 154         restore_flags(flags);
 155 #endif
 156 
 157         return retval;
 158 
 159 
 160 #endif
 161 }
 162 
 163 extern __inline__ unsigned int change_bit(unsigned int nr, void *vaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 {
 165 #ifdef __LITTLE_ENDIAN_BITOPS
 166 
 167 
 168         int retval;
 169         unsigned char *addr = (unsigned char *)vaddr;
 170         unsigned char mask;
 171 #ifndef TEST_BITOPS
 172         unsigned long flags;
 173 #endif
 174 
 175         addr += nr >> 3;
 176         mask = 1 << (nr & 7);
 177 
 178 #ifndef TEST_BITOPS
 179         save_flags(flags);
 180         cli();
 181 #endif
 182 
 183         retval = (mask & *addr) != 0;
 184         *addr ^= mask;
 185 
 186 #ifndef TEST_BITOPS
 187         restore_flags(flags);
 188 #endif
 189 
 190         return retval;
 191 
 192 
 193 #else   /* BIG ENDIAN BITOPS */
 194 
 195 
 196         int retval;
 197         unsigned long *addr = vaddr;
 198         unsigned long mask;
 199 #ifndef TEST_BITOPS
 200         unsigned long flags;
 201 #endif
 202 
 203         addr += nr>>5;
 204         mask = 1 << (nr&31);
 205 
 206 #ifndef TEST_BITOPS
 207         save_flags(flags);
 208         cli();
 209 #endif
 210 
 211         retval = (mask & *addr) != 0;
 212         *addr ^= mask;
 213 
 214 #ifndef TEST_BITOPS
 215         restore_flags(flags);
 216 #endif
 217 
 218         return retval;
 219 
 220 
 221 #endif
 222 }
 223 
 224 /* The following routine need not be atomic. */
 225 
 226 extern __inline__ unsigned int test_bit(int nr, void *vaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 227 {
 228 #ifdef __LITTLE_ENDIAN_BITOPS
 229 
 230         unsigned char mask;
 231         unsigned char *addr = (unsigned char *)vaddr;
 232 
 233         addr += nr >> 3;
 234         mask = 1 << (nr & 7);
 235         return ((mask & *addr) != 0);
 236 
 237 #else   /* BIG ENDIAN BITOPS */
 238 
 239         unsigned long mask;
 240         unsigned long *addr = vaddr;
 241 
 242         addr += (nr>>5);
 243         mask = 1 << (nr&31);
 244         return ((mask & *addr) != 0);
 245 
 246 #endif
 247 }
 248 
 249 /* There has to be a faster way to do this, sigh... */
 250 
 251 extern __inline__ unsigned long ffz(unsigned long word)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253   register unsigned long cnt;
 254 
 255   cnt = 0;
 256 
 257 #ifdef __LITTLE_ENDIAN_BITOPS
 258 
 259   for(int byte_bit = 24; byte_bit >=0; byte_bit -= 8)
 260           for(int bit = 0; bit<8; bit++)
 261                   if((word>>(byte_bit+bit))&1)
 262                           cnt++;
 263                   else
 264                           return cnt;
 265 
 266 #else /* BIT ENDIAN BITOPS */
 267   while(cnt<32) {
 268           if(!((word>>cnt)&1))
 269                   return cnt;
 270           else
 271                   cnt++;
 272   }
 273   return cnt;
 274 #endif
 275 
 276 }
 277 
 278 /* find_next_zero_bit() finds the first zero bit in a bit string of length
 279  * 'size' bits, starting the search at bit 'offset'. This is largely based
 280  * on Linus's ALPHA routines, which are pretty portable BTW.
 281  */
 282 
 283 extern __inline__ unsigned long
 284 find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286 #ifdef __LITTLE_ENDIAN_BITOPS
 287 
 288         /* FOO, needs to be written */
 289 
 290 #else   /* BIG ENDIAN BITOPS */
 291         unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
 292         unsigned long result = offset & ~31UL;
 293         unsigned long tmp;
 294 
 295         if (offset >= size)
 296                 return size;
 297         size -= result;
 298         offset &= 31UL;
 299         if (offset) 
 300         {
 301                 tmp = *(p++);
 302                 tmp |= ~0UL >> (32-offset);
 303                 if (size < 32)
 304                         goto found_first;
 305                 if (~tmp)
 306                         goto found_middle;
 307                 size -= 32;
 308                 result += 32;
 309         }
 310         while (size & ~32UL) 
 311         {
 312                 if (~(tmp = *(p++)))
 313                         goto found_middle;
 314                 result += 32;
 315                 size -= 32;
 316         }
 317         if (!size)
 318                 return result;
 319         tmp = *p;
 320 
 321 found_first:
 322         tmp |= ~0UL << size;
 323 found_middle:
 324         return result + ffz(tmp);
 325 #endif
 326 }
 327 
 328 /* Linus sez that gcc can optimize the following correctly, we'll see if this
 329  * holds on the Sparc as it does for the ALPHA.
 330  */
 331 
 332 #define find_first_zero_bit(addr, size) \
 333         find_next_zero_bit((addr), (size), 0)
 334 
 335 
 336 #endif /* defined(_SPARC_BITOPS_H) */
 337 

/* [previous][next][first][last][top][bottom][index][help] */