linux-bk/include/asm-ppc64/bitops.h
<<
>>
Prefs
   1/*
   2 * PowerPC64 atomic bit operations.
   3 * Dave Engebretsen, Todd Inglett, Don Reed, Pat McCarthy, Peter Bergner,
   4 * Anton Blanchard
   5 *
   6 * Originally taken from the 32b PPC code.  Modified to use 64b values for
   7 * the various counters & memory references.
   8 *
   9 * Bitops are odd when viewed on big-endian systems.  They were designed
  10 * on little endian so the size of the bitset doesn't matter (low order bytes
  11 * come first) as long as the bit in question is valid.
  12 *
  13 * Bits are "tested" often using the C expression (val & (1<<nr)) so we do
  14 * our best to stay compatible with that.  The assumption is that val will
  15 * be unsigned long for such tests.  As such, we assume the bits are stored
  16 * as an array of unsigned long (the usual case is a single unsigned long,
  17 * of course).  Here's an example bitset with bit numbering:
  18 *
  19 *   |63..........0|127........64|195.......128|255.......196|
  20 *
  21 * This leads to a problem. If an int, short or char is passed as a bitset
  22 * it will be a bad memory reference since we want to store in chunks
  23 * of unsigned long (64 bits here) size.
  24 *
  25 * This program is free software; you can redistribute it and/or
  26 * modify it under the terms of the GNU General Public License
  27 * as published by the Free Software Foundation; either version
  28 * 2 of the License, or (at your option) any later version.
  29 */
  30
  31#ifndef _PPC64_BITOPS_H
  32#define _PPC64_BITOPS_H
  33
  34#ifdef __KERNEL__
  35
  36#include <asm/memory.h>
  37
  38/*
  39 * clear_bit doesn't imply a memory barrier
  40 */
  41#define smp_mb__before_clear_bit()      smp_mb()
  42#define smp_mb__after_clear_bit()       smp_mb()
  43
  44static __inline__ int test_bit(unsigned long nr, __const__ volatile unsigned long *addr)
  45{
  46        return (1UL & (addr[nr >> 6] >> (nr & 63)));
  47}
  48
  49static __inline__ void set_bit(unsigned long nr, volatile unsigned long *addr)
  50{
  51        unsigned long old;
  52        unsigned long mask = 1UL << (nr & 0x3f);
  53        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  54
  55        __asm__ __volatile__(
  56"1:     ldarx   %0,0,%3         # set_bit\n\
  57        or      %0,%0,%2\n\
  58        stdcx.  %0,0,%3\n\
  59        bne-    1b"
  60        : "=&r" (old), "=m" (*p)
  61        : "r" (mask), "r" (p), "m" (*p)
  62        : "cc");
  63}
  64
  65static __inline__ void clear_bit(unsigned long nr, volatile unsigned long *addr)
  66{
  67        unsigned long old;
  68        unsigned long mask = 1UL << (nr & 0x3f);
  69        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  70
  71        __asm__ __volatile__(
  72"1:     ldarx   %0,0,%3         # clear_bit\n\
  73        andc    %0,%0,%2\n\
  74        stdcx.  %0,0,%3\n\
  75        bne-    1b"
  76        : "=&r" (old), "=m" (*p)
  77        : "r" (mask), "r" (p), "m" (*p)
  78        : "cc");
  79}
  80
  81static __inline__ void change_bit(unsigned long nr, volatile unsigned long *addr)
  82{
  83        unsigned long old;
  84        unsigned long mask = 1UL << (nr & 0x3f);
  85        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
  86
  87        __asm__ __volatile__(
  88"1:     ldarx   %0,0,%3         # change_bit\n\
  89        xor     %0,%0,%2\n\
  90        stdcx.  %0,0,%3\n\
  91        bne-    1b"
  92        : "=&r" (old), "=m" (*p)
  93        : "r" (mask), "r" (p), "m" (*p)
  94        : "cc");
  95}
  96
  97static __inline__ int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
  98{
  99        unsigned long old, t;
 100        unsigned long mask = 1UL << (nr & 0x3f);
 101        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 102
 103        __asm__ __volatile__(
 104        EIEIO_ON_SMP
 105"1:     ldarx   %0,0,%3         # test_and_set_bit\n\
 106        or      %1,%0,%2 \n\
 107        stdcx.  %1,0,%3 \n\
 108        bne-    1b"
 109        ISYNC_ON_SMP
 110        : "=&r" (old), "=&r" (t)
 111        : "r" (mask), "r" (p)
 112        : "cc", "memory");
 113
 114        return (old & mask) != 0;
 115}
 116
 117static __inline__ int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
 118{
 119        unsigned long old, t;
 120        unsigned long mask = 1UL << (nr & 0x3f);
 121        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 122
 123        __asm__ __volatile__(
 124        EIEIO_ON_SMP
 125"1:     ldarx   %0,0,%3         # test_and_clear_bit\n\
 126        andc    %1,%0,%2\n\
 127        stdcx.  %1,0,%3\n\
 128        bne-    1b"
 129        ISYNC_ON_SMP
 130        : "=&r" (old), "=&r" (t)
 131        : "r" (mask), "r" (p)
 132        : "cc", "memory");
 133
 134        return (old & mask) != 0;
 135}
 136
 137static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
 138{
 139        unsigned long old, t;
 140        unsigned long mask = 1UL << (nr & 0x3f);
 141        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 142
 143        __asm__ __volatile__(
 144        EIEIO_ON_SMP
 145"1:     ldarx   %0,0,%3         # test_and_change_bit\n\
 146        xor     %1,%0,%2\n\
 147        stdcx.  %1,0,%3\n\
 148        bne-    1b"
 149        ISYNC_ON_SMP
 150        : "=&r" (old), "=&r" (t)
 151        : "r" (mask), "r" (p)
 152        : "cc", "memory");
 153
 154        return (old & mask) != 0;
 155}
 156
 157static __inline__ void set_bits(unsigned long mask, unsigned long *addr)
 158{
 159        unsigned long old;
 160
 161        __asm__ __volatile__(
 162"1:     ldarx   %0,0,%3         # set_bit\n\
 163        or      %0,%0,%2\n\
 164        stdcx.  %0,0,%3\n\
 165        bne-    1b"
 166        : "=&r" (old), "=m" (*addr)
 167        : "r" (mask), "r" (addr), "m" (*addr)
 168        : "cc");
 169}
 170
 171/*
 172 * non-atomic versions
 173 */
 174static __inline__ void __set_bit(unsigned long nr, volatile unsigned long *addr)
 175{
 176        unsigned long mask = 1UL << (nr & 0x3f);
 177        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 178
 179        *p |= mask;
 180}
 181
 182static __inline__ void __clear_bit(unsigned long nr, volatile unsigned long *addr)
 183{
 184        unsigned long mask = 1UL << (nr & 0x3f);
 185        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 186
 187        *p &= ~mask;
 188}
 189
 190static __inline__ void __change_bit(unsigned long nr, volatile unsigned long *addr)
 191{
 192        unsigned long mask = 1UL << (nr & 0x3f);
 193        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 194
 195        *p ^= mask;
 196}
 197
 198static __inline__ int __test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
 199{
 200        unsigned long mask = 1UL << (nr & 0x3f);
 201        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 202        unsigned long old = *p;
 203
 204        *p = old | mask;
 205        return (old & mask) != 0;
 206}
 207
 208static __inline__ int __test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
 209{
 210        unsigned long mask = 1UL << (nr & 0x3f);
 211        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 212        unsigned long old = *p;
 213
 214        *p = old & ~mask;
 215        return (old & mask) != 0;
 216}
 217
 218static __inline__ int __test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
 219{
 220        unsigned long mask = 1UL << (nr & 0x3f);
 221        unsigned long *p = ((unsigned long *)addr) + (nr >> 6);
 222        unsigned long old = *p;
 223
 224        *p = old ^ mask;
 225        return (old & mask) != 0;
 226}
 227
 228/*
 229 * Return the zero-based bit position (from RIGHT TO LEFT, 63 -> 0) of the
 230 * most significant (left-most) 1-bit in a double word.
 231 */
 232static __inline__ int __ilog2(unsigned long x)
 233{
 234        int lz;
 235
 236        asm ("cntlzd %0,%1" : "=r" (lz) : "r" (x));
 237        return 63 - lz;
 238}
 239
 240/*
 241 * Determines the bit position of the least significant (rightmost) 0 bit
 242 * in the specified double word. The returned bit position will be zero-based,
 243 * starting from the right side (63 - 0).
 244 */
 245static __inline__ unsigned long ffz(unsigned long x)
 246{
 247        /* no zero exists anywhere in the 8 byte area. */
 248        if ((x = ~x) == 0)
 249                return 64;
 250
 251        /*
 252         * Calculate the bit position of the least signficant '1' bit in x
 253         * (since x has been changed this will actually be the least signficant
 254         * '0' bit in * the original x).  Note: (x & -x) gives us a mask that
 255         * is the least significant * (RIGHT-most) 1-bit of the value in x.
 256         */
 257        return __ilog2(x & -x);
 258}
 259
 260static __inline__ int __ffs(unsigned long x)
 261{
 262        return __ilog2(x & -x);
 263}
 264
 265/*
 266 * ffs: find first bit set. This is defined the same way as
 267 * the libc and compiler builtin ffs routines, therefore
 268 * differs in spirit from the above ffz (man ffs).
 269 */
 270static __inline__ int ffs(int x)
 271{
 272        unsigned long i = (unsigned long)x;
 273        return __ilog2(i & -i) + 1;
 274}
 275
 276/*
 277 * fls: find last (most-significant) bit set.
 278 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
 279 */
 280#define fls(x) generic_fls(x)
 281
 282/*
 283 * hweightN: returns the hamming weight (i.e. the number
 284 * of bits set) of a N-bit word
 285 */
 286#define hweight64(x) generic_hweight64(x)
 287#define hweight32(x) generic_hweight32(x)
 288#define hweight16(x) generic_hweight16(x)
 289#define hweight8(x) generic_hweight8(x)
 290
 291extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
 292#define find_first_zero_bit(addr, size) \
 293        find_next_zero_bit((addr), (size), 0)
 294
 295extern unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
 296#define find_first_bit(addr, size) \
 297        find_next_bit((addr), (size), 0)
 298
 299extern unsigned long find_next_zero_le_bit(const unsigned long *addr, unsigned long size, unsigned long offset);
 300#define find_first_zero_le_bit(addr, size) \
 301        find_next_zero_le_bit((addr), (size), 0)
 302
 303static __inline__ int test_le_bit(unsigned long nr, __const__ unsigned long * addr)
 304{
 305        __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
 306        return (ADDR[nr >> 3] >> (nr & 7)) & 1;
 307}
 308
 309/*
 310 * non-atomic versions
 311 */
 312static __inline__ void __set_le_bit(unsigned long nr, unsigned long *addr)
 313{
 314        unsigned char *ADDR = (unsigned char *)addr;
 315
 316        ADDR += nr >> 3;
 317        *ADDR |= 1 << (nr & 0x07);
 318}
 319
 320static __inline__ void __clear_le_bit(unsigned long nr, unsigned long *addr)
 321{
 322        unsigned char *ADDR = (unsigned char *)addr;
 323
 324        ADDR += nr >> 3;
 325        *ADDR &= ~(1 << (nr & 0x07));
 326}
 327
 328static __inline__ int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
 329{
 330        int mask, retval;
 331        unsigned char *ADDR = (unsigned char *)addr;
 332
 333        ADDR += nr >> 3;
 334        mask = 1 << (nr & 0x07);
 335        retval = (mask & *ADDR) != 0;
 336        *ADDR |= mask;
 337        return retval;
 338}
 339
 340static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
 341{
 342        int mask, retval;
 343        unsigned char *ADDR = (unsigned char *)addr;
 344
 345        ADDR += nr >> 3;
 346        mask = 1 << (nr & 0x07);
 347        retval = (mask & *ADDR) != 0;
 348        *ADDR &= ~mask;
 349        return retval;
 350}
 351
 352#define ext2_set_bit(nr,addr) \
 353        __test_and_set_le_bit((nr),(unsigned long*)addr)
 354#define ext2_clear_bit(nr, addr) \
 355        __test_and_clear_le_bit((nr),(unsigned long*)addr)
 356
 357#define ext2_set_bit_atomic(lock, nr, addr)             \
 358        ({                                              \
 359                int ret;                                \
 360                spin_lock(lock);                        \
 361                ret = ext2_set_bit((nr), (addr));       \
 362                spin_unlock(lock);                      \
 363                ret;                                    \
 364        })
 365
 366#define ext2_clear_bit_atomic(lock, nr, addr)           \
 367        ({                                              \
 368                int ret;                                \
 369                spin_lock(lock);                        \
 370                ret = ext2_clear_bit((nr), (addr));     \
 371                spin_unlock(lock);                      \
 372                ret;                                    \
 373        })
 374
 375#define ext2_test_bit(nr, addr)      test_le_bit((nr),(unsigned long*)addr)
 376#define ext2_find_first_zero_bit(addr, size) \
 377        find_first_zero_le_bit((unsigned long*)addr, size)
 378#define ext2_find_next_zero_bit(addr, size, off) \
 379        find_next_zero_le_bit((unsigned long*)addr, size, off)
 380
 381#define minix_test_and_set_bit(nr,addr)         test_and_set_bit(nr,addr)
 382#define minix_set_bit(nr,addr)                  set_bit(nr,addr)
 383#define minix_test_and_clear_bit(nr,addr)       test_and_clear_bit(nr,addr)
 384#define minix_test_bit(nr,addr)                 test_bit(nr,addr)
 385#define minix_find_first_zero_bit(addr,size)    find_first_zero_bit(addr,size)
 386
 387#endif /* __KERNEL__ */
 388#endif /* _PPC64_BITOPS_H */
 389
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.