home *** CD-ROM | disk | FTP | other *** search
- #ifndef _SPARC_BITOPS_H
- #define _SPARC_BITOPS_H
-
- /*
- * Copyright 1994, David S. Miller (davem@caip.rutgers.edu).
- */
-
-
- /* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
- * is in the highest of the four bytes and bit '31' is the high bit
- * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
- */
-
- /* For now, the sun4c implementation will disable and enable traps
- * in order to insure atomicity. Things will have to be different
- * for sun4m (ie. SMP) no doubt.
- */
-
- extern __inline__ unsigned int set_bit(unsigned int nr, void *addr)
- {
- register unsigned long retval, tmp, mask, psr;
-
- __asm__ __volatile__("or %%g0, 0x1, %3\n\t" /* produce the mask */
- "sll %3, %4, %3\n\t"
- "rd %%psr, %5\n\t" /* read the psr */
- "wr %5, 0x20, %%psr\n\t" /* traps disabled */
- "ld [%1], %2\n\t" /* critical section */
- "and %3, %2, %0\n\t"
- "or %3, %2, %2\n\t"
- "st %2, [%1]\n\t"
- "wr %5, 0x0, %%psr\n\t" : /* re-enable traps */
- "=r" (retval) :
- "r" (addr), "r" (tmp=0), "r" (mask=0),
- "r" (nr), "r" (psr=0));
-
- return retval; /* confuse gcc :-) */
-
- }
-
- extern __inline__ unsigned int clear_bit(unsigned int nr, void *addr)
- {
- register unsigned long retval, tmp, mask, psr;
-
- __asm__ __volatile__("or %%g0, 0x1, %3\n\t"
- "sll %3, %4, %3\n\t"
- "rd %%psr, %5\n\t"
- "wr %5, 0x20, %%psr\n\t" /* disable traps */
- "ld [%1], %2\n\t"
- "and %2, %3, %0\n\t" /* get old bit */
- "andn %2, %3, %2\n\t" /* set new val */
- "st %2, [%1]\n\t"
- "wr %5, 0x0, %%psr\n\t" : /* enable traps */
- "=r" (retval) :
- "r" (addr), "r" (tmp=0), "r" (mask=0),
- "r" (nr), "r" (psr=0));
-
- return retval; /* confuse gcc ;-) */
-
- }
-
- extern __inline__ unsigned int change_bit(unsigned int nr, void *addr)
- {
- register unsigned long retval, tmp, mask, psr;
-
- __asm__ __volatile__("or %%g0, 0x1, %3\n\t"
- "sll %3, %4, %3\n\t"
- "rd %%psr, %5\n\t"
- "wr %5, 0x20, %%psr\n\t" /* disable traps */
- "ld [%1], %2\n\t"
- "and %3, %2, %0\n\t" /* get old bit val */
- "xor %3, %2, %2\n\t" /* set new val */
- "st %2, [%1]\n\t"
- "wr %5, 0x0, %%psr\n\t" : /* enable traps */
- "=r" (retval) :
- "r" (addr), "r" (tmp=0), "r" (mask=0),
- "r" (nr), "r" (psr=0));
-
- return retval; /* confuse gcc ;-) */
-
- }
-
- /* The following routine need not be atomic. */
-
- extern __inline__ unsigned int test_bit(int nr, void *addr)
- {
- register unsigned long retval, tmp;
-
- __asm__ __volatile__("ld [%1], %2\n\t"
- "or %%g0, 0x1, %0\n\t"
- "sll %0, %3, %0\n\t"
- "and %0, %2, %0\n\t" :
- "=r" (retval) :
- "r" (addr), "r" (tmp=0),
- "r" (nr));
-
- return retval; /* confuse gcc :> */
-
- }
-
- /* There has to be a faster way to do this, sigh... */
-
- extern __inline__ unsigned long ffz(unsigned long word)
- {
- register unsigned long cnt, tmp, tmp2;
-
- cnt = 0;
-
- __asm__("or %%g0, %3, %2\n\t"
- "1: and %2, 0x1, %1\n\t"
- "srl %2, 0x1, %2\n\t"
- "cmp %1, 0\n\t"
- "bne,a 1b\n\t"
- "add %0, 0x1, %0\n\t" :
- "=r" (cnt) :
- "r" (tmp=0), "r" (tmp2=0), "r" (word));
-
- return cnt;
- }
-
- /* find_next_zero_bit() finds the first zero bit in a bit string of length
- * 'size' bits, starting the search at bit 'offset'. This is largely based
- * on Linus's ALPHA routines, which are pretty portable BTW.
- */
-
- extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
- {
- unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
- unsigned long result = offset & ~31UL;
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset &= 31UL;
- if (offset)
- {
- tmp = *(p++);
- tmp |= ~0UL >> (32-offset);
- if (size < 32)
- goto found_first;
- if (~tmp)
- goto found_middle;
- size -= 32;
- result += 32;
- }
- while (size & ~32UL)
- {
- if (~(tmp = *(p++)))
- goto found_middle;
- result += 32;
- size -= 32;
- }
- if (!size)
- return result;
- tmp = *p;
-
- found_first:
- tmp |= ~0UL << size;
- found_middle:
- return result + ffz(tmp);
- }
-
- /* Linus sez that gcc can optimize the following correctly, we'll see if this
- * holds on the Sparc as it does for the ALPHA.
- */
-
- #define find_first_zero_bit(addr, size) \
- find_next_zero_bit((addr), (size), 0)
-
-
- #endif /* defined(_SPARC_BITOPS_H) */
-
-