/*
 * Copyright 1995, Russell King.
 * Various bits and pieces copyrights include:
 *  Linus Torvalds (test_bit).
 * Big endian support: Copyright 2001, Nicolas Pitre
 *  reworked by rmk.
 */

#ifndef _ARM_BITOPS_H
#define _ARM_BITOPS_H

#include <xen/macros.h>

#include <asm/asm_defns.h>

/*
 * Non-atomic bit manipulation.
 *
 * Implemented using atomics to be interrupt safe. Could alternatively
 * implement with local interrupt masking.
 */
#define __set_bit(n,p)            set_bit(n,p)
#define __clear_bit(n,p)          clear_bit(n,p)

#define BITOP_BITS_PER_WORD     32
#define BITOP_MASK(nr)          (1UL << ((nr) % BITOP_BITS_PER_WORD))
#define BITOP_WORD(nr)          ((nr) / BITOP_BITS_PER_WORD)
#define BITS_PER_BYTE           8

#define ADDR (*(volatile int *) addr)
#define CONST_ADDR (*(const volatile int *) addr)

#if defined(CONFIG_ARM_32)
# include <asm/arm32/bitops.h>
#elif defined(CONFIG_ARM_64)
# include <asm/arm64/bitops.h>
#else
# error "unknown ARM variant"
#endif

/*
 * Atomic bitops
 *
 * The helpers below *should* only be used on memory shared between
 * trusted threads or we know the memory cannot be accessed by another
 * thread.
 */

void set_bit(int nr, volatile void *p);
void clear_bit(int nr, volatile void *p);
void change_bit(int nr, volatile void *p);
int test_and_set_bit(int nr, volatile void *p);
int test_and_clear_bit(int nr, volatile void *p);
int test_and_change_bit(int nr, volatile void *p);

void clear_mask16(uint16_t mask, volatile void *p);

/*
 * The helpers below may fail to update the memory if the action takes
 * too long.
 *
 * @max_try: Maximum number of iterations
 *
 * The helpers will return true when the update has succeeded (i.e no
 * timeout) and false if the update has failed.
 */
bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
bool test_and_set_bit_timeout(int nr, volatile void *p,
                              int *oldbit, unsigned int max_try);
bool test_and_clear_bit_timeout(int nr, volatile void *p,
                                int *oldbit, unsigned int max_try);
bool test_and_change_bit_timeout(int nr, volatile void *p,
                                 int *oldbit, unsigned int max_try);
bool clear_mask16_timeout(uint16_t mask, volatile void *p,
                          unsigned int max_try);

/**
 * __test_and_set_bit - Set a bit and return its old value
 * @nr: Bit to set
 * @addr: Address to count from
 *
 * This operation is non-atomic and can be reordered.
 * If two examples of this operation race, one can appear to succeed
 * but actually fail.  You must protect multiple accesses with a lock.
 */
static inline int __test_and_set_bit(int nr, volatile void *addr)
{
        unsigned int mask = BITOP_MASK(nr);
        volatile unsigned int *p =
                ((volatile unsigned int *)addr) + BITOP_WORD(nr);
        unsigned int old = *p;

        *p = old | mask;
        return (old & mask) != 0;
}

/**
 * __test_and_clear_bit - Clear a bit and return its old value
 * @nr: Bit to clear
 * @addr: Address to count from
 *
 * This operation is non-atomic and can be reordered.
 * If two examples of this operation race, one can appear to succeed
 * but actually fail.  You must protect multiple accesses with a lock.
 */
static inline int __test_and_clear_bit(int nr, volatile void *addr)
{
        unsigned int mask = BITOP_MASK(nr);
        volatile unsigned int *p =
                ((volatile unsigned int *)addr) + BITOP_WORD(nr);
        unsigned int old = *p;

        *p = old & ~mask;
        return (old & mask) != 0;
}

/* WARNING: non atomic and it can be reordered! */
static inline int __test_and_change_bit(int nr,
                                            volatile void *addr)
{
        unsigned int mask = BITOP_MASK(nr);
        volatile unsigned int *p =
                ((volatile unsigned int *)addr) + BITOP_WORD(nr);
        unsigned int old = *p;

        *p = old ^ mask;
        return (old & mask) != 0;
}

/**
 * test_bit - Determine whether a bit is set
 * @nr: bit number to test
 * @addr: Address to start counting from
 */
static inline int test_bit(int nr, const volatile void *addr)
{
        const volatile unsigned int *p = (const volatile unsigned int *)addr;
        return 1UL & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD-1)));
}

#define arch_ffs(x)  ((x) ? 1 + __builtin_ctz(x) : 0)
#define arch_ffsl(x) ((x) ? 1 + __builtin_ctzl(x) : 0)
#define arch_fls(x)  ((x) ? 32 - __builtin_clz(x) : 0)
#define arch_flsl(x) ((x) ? BITS_PER_LONG - __builtin_clzl(x) : 0)

/**
 * hweightN - returns the hamming weight of a N-bit word
 * @x: the word to weigh
 *
 * The Hamming Weight of a number is the total number of bits set in it.
 */
#define hweight64(x) generic_hweight64(x)
#define hweight32(x) generic_hweight32(x)
#define hweight16(x) generic_hweight16(x)
#define hweight8(x) generic_hweight8(x)

#endif /* _ARM_BITOPS_H */
/*
 * Local variables:
 * mode: C
 * c-file-style: "BSD"
 * c-basic-offset: 4
 * indent-tabs-mode: nil
 * End:
 */
