diff mbox series

[v3,10/34] xen/riscv: introduce bitops.h

Message ID 841d59c3950970f4937da200cf8f04aa39132e14.1703255175.git.oleksii.kurochko@gmail.com (mailing list archive)
State Superseded
Headers show
Series Enable build of full Xen for RISC-V | expand

Commit Message

Oleksii Kurochko Dec. 22, 2023, 3:12 p.m. UTC
Taken from Linux-6.4.0-rc1

Xen's bitops.h consists of several Linux's headers:
* linux/arch/include/asm/bitops.h:
  * The following function were removed as they aren't used in Xen:
      	* test_and_change_bit
      	* test_and_set_bit_lock
      	* clear_bit_unlock
      	* __clear_bit_unlock
   * The following functions were renamed in the way how they are
     used by common code:
     	* __test_and_set_bit
     	* __test_and_clear_bit
   * The declaration and implementation of the following functios
     were updated to make Xen build happy:
	* clear_bit
	* set_bit
	* __test_and_clear_bit
	* __test_and_set_bit
* linux/include/asm-generic/bitops/find.h ( only few function
  declaration were taken, as implementation will be provided by
  Xen ).
* linux/arch/include/linux/bits.h ( taken only definitions for BIT_MASK,
  BIT_WORD, BITS_PER_BYTE )

Additionaly, the following bit ops are introduced:
* __ffs
* ffsl
* fls
* flsl
* ffs
* ffz
* find_first_bit_set
* hweight64
* test_bit

Some of the introduced bit operations are included in asm-generic,
as they exhibit similarity across multiple architectures.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in V3:
 - update the commit message
 - Introduce the following asm-generic bitops headers:
	create mode 100644 xen/arch/riscv/include/asm/bitops.h
	create mode 100644 xen/include/asm-generic/bitops/bitops-bits.h
	create mode 100644 xen/include/asm-generic/bitops/ffs.h
	create mode 100644 xen/include/asm-generic/bitops/ffz.h
	create mode 100644 xen/include/asm-generic/bitops/find-first-bit-set.h
	create mode 100644 xen/include/asm-generic/bitops/fls.h
	create mode 100644 xen/include/asm-generic/bitops/flsl.h
	create mode 100644 xen/include/asm-generic/bitops/hweight.h
	create mode 100644 xen/include/asm-generic/bitops/test-bit.h
 - switch some bitops functions to asm-generic's versions.
 - re-sync some macros with Linux kernel version mentioned in the commit message.
 - Xen code style fixes.
---
Changes in V2:
 - Nothing changed. Only rebase.
---
 xen/arch/riscv/include/asm/bitops.h           | 267 ++++++++++++++++++
 xen/include/asm-generic/bitops/bitops-bits.h  |  10 +
 xen/include/asm-generic/bitops/ffs.h          |   9 +
 xen/include/asm-generic/bitops/ffz.h          |  13 +
 .../asm-generic/bitops/find-first-bit-set.h   |  17 ++
 xen/include/asm-generic/bitops/fls.h          |  18 ++
 xen/include/asm-generic/bitops/flsl.h         |  10 +
 xen/include/asm-generic/bitops/hweight.h      |  13 +
 xen/include/asm-generic/bitops/test-bit.h     |  16 ++
 9 files changed, 373 insertions(+)
 create mode 100644 xen/arch/riscv/include/asm/bitops.h
 create mode 100644 xen/include/asm-generic/bitops/bitops-bits.h
 create mode 100644 xen/include/asm-generic/bitops/ffs.h
 create mode 100644 xen/include/asm-generic/bitops/ffz.h
 create mode 100644 xen/include/asm-generic/bitops/find-first-bit-set.h
 create mode 100644 xen/include/asm-generic/bitops/fls.h
 create mode 100644 xen/include/asm-generic/bitops/flsl.h
 create mode 100644 xen/include/asm-generic/bitops/hweight.h
 create mode 100644 xen/include/asm-generic/bitops/test-bit.h

Comments

Jan Beulich Jan. 15, 2024, 4:44 p.m. UTC | #1
On 22.12.2023 16:12, Oleksii Kurochko wrote:
> --- /dev/null
> +++ b/xen/arch/riscv/include/asm/bitops.h
> @@ -0,0 +1,267 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2012 Regents of the University of California */
> +
> +#ifndef _ASM_RISCV_BITOPS_H
> +#define _ASM_RISCV_BITOPS_H
> +
> +#include <asm/system.h>
> +
> +#include <asm-generic/bitops/bitops-bits.h>
> +
> +/* Based on linux/arch/include/linux/bits.h */
> +
> +#define BIT_MASK(nr)        (1UL << ((nr) % BITS_PER_LONG))
> +#define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)
> +
> +#define __set_bit(n,p)      set_bit(n,p)
> +#define __clear_bit(n,p)    clear_bit(n,p)
> +
> +/* Based on linux/arch/include/asm/bitops.h */
> +
> +#if ( BITS_PER_LONG == 64 )
> +#define __AMO(op)   "amo" #op ".d"
> +#elif ( BITS_PER_LONG == 32 )
> +#define __AMO(op)   "amo" #op ".w"
> +#else
> +#error "Unexpected BITS_PER_LONG"
> +#endif
> +
> +#define __test_and_op_bit_ord(op, mod, nr, addr, ord)		\
> +({								\
> +    unsigned long __res, __mask;				\
> +    __mask = BIT_MASK(nr);					\
> +    __asm__ __volatile__ (					\
> +        __AMO(op) #ord " %0, %2, %1"			\
> +        : "=r" (__res), "+A" (addr[BIT_WORD(nr)])	\
> +        : "r" (mod(__mask))				\
> +        : "memory");					\
> +    ((__res & __mask) != 0);				\
> +})

Despite the taking from Linux I think the overall result wants to be
consistent formatting-wise: You switched to blank indentation (which
is fine), but you left tabs as padding for the line continuation
characters.

> +#define __op_bit_ord(op, mod, nr, addr, ord)			\
> +    __asm__ __volatile__ (					\
> +        __AMO(op) #ord " zero, %1, %0"			\
> +        : "+A" (addr[BIT_WORD(nr)])			\
> +        : "r" (mod(BIT_MASK(nr)))			\
> +        : "memory");
> +
> +#define __test_and_op_bit(op, mod, nr, addr) 			\

(At least) here you even use a mix.

> +    __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
> +#define __op_bit(op, mod, nr, addr)				\
> +    __op_bit_ord(op, mod, nr, addr, )
> +
> +/* Bitmask modifiers */
> +#define __NOP(x)	(x)
> +#define __NOT(x)	(~(x))
> +
> +/**
> + * __test_and_set_bit - Set a bit and return its old value
> + * @nr: Bit to set
> + * @addr: Address to count from
> + *
> + * This operation may be reordered on other architectures than x86.
> + */
> +static inline int __test_and_set_bit(int nr, volatile void *p)
> +{
> +    volatile uint32_t *addr = p;
> +
> +    return __test_and_op_bit(or, __NOP, nr, addr);
> +}
> +
> +/**
> + * __test_and_clear_bit - Clear a bit and return its old value
> + * @nr: Bit to clear
> + * @addr: Address to count from
> + *
> + * This operation can be reordered on other architectures other than x86.
> + */
> +static inline int __test_and_clear_bit(int nr, volatile void *p)
> +{
> +    volatile uint32_t *addr = p;
> +
> +    return __test_and_op_bit(and, __NOT, nr, addr);
> +}
> +
> +/**
> + * set_bit - Atomically set a bit in memory
> + * @nr: the bit to set
> + * @addr: the address to start counting from
> + *
> + * Note: there are no guarantees that this function will not be reordered
> + * on non x86 architectures, so if you are writing portable code,
> + * make sure not to rely on its reordering guarantees.
> + *
> + * Note that @nr may be almost arbitrarily large; this function is not
> + * restricted to acting on a single-word quantity.
> + */
> +static inline void set_bit(int nr, volatile void *p)
> +{
> +    volatile uint32_t *addr = p;
> +
> +    __op_bit(or, __NOP, nr, addr);
> +}
> +
> +/**
> + * clear_bit - Clears a bit in memory
> + * @nr: Bit to clear
> + * @addr: Address to start counting from
> + *
> + * Note: there are no guarantees that this function will not be reordered
> + * on non x86 architectures, so if you are writing portable code,
> + * make sure not to rely on its reordering guarantees.
> + */
> +static inline void clear_bit(int nr, volatile void *p)
> +{
> +    volatile uint32_t *addr = p;
> +
> +    __op_bit(and, __NOT, nr, addr);
> +}
> +
> +#undef __test_and_op_bit
> +#undef __op_bit
> +#undef __NOP
> +#undef __NOT
> +#undef __AMO
> +
> +#define test_and_set_bit   __test_and_set_bit
> +#define test_and_clear_bit __test_and_clear_bit

I realize test-and-change have no present users, despite being made
available by Arm and x86, but I think they would better be provided
right away, rather than someone introducing a use then needing to
fiddle with RISC-V (and apparently also PPC) code.

I'm also puzzled by this aliasing: Aren't there cheaper non-atomic
insn forms that could be used for the double-underscore-prefixed
variants?

> +/* Based on linux/include/asm-generic/bitops/find.h */
> +
> +#ifndef find_next_bit

What is this to guard against?

> +/**
> + * find_next_bit - find the next set bit in a memory region
> + * @addr: The address to base the search on
> + * @offset: The bitnumber to start searching at
> + * @size: The bitmap size in bits
> + */
> +extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
> +        size, unsigned long offset);
> +#endif
> +
> +#ifndef find_next_zero_bit
> +/**
> + * find_next_zero_bit - find the next cleared bit in a memory region
> + * @addr: The address to base the search on
> + * @offset: The bitnumber to start searching at
> + * @size: The bitmap size in bits
> + */
> +extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
> +        long size, unsigned long offset);
> +#endif
> +
> +/**
> + * find_first_bit - find the first set bit in a memory region
> + * @addr: The address to start the search at
> + * @size: The maximum size to search
> + *
> + * Returns the bit number of the first set bit.
> + */
> +extern unsigned long find_first_bit(const unsigned long *addr,
> +                    unsigned long size);
> +
> +/**
> + * find_first_zero_bit - find the first cleared bit in a memory region
> + * @addr: The address to start the search at
> + * @size: The maximum size to search
> + *
> + * Returns the bit number of the first cleared bit.
> + */
> +extern unsigned long find_first_zero_bit(const unsigned long *addr,
> +                     unsigned long size);
> +
> +/**
> + * ffs - find first bit in word.
> + * @word: The word to search
> + *
> + * Returns 0 if no bit exists, otherwise returns 1-indexed bit location.
> + */
> +static inline unsigned long __ffs(unsigned long word)
> +{
> +    int num = 0;

I understand it's this way in Linux, so there may be reasons to keep it
like that. Generally though we'd prefer unsigned here, and the type of
a variable used for the return value of a function would also better be
in sync with the function's return type (which I don't think needs to
be "unsigned long" either; "unsigned int" would apparently suffice).

> +#if BITS_PER_LONG == 64
> +    if ((word & 0xffffffff) == 0) {
> +        num += 32;
> +        word >>= 32;
> +    }

You're ending up with neither Xen nor Linux style this way. May I
suggest to settle on either?

> +#endif
> +    if ((word & 0xffff) == 0) {
> +        num += 16;
> +        word >>= 16;
> +    }
> +    if ((word & 0xff) == 0) {
> +        num += 8;
> +        word >>= 8;
> +    }
> +    if ((word & 0xf) == 0) {
> +        num += 4;
> +        word >>= 4;
> +    }
> +    if ((word & 0x3) == 0) {
> +        num += 2;
> +        word >>= 2;
> +    }
> +    if ((word & 0x1) == 0)
> +        num += 1;
> +    return num;
> +}
> +
> +/**
> + * ffsl - find first bit in long.
> + * @word: The word to search
> + *
> + * Returns 0 if no bit exists, otherwise returns 1-indexed bit location.
> + */
> +static inline unsigned int ffsl(unsigned long word)
> +{
> +    int num = 1;
> +
> +    if (!word)
> +        return 0;
> +
> +#if BITS_PER_LONG == 64
> +    if ((word & 0xffffffff) == 0) {
> +        num += 32;
> +        word >>= 32;
> +    }
> +#endif
> +    if ((word & 0xffff) == 0) {
> +        num += 16;
> +        word >>= 16;
> +    }
> +    if ((word & 0xff) == 0) {
> +        num += 8;
> +        word >>= 8;
> +    }
> +    if ((word & 0xf) == 0) {
> +        num += 4;
> +        word >>= 4;
> +    }
> +    if ((word & 0x3) == 0) {
> +        num += 2;
> +        word >>= 2;
> +    }
> +    if ((word & 0x1) == 0)
> +        num += 1;
> +    return num;
> +}

What's RISC-V-specific about the above? IOW why ...

> +#include <asm-generic/bitops/fls.h>
> +#include <asm-generic/bitops/flsl.h>
> +#include <asm-generic/bitops/ffs.h>
> +#include <asm-generic/bitops/ffz.h>

... can't those two also come from respective generic headers?

> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/bitops-bits.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
> +#define _ASM_GENERIC_BITOPS_BITS_H_
> +
> +#define BITOP_BITS_PER_WORD     32
> +#define BITOP_MASK(nr)          (1UL << ((nr) % BITOP_BITS_PER_WORD))

Why 1UL and not just 1U, when bits per word is 32?

> +#define BITOP_WORD(nr)          ((nr) / BITOP_BITS_PER_WORD)
> +#define BITS_PER_BYTE           8
> +
> +#endif /* _ASM_GENERIC_BITOPS_BITS_H_ */
> \ No newline at end of file

Nit: I did comment on such before (and there's at least one more
further down).

> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/ffs.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_FFS_H_
> +#define _ASM_GENERIC_BITOPS_FFS_H_
> +
> +#include <xen/macros.h>
> +
> +#define ffs(x) ({ unsigned int t_ = (x); fls(ISOLATE_LSB(t_)); })
> +
> +#endif /* _ASM_GENERIC_BITOPS_FFS_H_ */
> diff --git a/xen/include/asm-generic/bitops/ffz.h b/xen/include/asm-generic/bitops/ffz.h
> new file mode 100644
> index 0000000000..92c35455d5
> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/ffz.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_FFZ_H_
> +#define _ASM_GENERIC_BITOPS_FFZ_H_
> +
> +/*
> + * ffz - find first zero in word.
> + * @word: The word to search
> + *
> + * Undefined if no zero exists, so code should check against ~0UL first.
> + */
> +#define ffz(x)  __ffs(~(x))

For a generic header I'd like to see consistency: ffz() may expand to
ffs(), and __ffz() may expand to __ffs(). A mix like you have it above
wants at least explaining in the description. (I don't understand
anyway why both ffs() and __ffs() would be needed. We don't have any
__ffs() on x86 afaics.)

> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/find-first-bit-set.h

This file name, if it really needs to be this long, wants to match ...

> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_
> +#define _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_
> +
> +/**
> + * find_first_set_bit - find the first set bit in @word
> + * @word: the word to search
> + *
> + * Returns the bit-number of the first set bit (first bit being 0).
> + * The input must *not* be zero.
> + */
> +static inline unsigned int find_first_set_bit(unsigned long word)

... the function implemented herein.

> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/fls.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_FLS_H_
> +#define _ASM_GENERIC_BITOPS_FLS_H_
> +
> +/**
> + * fls - find last (most-significant) bit set
> + * @x: the word to search
> + *
> + * This is defined the same way as ffs.
> + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
> + */
> +
> +static inline int fls(unsigned int x)
> +{
> +    return generic_fls(x);
> +}

Seing this, why would e.g. ffsl() not use generic_ffsl() then?

> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/hweight.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
> +#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
> +
> +/*
> + * 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)
> +
> +#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */

Do we really need this? An arch not having suitable insns (RISC-V has,
iirc) can easily have this one #define (or the ip to four ones when
also covering the other widths) in its asm header.

> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/test-bit.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_TESTBIT_H_
> +#define _ASM_GENERIC_BITOPS_TESTBIT_H_
> +
> +/**
> + * 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 = addr;

With BITOP_BITS_PER_WORD I think you really mean uint32_t here.
Also you want to make sure asm-generic/bitops/bitops-bits.h is
really in use here, or else an arch overriding / not using that
header may end up screwed.

Jan

> +    return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD - 1)));
> +}
> +
> +#endif /* _ASM_GENERIC_BITOPS_TESTBIT_H_ */
> \ No newline at end of file
Oleksii Kurochko Jan. 16, 2024, 1:06 p.m. UTC | #2
On Mon, 2024-01-15 at 17:44 +0100, Jan Beulich wrote:
> On 22.12.2023 16:12, Oleksii Kurochko wrote:
> > --- /dev/null
> > +++ b/xen/arch/riscv/include/asm/bitops.h
> > @@ -0,0 +1,267 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/* Copyright (C) 2012 Regents of the University of California */
> > +
> > +#ifndef _ASM_RISCV_BITOPS_H
> > +#define _ASM_RISCV_BITOPS_H
> > +
> > +#include <asm/system.h>
> > +
> > +#include <asm-generic/bitops/bitops-bits.h>
> > +
> > +/* Based on linux/arch/include/linux/bits.h */
> > +
> > +#define BIT_MASK(nr)        (1UL << ((nr) % BITS_PER_LONG))
> > +#define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)
> > +
> > +#define __set_bit(n,p)      set_bit(n,p)
> > +#define __clear_bit(n,p)    clear_bit(n,p)
> > +
> > +/* Based on linux/arch/include/asm/bitops.h */
> > +
> > +#if ( BITS_PER_LONG == 64 )
> > +#define __AMO(op)   "amo" #op ".d"
> > +#elif ( BITS_PER_LONG == 32 )
> > +#define __AMO(op)   "amo" #op ".w"
> > +#else
> > +#error "Unexpected BITS_PER_LONG"
> > +#endif
> > +
> > +#define __test_and_op_bit_ord(op, mod, nr, addr, ord)		\
> > +({								\
> > +    unsigned long __res, __mask;				\
> > +    __mask = BIT_MASK(nr);					\
> > +    __asm__ __volatile__ (					\
> > +        __AMO(op) #ord " %0, %2, %1"			\
> > +        : "=r" (__res), "+A" (addr[BIT_WORD(nr)])	\
> > +        : "r" (mod(__mask))				\
> > +        : "memory");					\
> > +    ((__res & __mask) != 0);				\
> > +})
> 
> Despite the taking from Linux I think the overall result wants to be
> consistent formatting-wise: You switched to blank indentation (which
> is fine), but you left tabs as padding for the line continuation
> characters.
I think it is because of my IDE. I will be consistent in next patch
version.

Thanks.

> 
> > +#define __op_bit_ord(op, mod, nr, addr, ord)			\
> > +    __asm__ __volatile__ (					\
> > +        __AMO(op) #ord " zero, %1, %0"			\
> > +        : "+A" (addr[BIT_WORD(nr)])			\
> > +        : "r" (mod(BIT_MASK(nr)))			\
> > +        : "memory");
> > +
> > +#define __test_and_op_bit(op, mod, nr, addr) 			\
> 
> (At least) here you even use a mix.
> 
> > +    __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
> > +#define __op_bit(op, mod, nr, addr)				\
> > +    __op_bit_ord(op, mod, nr, addr, )
> > +
> > +/* Bitmask modifiers */
> > +#define __NOP(x)	(x)
> > +#define __NOT(x)	(~(x))
> > +
> > +/**
> > + * __test_and_set_bit - Set a bit and return its old value
> > + * @nr: Bit to set
> > + * @addr: Address to count from
> > + *
> > + * This operation may be reordered on other architectures than
> > x86.
> > + */
> > +static inline int __test_and_set_bit(int nr, volatile void *p)
> > +{
> > +    volatile uint32_t *addr = p;
> > +
> > +    return __test_and_op_bit(or, __NOP, nr, addr);
> > +}
> > +
> > +/**
> > + * __test_and_clear_bit - Clear a bit and return its old value
> > + * @nr: Bit to clear
> > + * @addr: Address to count from
> > + *
> > + * This operation can be reordered on other architectures other
> > than x86.
> > + */
> > +static inline int __test_and_clear_bit(int nr, volatile void *p)
> > +{
> > +    volatile uint32_t *addr = p;
> > +
> > +    return __test_and_op_bit(and, __NOT, nr, addr);
> > +}
> > +
> > +/**
> > + * set_bit - Atomically set a bit in memory
> > + * @nr: the bit to set
> > + * @addr: the address to start counting from
> > + *
> > + * Note: there are no guarantees that this function will not be
> > reordered
> > + * on non x86 architectures, so if you are writing portable code,
> > + * make sure not to rely on its reordering guarantees.
> > + *
> > + * Note that @nr may be almost arbitrarily large; this function is
> > not
> > + * restricted to acting on a single-word quantity.
> > + */
> > +static inline void set_bit(int nr, volatile void *p)
> > +{
> > +    volatile uint32_t *addr = p;
> > +
> > +    __op_bit(or, __NOP, nr, addr);
> > +}
> > +
> > +/**
> > + * clear_bit - Clears a bit in memory
> > + * @nr: Bit to clear
> > + * @addr: Address to start counting from
> > + *
> > + * Note: there are no guarantees that this function will not be
> > reordered
> > + * on non x86 architectures, so if you are writing portable code,
> > + * make sure not to rely on its reordering guarantees.
> > + */
> > +static inline void clear_bit(int nr, volatile void *p)
> > +{
> > +    volatile uint32_t *addr = p;
> > +
> > +    __op_bit(and, __NOT, nr, addr);
> > +}
> > +
> > +#undef __test_and_op_bit
> > +#undef __op_bit
> > +#undef __NOP
> > +#undef __NOT
> > +#undef __AMO
> > +
> > +#define test_and_set_bit   __test_and_set_bit
> > +#define test_and_clear_bit __test_and_clear_bit
> 
> I realize test-and-change have no present users, despite being made
> available by Arm and x86, but I think they would better be provided
> right away, rather than someone introducing a use then needing to
> fiddle with RISC-V (and apparently also PPC) code.
Sure, it makes sense. I'll add test-and-change too.

> 
> I'm also puzzled by this aliasing: Aren't there cheaper non-atomic
> insn forms that could be used for the double-underscore-prefixed
> variants?
It will be cheaper, but I assume that this API should be safe in the
case of SMP where different CPUs can access the same variable or
similar cases with simultaneous access to the variable.

> 
> > +/* Based on linux/include/asm-generic/bitops/find.h */
> > +
> > +#ifndef find_next_bit
> 
> What is this to guard against?
This was copied from Linux, but in case of Xen it can be dropped.

> 
> > +/**
> > + * find_next_bit - find the next set bit in a memory region
> > + * @addr: The address to base the search on
> > + * @offset: The bitnumber to start searching at
> > + * @size: The bitmap size in bits
> > + */
> > +extern unsigned long find_next_bit(const unsigned long *addr,
> > unsigned long
> > +        size, unsigned long offset);
> > +#endif
> > +
> > +#ifndef find_next_zero_bit
> > +/**
> > + * find_next_zero_bit - find the next cleared bit in a memory
> > region
> > + * @addr: The address to base the search on
> > + * @offset: The bitnumber to start searching at
> > + * @size: The bitmap size in bits
> > + */
> > +extern unsigned long find_next_zero_bit(const unsigned long *addr,
> > unsigned
> > +        long size, unsigned long offset);
> > +#endif
> > +
> > +/**
> > + * find_first_bit - find the first set bit in a memory region
> > + * @addr: The address to start the search at
> > + * @size: The maximum size to search
> > + *
> > + * Returns the bit number of the first set bit.
> > + */
> > +extern unsigned long find_first_bit(const unsigned long *addr,
> > +                    unsigned long size);
> > +
> > +/**
> > + * find_first_zero_bit - find the first cleared bit in a memory
> > region
> > + * @addr: The address to start the search at
> > + * @size: The maximum size to search
> > + *
> > + * Returns the bit number of the first cleared bit.
> > + */
> > +extern unsigned long find_first_zero_bit(const unsigned long
> > *addr,
> > +                     unsigned long size);
> > +
> > +/**
> > + * ffs - find first bit in word.
> > + * @word: The word to search
> > + *
> > + * Returns 0 if no bit exists, otherwise returns 1-indexed bit
> > location.
> > + */
> > +static inline unsigned long __ffs(unsigned long word)
> > +{
> > +    int num = 0;
> 
> I understand it's this way in Linux, so there may be reasons to keep
> it
> like that. Generally though we'd prefer unsigned here, and the type
> of
> a variable used for the return value of a function would also better
> be
> in sync with the function's return type (which I don't think needs to
> be "unsigned long" either; "unsigned int" would apparently suffice).
> 
> > +#if BITS_PER_LONG == 64
> > +    if ((word & 0xffffffff) == 0) {
> > +        num += 32;
> > +        word >>= 32;
> > +    }
> 
> You're ending up with neither Xen nor Linux style this way. May I
> suggest to settle on either?

Will it fine to rework header from Linux to Xen style? Does it make
sense?
I think this file can be reworked to Xen style as I don't expect that
it will be changed since it will be merged.

> 
> > +#endif
> > +    if ((word & 0xffff) == 0) {
> > +        num += 16;
> > +        word >>= 16;
> > +    }
> > +    if ((word & 0xff) == 0) {
> > +        num += 8;
> > +        word >>= 8;
> > +    }
> > +    if ((word & 0xf) == 0) {
> > +        num += 4;
> > +        word >>= 4;
> > +    }
> > +    if ((word & 0x3) == 0) {
> > +        num += 2;
> > +        word >>= 2;
> > +    }
> > +    if ((word & 0x1) == 0)
> > +        num += 1;
> > +    return num;
> > +}
> > +
> > +/**
> > + * ffsl - find first bit in long.
> > + * @word: The word to search
> > + *
> > + * Returns 0 if no bit exists, otherwise returns 1-indexed bit
> > location.
> > + */
> > +static inline unsigned int ffsl(unsigned long word)
> > +{
> > +    int num = 1;
> > +
> > +    if (!word)
> > +        return 0;
> > +
> > +#if BITS_PER_LONG == 64
> > +    if ((word & 0xffffffff) == 0) {
> > +        num += 32;
> > +        word >>= 32;
> > +    }
> > +#endif
> > +    if ((word & 0xffff) == 0) {
> > +        num += 16;
> > +        word >>= 16;
> > +    }
> > +    if ((word & 0xff) == 0) {
> > +        num += 8;
> > +        word >>= 8;
> > +    }
> > +    if ((word & 0xf) == 0) {
> > +        num += 4;
> > +        word >>= 4;
> > +    }
> > +    if ((word & 0x3) == 0) {
> > +        num += 2;
> > +        word >>= 2;
> > +    }
> > +    if ((word & 0x1) == 0)
> > +        num += 1;
> > +    return num;
> > +}
> 
> What's RISC-V-specific about the above? IOW why ...
> 
> > +#include <asm-generic/bitops/fls.h>
> > +#include <asm-generic/bitops/flsl.h>
> > +#include <asm-generic/bitops/ffs.h>
> > +#include <asm-generic/bitops/ffz.h>
> 
> ... can't those two also come from respective generic headers?
Sure it can. Originally, I don't introduce it as generic headers
because RISC-V is only one who isn using C generic version.

I found that there is already present such generic function in
xen/bitops.h. I think it makes sense to re-use them.

> 
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/bitops-bits.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
> > +#define _ASM_GENERIC_BITOPS_BITS_H_
> > +
> > +#define BITOP_BITS_PER_WORD     32
> > +#define BITOP_MASK(nr)          (1UL << ((nr) %
> > BITOP_BITS_PER_WORD))
> 
> Why 1UL and not just 1U, when bits per word is 32?
There is no specific reason, should 1U. ( I originally used
BITOPS_BITS_PER_LONG ) and with introduction of asm-generic bitops
decided to follow what other archs provide.

Regarding to the second part of the question, I don't understand it
fully. Considering BITOP_BIT_PER_WORD definition for other archs ( ARM
and PPC ) it is expected that word is 32 bits.

> 
> > +#define BITOP_WORD(nr)          ((nr) / BITOP_BITS_PER_WORD)
> > +#define BITS_PER_BYTE           8
> > +
> > +#endif /* _ASM_GENERIC_BITOPS_BITS_H_ */
> > \ No newline at end of file
> 
> Nit: I did comment on such before (and there's at least one more
> further down).
Thanks.
I'll add a newline.

> 
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/ffs.h
> > @@ -0,0 +1,9 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_FFS_H_
> > +#define _ASM_GENERIC_BITOPS_FFS_H_
> > +
> > +#include <xen/macros.h>
> > +
> > +#define ffs(x) ({ unsigned int t_ = (x); fls(ISOLATE_LSB(t_)); })
> > +
> > +#endif /* _ASM_GENERIC_BITOPS_FFS_H_ */
> > diff --git a/xen/include/asm-generic/bitops/ffz.h
> > b/xen/include/asm-generic/bitops/ffz.h
> > new file mode 100644
> > index 0000000000..92c35455d5
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/ffz.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_FFZ_H_
> > +#define _ASM_GENERIC_BITOPS_FFZ_H_
> > +
> > +/*
> > + * ffz - find first zero in word.
> > + * @word: The word to search
> > + *
> > + * Undefined if no zero exists, so code should check against ~0UL
> > first.
> > + */
> > +#define ffz(x)  __ffs(~(x))
> 
> For a generic header I'd like to see consistency: ffz() may expand to
> ffs(), and __ffz() may expand to __ffs(). A mix like you have it
> above
> wants at least explaining in the description. (I don't understand
> anyway why both ffs() and __ffs() would be needed. We don't have any
> __ffs() on x86 afaics.)
Then it looks to me that ffs() should be used instead.
ffz() was defined with __ffs() because Arm and PPC are defined so.
> 
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/find-first-bit-set.h
> 
> This file name, if it really needs to be this long, wants to match
> ...
> 
> > @@ -0,0 +1,17 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_
> > +#define _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_
> > +
> > +/**
> > + * find_first_set_bit - find the first set bit in @word
> > + * @word: the word to search
> > + *
> > + * Returns the bit-number of the first set bit (first bit being
> > 0).
> > + * The input must *not* be zero.
> > + */
> > +static inline unsigned int find_first_set_bit(unsigned long word)
> 
> ... the function implemented herein.
Thanks. I'll update the file name.
> 
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/fls.h
> > @@ -0,0 +1,18 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_FLS_H_
> > +#define _ASM_GENERIC_BITOPS_FLS_H_
> > +
> > +/**
> > + * fls - find last (most-significant) bit set
> > + * @x: the word to search
> > + *
> > + * This is defined the same way as ffs.
> > + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
> > + */
> > +
> > +static inline int fls(unsigned int x)
> > +{
> > +    return generic_fls(x);
> > +}
> 
> Seing this, why would e.g. ffsl() not use generic_ffsl() then?
> 
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/hweight.h
> > @@ -0,0 +1,13 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
> > +#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
> > +
> > +/*
> > + * 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)
> > +
> > +#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
> 
> Do we really need this? An arch not having suitable insns (RISC-V
> has,
> iirc) can easily have this one #define (or the ip to four ones when
> also covering the other widths) in its asm header.
> 
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/test-bit.h
> > @@ -0,0 +1,16 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_TESTBIT_H_
> > +#define _ASM_GENERIC_BITOPS_TESTBIT_H_
> > +
> > +/**
> > + * 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 = addr;
> 
> With BITOP_BITS_PER_WORD I think you really mean uint32_t here.
Isn't it the same: 'unsigned int' and 'uint32_t'?

> Also you want to make sure asm-generic/bitops/bitops-bits.h is
> really in use here, or else an arch overriding / not using that
> header may end up screwed.
I am not really understand what do you mean. Could you please explain a
little bit more.

~ Oleksii
> 
> Jan
> 
> > +    return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD -
> > 1)));
> > +}
> > +
> > +#endif /* _ASM_GENERIC_BITOPS_TESTBIT_H_ */
> > \ No newline at end of file
>
Jan Beulich Jan. 16, 2024, 1:24 p.m. UTC | #3
On 16.01.2024 14:06, Oleksii wrote:
> On Mon, 2024-01-15 at 17:44 +0100, Jan Beulich wrote:
>> On 22.12.2023 16:12, Oleksii Kurochko wrote:
>>> +#define test_and_set_bit   __test_and_set_bit
>>> +#define test_and_clear_bit __test_and_clear_bit
>>
>> I realize test-and-change have no present users, despite being made
>> available by Arm and x86, but I think they would better be provided
>> right away, rather than someone introducing a use then needing to
>> fiddle with RISC-V (and apparently also PPC) code.
> Sure, it makes sense. I'll add test-and-change too.
> 
>> I'm also puzzled by this aliasing: Aren't there cheaper non-atomic
>> insn forms that could be used for the double-underscore-prefixed
>> variants?
> It will be cheaper, but I assume that this API should be safe in the
> case of SMP where different CPUs can access the same variable or
> similar cases with simultaneous access to the variable.

Of course, that's what test_and_...() are for. __test_and_...() are
for cases where there's no concurrency, when hence the cheaper forms
can be used. Thus my asking about the aliasing done above.

>>> +#if BITS_PER_LONG == 64
>>> +    if ((word & 0xffffffff) == 0) {
>>> +        num += 32;
>>> +        word >>= 32;
>>> +    }
>>
>> You're ending up with neither Xen nor Linux style this way. May I
>> suggest to settle on either?
> 
> Will it fine to rework header from Linux to Xen style? Does it make
> sense?
> I think this file can be reworked to Xen style as I don't expect that
> it will be changed since it will be merged.

You may keep Linux style or fully switch to Xen style - which one is
largely up to you. All I'm asking is to avoid introducing further
mixed-style source files.

>>> --- /dev/null
>>> +++ b/xen/include/asm-generic/bitops/bitops-bits.h
>>> @@ -0,0 +1,10 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
>>> +#define _ASM_GENERIC_BITOPS_BITS_H_
>>> +
>>> +#define BITOP_BITS_PER_WORD     32
>>> +#define BITOP_MASK(nr)          (1UL << ((nr) %
>>> BITOP_BITS_PER_WORD))
>>
>> Why 1UL and not just 1U, when bits per word is 32?
> There is no specific reason, should 1U. ( I originally used
> BITOPS_BITS_PER_LONG ) and with introduction of asm-generic bitops
> decided to follow what other archs provide.
> 
> Regarding to the second part of the question, I don't understand it
> fully. Considering BITOP_BIT_PER_WORD definition for other archs ( ARM
> and PPC ) it is expected that word is 32 bits.

The 2nd part was explaining why I'm asking. It wasn't another question.

>>> --- /dev/null
>>> +++ b/xen/include/asm-generic/bitops/test-bit.h
>>> @@ -0,0 +1,16 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +#ifndef _ASM_GENERIC_BITOPS_TESTBIT_H_
>>> +#define _ASM_GENERIC_BITOPS_TESTBIT_H_
>>> +
>>> +/**
>>> + * 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 = addr;
>>
>> With BITOP_BITS_PER_WORD I think you really mean uint32_t here.
> Isn't it the same: 'unsigned int' and 'uint32_t'?

No, or else there wouldn't have been a need to introduce uint<N>_t (and
others) in C99. It just so happens that right now all architectures Xen
can be built for have sizeof(int) == 4 and CHAR_BITS == 8. In an arch-
specific header I would see this as less of an issue, but in a generic
header we'd better avoid encoding wrong assumptions. The one assumption
we generally make is that sizeof(int) >= 4 and CHAR_BITS >= 8 (albeit I
bet really in various places we assume CHAR_BITS == 8).

>> Also you want to make sure asm-generic/bitops/bitops-bits.h is
>> really in use here, or else an arch overriding / not using that
>> header may end up screwed.
> I am not really understand what do you mean. Could you please explain a
> little bit more.

Whichever type you use here, it needs to be in sync with
BITOP_BITS_PER_WORD. Hence you want to include the _local_ bitops-bits.h
here, such that in case of an inconsistent override by an arch the
compiler would complain about the two differring #define-s. (IOW an
arch overriding BITOP_BITS_PER_WORD cannot re-use this header as-is.)

The same may, btw, be true for others of the new headers you add - the
same #include would therefore be needed there as well.

Jan
Oleksii Kurochko Jan. 17, 2024, 11:13 a.m. UTC | #4
On Tue, 2024-01-16 at 14:24 +0100, Jan Beulich wrote:
> On 16.01.2024 14:06, Oleksii wrote:
> > On Mon, 2024-01-15 at 17:44 +0100, Jan Beulich wrote:
> > > On 22.12.2023 16:12, Oleksii Kurochko wrote:
> > > > +#define test_and_set_bit   __test_and_set_bit
> > > > +#define test_and_clear_bit __test_and_clear_bit
> > > 
> > > I realize test-and-change have no present users, despite being
> > > made
> > > available by Arm and x86, but I think they would better be
> > > provided
> > > right away, rather than someone introducing a use then needing to
> > > fiddle with RISC-V (and apparently also PPC) code.
> > Sure, it makes sense. I'll add test-and-change too.
> > 
> > > I'm also puzzled by this aliasing: Aren't there cheaper non-
> > > atomic
> > > insn forms that could be used for the double-underscore-prefixed
> > > variants?
> > It will be cheaper, but I assume that this API should be safe in
> > the
> > case of SMP where different CPUs can access the same variable or
> > similar cases with simultaneous access to the variable.
> 
> Of course, that's what test_and_...() are for. __test_and_...() are
> for cases where there's no concurrency, when hence the cheaper forms
> can be used. Thus my asking about the aliasing done above.
Then it makes sense to update __test_and...() to use non-atomic insn.
I'll do that in the next patch version.

Thanks for explanation.

> 
> > > > +#if BITS_PER_LONG == 64
> > > > +    if ((word & 0xffffffff) == 0) {
> > > > +        num += 32;
> > > > +        word >>= 32;
> > > > +    }
> > > 
> > > You're ending up with neither Xen nor Linux style this way. May I
> > > suggest to settle on either?
> > 
> > Will it fine to rework header from Linux to Xen style? Does it make
> > sense?
> > I think this file can be reworked to Xen style as I don't expect
> > that
> > it will be changed since it will be merged.
> 
> You may keep Linux style or fully switch to Xen style - which one is
> largely up to you. All I'm asking is to avoid introducing further
> mixed-style source files.
I'll be consistent in code style.

> 
> > > > --- /dev/null
> > > > +++ b/xen/include/asm-generic/bitops/bitops-bits.h
> > > > @@ -0,0 +1,10 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
> > > > +#define _ASM_GENERIC_BITOPS_BITS_H_
> > > > +
> > > > +#define BITOP_BITS_PER_WORD     32
> > > > +#define BITOP_MASK(nr)          (1UL << ((nr) %
> > > > BITOP_BITS_PER_WORD))
> > > 
> > > Why 1UL and not just 1U, when bits per word is 32?
> > There is no specific reason, should 1U. ( I originally used
> > BITOPS_BITS_PER_LONG ) and with introduction of asm-generic bitops
> > decided to follow what other archs provide.
> > 
> > Regarding to the second part of the question, I don't understand it
> > fully. Considering BITOP_BIT_PER_WORD definition for other archs (
> > ARM
> > and PPC ) it is expected that word is 32 bits.
> 
> The 2nd part was explaining why I'm asking. It wasn't another
> question.
> 
> > > > --- /dev/null
> > > > +++ b/xen/include/asm-generic/bitops/test-bit.h
> > > > @@ -0,0 +1,16 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +#ifndef _ASM_GENERIC_BITOPS_TESTBIT_H_
> > > > +#define _ASM_GENERIC_BITOPS_TESTBIT_H_
> > > > +
> > > > +/**
> > > > + * 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 = addr;
> > > 
> > > With BITOP_BITS_PER_WORD I think you really mean uint32_t here.
> > Isn't it the same: 'unsigned int' and 'uint32_t'?
> 
> No, or else there wouldn't have been a need to introduce uint<N>_t
> (and
> others) in C99. It just so happens that right now all architectures
> Xen
> can be built for have sizeof(int) == 4 and CHAR_BITS == 8. In an
> arch-
> specific header I would see this as less of an issue, but in a
> generic
> header we'd better avoid encoding wrong assumptions. The one
> assumption
> we generally make is that sizeof(int) >= 4 and CHAR_BITS >= 8 (albeit
> I
> bet really in various places we assume CHAR_BITS == 8).
In this case we have to switch to uint<N>_t.
Thanks for the explanation. I'll update this part of code in the next
patch version.

> 
> > > Also you want to make sure asm-generic/bitops/bitops-bits.h is
> > > really in use here, or else an arch overriding / not using that
> > > header may end up screwed.
> > I am not really understand what do you mean. Could you please
> > explain a
> > little bit more.
> 
> Whichever type you use here, it needs to be in sync with
> BITOP_BITS_PER_WORD. Hence you want to include the _local_ bitops-
> bits.h
> here, such that in case of an inconsistent override by an arch the
> compiler would complain about the two differring #define-s. (IOW an
> arch overriding BITOP_BITS_PER_WORD cannot re-use this header as-is.)
> 
> The same may, btw, be true for others of the new headers you add -
> the
> same #include would therefore be needed there as well.
Now it clear to me.


It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD, and
BITS_PER_BYTE are defined in {arm, ppc, riscv}/include/asm/bitops.h.
I expected that any architecture planning to use asm-
generic/bitops/bitops-bits.h would include it at the beginning of
<arch>/include/asm/bitops.h, similar to what is done for RISC-V:
   #ifndef _ASM_RISCV_BITOPS_H
   #define _ASM_RISCV_BITOPS_H
   
   #include <asm/system.h>
   
   #include <asm-generic/bitops/bitops-bits.h>
   ...

But in this case, to allow architecture overrides macros, it is
necessary to update asm-generic/bitops/bitops-bits.h:
    #ifndef BITOP_BITS_PER_WORD
    #define BITOP_BITS_PER_WORD     32
    #endif
   ...
Therefore,  if an architecture needs to override something, it will add
#define ... before #include <asm-generic/bitops/bitops-bits.h>.

Does it make sense?

~ Oleksii
Jan Beulich Jan. 17, 2024, 11:17 a.m. UTC | #5
On 17.01.2024 12:13, Oleksii wrote:
> On Tue, 2024-01-16 at 14:24 +0100, Jan Beulich wrote:
>> On 16.01.2024 14:06, Oleksii wrote:
>>> On Mon, 2024-01-15 at 17:44 +0100, Jan Beulich wrote:
>>>> On 22.12.2023 16:12, Oleksii Kurochko wrote:
>>>>> --- /dev/null
>>>>> +++ b/xen/include/asm-generic/bitops/test-bit.h
>>>>> @@ -0,0 +1,16 @@
>>>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>>>> +#ifndef _ASM_GENERIC_BITOPS_TESTBIT_H_
>>>>> +#define _ASM_GENERIC_BITOPS_TESTBIT_H_
>>>>> +
>>>>> +/**
>>>>> + * 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 = addr;
>>>>
>>>> With BITOP_BITS_PER_WORD I think you really mean uint32_t here.
>>> Isn't it the same: 'unsigned int' and 'uint32_t'?
>>
>> No, or else there wouldn't have been a need to introduce uint<N>_t
>> (and
>> others) in C99. It just so happens that right now all architectures
>> Xen
>> can be built for have sizeof(int) == 4 and CHAR_BITS == 8. In an
>> arch-
>> specific header I would see this as less of an issue, but in a
>> generic
>> header we'd better avoid encoding wrong assumptions. The one
>> assumption
>> we generally make is that sizeof(int) >= 4 and CHAR_BITS >= 8 (albeit
>> I
>> bet really in various places we assume CHAR_BITS == 8).
> In this case we have to switch to uint<N>_t.
> Thanks for the explanation. I'll update this part of code in the next
> patch version.
> 
>>
>>>> Also you want to make sure asm-generic/bitops/bitops-bits.h is
>>>> really in use here, or else an arch overriding / not using that
>>>> header may end up screwed.
>>> I am not really understand what do you mean. Could you please
>>> explain a
>>> little bit more.
>>
>> Whichever type you use here, it needs to be in sync with
>> BITOP_BITS_PER_WORD. Hence you want to include the _local_ bitops-
>> bits.h
>> here, such that in case of an inconsistent override by an arch the
>> compiler would complain about the two differring #define-s. (IOW an
>> arch overriding BITOP_BITS_PER_WORD cannot re-use this header as-is.)
>>
>> The same may, btw, be true for others of the new headers you add -
>> the
>> same #include would therefore be needed there as well.
> Now it clear to me.
> 
> 
> It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD, and
> BITS_PER_BYTE are defined in {arm, ppc, riscv}/include/asm/bitops.h.
> I expected that any architecture planning to use asm-
> generic/bitops/bitops-bits.h would include it at the beginning of
> <arch>/include/asm/bitops.h, similar to what is done for RISC-V:
>    #ifndef _ASM_RISCV_BITOPS_H
>    #define _ASM_RISCV_BITOPS_H
>    
>    #include <asm/system.h>
>    
>    #include <asm-generic/bitops/bitops-bits.h>
>    ...
> 
> But in this case, to allow architecture overrides macros, it is
> necessary to update asm-generic/bitops/bitops-bits.h:
>     #ifndef BITOP_BITS_PER_WORD
>     #define BITOP_BITS_PER_WORD     32
>     #endif
>    ...
> Therefore,  if an architecture needs to override something, it will add
> #define ... before #include <asm-generic/bitops/bitops-bits.h>.
> 
> Does it make sense?

Sure. But then the arch also needs to provide a corresponding typedef
(and bitops-bits.h the fallback one), for use wherever you use any of
those #define-s.

Jan
Oleksii Kurochko Jan. 17, 2024, 11:37 a.m. UTC | #6
> > > 
> > > > > Also you want to make sure asm-generic/bitops/bitops-bits.h
> > > > > is
> > > > > really in use here, or else an arch overriding / not using
> > > > > that
> > > > > header may end up screwed.
> > > > I am not really understand what do you mean. Could you please
> > > > explain a
> > > > little bit more.
> > > 
> > > Whichever type you use here, it needs to be in sync with
> > > BITOP_BITS_PER_WORD. Hence you want to include the _local_
> > > bitops-
> > > bits.h
> > > here, such that in case of an inconsistent override by an arch
> > > the
> > > compiler would complain about the two differring #define-s. (IOW
> > > an
> > > arch overriding BITOP_BITS_PER_WORD cannot re-use this header as-
> > > is.)
> > > 
> > > The same may, btw, be true for others of the new headers you add
> > > -
> > > the
> > > same #include would therefore be needed there as well.
> > Now it clear to me.
> > 
> > 
> > It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD, and
> > BITS_PER_BYTE are defined in {arm, ppc,
> > riscv}/include/asm/bitops.h.
> > I expected that any architecture planning to use asm-
> > generic/bitops/bitops-bits.h would include it at the beginning of
> > <arch>/include/asm/bitops.h, similar to what is done for RISC-V:
> >    #ifndef _ASM_RISCV_BITOPS_H
> >    #define _ASM_RISCV_BITOPS_H
> >    
> >    #include <asm/system.h>
> >    
> >    #include <asm-generic/bitops/bitops-bits.h>
> >    ...
> > 
> > But in this case, to allow architecture overrides macros, it is
> > necessary to update asm-generic/bitops/bitops-bits.h:
> >     #ifndef BITOP_BITS_PER_WORD
> >     #define BITOP_BITS_PER_WORD     32
> >     #endif
> >    ...
> > Therefore,  if an architecture needs to override something, it will
> > add
> > #define ... before #include <asm-generic/bitops/bitops-bits.h>.
> > 
> > Does it make sense?
> 
> Sure. But then the arch also needs to provide a corresponding typedef
> (and bitops-bits.h the fallback one), for use wherever you use any of
> those #define-s.
Which one typedef is needed to provide?
<asm-generic/bitops/bitops-bits.h> contains only macros.


~ Oleksii
Jan Beulich Jan. 17, 2024, 1:42 p.m. UTC | #7
On 17.01.2024 12:37, Oleksii wrote:
>>>>
>>>>>> Also you want to make sure asm-generic/bitops/bitops-bits.h
>>>>>> is
>>>>>> really in use here, or else an arch overriding / not using
>>>>>> that
>>>>>> header may end up screwed.
>>>>> I am not really understand what do you mean. Could you please
>>>>> explain a
>>>>> little bit more.
>>>>
>>>> Whichever type you use here, it needs to be in sync with
>>>> BITOP_BITS_PER_WORD. Hence you want to include the _local_
>>>> bitops-
>>>> bits.h
>>>> here, such that in case of an inconsistent override by an arch
>>>> the
>>>> compiler would complain about the two differring #define-s. (IOW
>>>> an
>>>> arch overriding BITOP_BITS_PER_WORD cannot re-use this header as-
>>>> is.)
>>>>
>>>> The same may, btw, be true for others of the new headers you add
>>>> -
>>>> the
>>>> same #include would therefore be needed there as well.
>>> Now it clear to me.
>>>
>>>
>>> It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD, and
>>> BITS_PER_BYTE are defined in {arm, ppc,
>>> riscv}/include/asm/bitops.h.
>>> I expected that any architecture planning to use asm-
>>> generic/bitops/bitops-bits.h would include it at the beginning of
>>> <arch>/include/asm/bitops.h, similar to what is done for RISC-V:
>>>    #ifndef _ASM_RISCV_BITOPS_H
>>>    #define _ASM_RISCV_BITOPS_H
>>>    
>>>    #include <asm/system.h>
>>>    
>>>    #include <asm-generic/bitops/bitops-bits.h>
>>>    ...
>>>
>>> But in this case, to allow architecture overrides macros, it is
>>> necessary to update asm-generic/bitops/bitops-bits.h:
>>>     #ifndef BITOP_BITS_PER_WORD
>>>     #define BITOP_BITS_PER_WORD     32
>>>     #endif
>>>    ...
>>> Therefore,  if an architecture needs to override something, it will
>>> add
>>> #define ... before #include <asm-generic/bitops/bitops-bits.h>.
>>>
>>> Does it make sense?
>>
>> Sure. But then the arch also needs to provide a corresponding typedef
>> (and bitops-bits.h the fallback one), for use wherever you use any of
>> those #define-s.
> Which one typedef is needed to provide?
> <asm-generic/bitops/bitops-bits.h> contains only macros.

A new one, to replace where right now you use "unsigned int" and I
initially said you need to use "uint32_t" instead. With what you said
earlier, uint32_t won't work there (anymore).

Jan
Oleksii Kurochko Jan. 18, 2024, 9:43 a.m. UTC | #8
On Wed, 2024-01-17 at 14:42 +0100, Jan Beulich wrote:
> On 17.01.2024 12:37, Oleksii wrote:
> > > > > 
> > > > > > > Also you want to make sure asm-generic/bitops/bitops-
> > > > > > > bits.h
> > > > > > > is
> > > > > > > really in use here, or else an arch overriding / not
> > > > > > > using
> > > > > > > that
> > > > > > > header may end up screwed.
> > > > > > I am not really understand what do you mean. Could you
> > > > > > please
> > > > > > explain a
> > > > > > little bit more.
> > > > > 
> > > > > Whichever type you use here, it needs to be in sync with
> > > > > BITOP_BITS_PER_WORD. Hence you want to include the _local_
> > > > > bitops-
> > > > > bits.h
> > > > > here, such that in case of an inconsistent override by an
> > > > > arch
> > > > > the
> > > > > compiler would complain about the two differring #define-s.
> > > > > (IOW
> > > > > an
> > > > > arch overriding BITOP_BITS_PER_WORD cannot re-use this header
> > > > > as-
> > > > > is.)
> > > > > 
> > > > > The same may, btw, be true for others of the new headers you
> > > > > add
> > > > > -
> > > > > the
> > > > > same #include would therefore be needed there as well.
> > > > Now it clear to me.
> > > > 
> > > > 
> > > > It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD, and
> > > > BITS_PER_BYTE are defined in {arm, ppc,
> > > > riscv}/include/asm/bitops.h.
> > > > I expected that any architecture planning to use asm-
> > > > generic/bitops/bitops-bits.h would include it at the beginning
> > > > of
> > > > <arch>/include/asm/bitops.h, similar to what is done for RISC-
> > > > V:
> > > >    #ifndef _ASM_RISCV_BITOPS_H
> > > >    #define _ASM_RISCV_BITOPS_H
> > > >    
> > > >    #include <asm/system.h>
> > > >    
> > > >    #include <asm-generic/bitops/bitops-bits.h>
> > > >    ...
> > > > 
> > > > But in this case, to allow architecture overrides macros, it is
> > > > necessary to update asm-generic/bitops/bitops-bits.h:
> > > >     #ifndef BITOP_BITS_PER_WORD
> > > >     #define BITOP_BITS_PER_WORD     32
> > > >     #endif
> > > >    ...
> > > > Therefore,  if an architecture needs to override something, it
> > > > will
> > > > add
> > > > #define ... before #include <asm-generic/bitops/bitops-bits.h>.
> > > > 
> > > > Does it make sense?
> > > 
> > > Sure. But then the arch also needs to provide a corresponding
> > > typedef
> > > (and bitops-bits.h the fallback one), for use wherever you use
> > > any of
> > > those #define-s.
> > Which one typedef is needed to provide?
> > <asm-generic/bitops/bitops-bits.h> contains only macros.
> 
> A new one, to replace where right now you use "unsigned int" and I
> initially said you need to use "uint32_t" instead. With what you said
> earlier, uint32_t won't work there (anymore).
Wouldn't it be enough just to "#include <xen/types.h>" in headers where
"uint32_t" is used?

~ Olkesii
Jan Beulich Jan. 18, 2024, 11:01 a.m. UTC | #9
On 18.01.2024 10:43, Oleksii wrote:
> On Wed, 2024-01-17 at 14:42 +0100, Jan Beulich wrote:
>> On 17.01.2024 12:37, Oleksii wrote:
>>>>>>
>>>>>>>> Also you want to make sure asm-generic/bitops/bitops-
>>>>>>>> bits.h
>>>>>>>> is
>>>>>>>> really in use here, or else an arch overriding / not
>>>>>>>> using
>>>>>>>> that
>>>>>>>> header may end up screwed.
>>>>>>> I am not really understand what do you mean. Could you
>>>>>>> please
>>>>>>> explain a
>>>>>>> little bit more.
>>>>>>
>>>>>> Whichever type you use here, it needs to be in sync with
>>>>>> BITOP_BITS_PER_WORD. Hence you want to include the _local_
>>>>>> bitops-
>>>>>> bits.h
>>>>>> here, such that in case of an inconsistent override by an
>>>>>> arch
>>>>>> the
>>>>>> compiler would complain about the two differring #define-s.
>>>>>> (IOW
>>>>>> an
>>>>>> arch overriding BITOP_BITS_PER_WORD cannot re-use this header
>>>>>> as-
>>>>>> is.)
>>>>>>
>>>>>> The same may, btw, be true for others of the new headers you
>>>>>> add
>>>>>> -
>>>>>> the
>>>>>> same #include would therefore be needed there as well.
>>>>> Now it clear to me.
>>>>>
>>>>>
>>>>> It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD, and
>>>>> BITS_PER_BYTE are defined in {arm, ppc,
>>>>> riscv}/include/asm/bitops.h.
>>>>> I expected that any architecture planning to use asm-
>>>>> generic/bitops/bitops-bits.h would include it at the beginning
>>>>> of
>>>>> <arch>/include/asm/bitops.h, similar to what is done for RISC-
>>>>> V:
>>>>>    #ifndef _ASM_RISCV_BITOPS_H
>>>>>    #define _ASM_RISCV_BITOPS_H
>>>>>    
>>>>>    #include <asm/system.h>
>>>>>    
>>>>>    #include <asm-generic/bitops/bitops-bits.h>
>>>>>    ...
>>>>>
>>>>> But in this case, to allow architecture overrides macros, it is
>>>>> necessary to update asm-generic/bitops/bitops-bits.h:
>>>>>     #ifndef BITOP_BITS_PER_WORD
>>>>>     #define BITOP_BITS_PER_WORD     32
>>>>>     #endif
>>>>>    ...
>>>>> Therefore,  if an architecture needs to override something, it
>>>>> will
>>>>> add
>>>>> #define ... before #include <asm-generic/bitops/bitops-bits.h>.
>>>>>
>>>>> Does it make sense?
>>>>
>>>> Sure. But then the arch also needs to provide a corresponding
>>>> typedef
>>>> (and bitops-bits.h the fallback one), for use wherever you use
>>>> any of
>>>> those #define-s.
>>> Which one typedef is needed to provide?
>>> <asm-generic/bitops/bitops-bits.h> contains only macros.
>>
>> A new one, to replace where right now you use "unsigned int" and I
>> initially said you need to use "uint32_t" instead. With what you said
>> earlier, uint32_t won't work there (anymore).
> Wouldn't it be enough just to "#include <xen/types.h>" in headers where
> "uint32_t" is used?

No, my point wasn't to make uint32_t available. We need a _separate_
typedef which matches the #define-s. Otherwise, if an arch defines
BITOP_BITS_PER_WORD to, say, 64, this generic code would do the wrong
thing.

Jan
Jan Beulich Jan. 18, 2024, 11:03 a.m. UTC | #10
On 22.12.2023 16:12, Oleksii Kurochko wrote:
> --- /dev/null
> +++ b/xen/include/asm-generic/bitops/bitops-bits.h
> @@ -0,0 +1,10 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
> +#define _ASM_GENERIC_BITOPS_BITS_H_
> +
> +#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

Btw, I can't spot a use of BITS_PER_BYTE. Why do you add it? And if
it really needed adding, it surely wouldn't belong here.

Jan
Oleksii Kurochko Jan. 19, 2024, 9:09 a.m. UTC | #11
On Thu, 2024-01-18 at 12:03 +0100, Jan Beulich wrote:
> On 22.12.2023 16:12, Oleksii Kurochko wrote:
> > --- /dev/null
> > +++ b/xen/include/asm-generic/bitops/bitops-bits.h
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
> > +#define _ASM_GENERIC_BITOPS_BITS_H_
> > +
> > +#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
> 
> Btw, I can't spot a use of BITS_PER_BYTE. Why do you add it? And if
> it really needed adding, it surely wouldn't belong here.
It is used in common/bitmap.c and ns16550.c, and inside some arch code,
but it is not used by RISC-V right now.

Would it be better to define it in config.h?

~ Oleksii
Jan Beulich Jan. 19, 2024, 9:14 a.m. UTC | #12
On 19.01.2024 10:09, Oleksii wrote:
> On Thu, 2024-01-18 at 12:03 +0100, Jan Beulich wrote:
>> On 22.12.2023 16:12, Oleksii Kurochko wrote:
>>> --- /dev/null
>>> +++ b/xen/include/asm-generic/bitops/bitops-bits.h
>>> @@ -0,0 +1,10 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
>>> +#define _ASM_GENERIC_BITOPS_BITS_H_
>>> +
>>> +#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
>>
>> Btw, I can't spot a use of BITS_PER_BYTE. Why do you add it? And if
>> it really needed adding, it surely wouldn't belong here.
> It is used in common/bitmap.c and ns16550.c, and inside some arch code,
> but it is not used by RISC-V right now.
> 
> Would it be better to define it in config.h?

Yes, perhaps. Imo this shouldn't have a "generic" fallback; every arch
should explicitly state this (along with e.g. BITS_PER_LONG).

Jan
Oleksii Kurochko Jan. 19, 2024, 9:16 a.m. UTC | #13
On Thu, 2024-01-18 at 12:01 +0100, Jan Beulich wrote:
> On 18.01.2024 10:43, Oleksii wrote:
> > On Wed, 2024-01-17 at 14:42 +0100, Jan Beulich wrote:
> > > On 17.01.2024 12:37, Oleksii wrote:
> > > > > > > 
> > > > > > > > > Also you want to make sure asm-generic/bitops/bitops-
> > > > > > > > > bits.h
> > > > > > > > > is
> > > > > > > > > really in use here, or else an arch overriding / not
> > > > > > > > > using
> > > > > > > > > that
> > > > > > > > > header may end up screwed.
> > > > > > > > I am not really understand what do you mean. Could you
> > > > > > > > please
> > > > > > > > explain a
> > > > > > > > little bit more.
> > > > > > > 
> > > > > > > Whichever type you use here, it needs to be in sync with
> > > > > > > BITOP_BITS_PER_WORD. Hence you want to include the
> > > > > > > _local_
> > > > > > > bitops-
> > > > > > > bits.h
> > > > > > > here, such that in case of an inconsistent override by an
> > > > > > > arch
> > > > > > > the
> > > > > > > compiler would complain about the two differring #define-
> > > > > > > s.
> > > > > > > (IOW
> > > > > > > an
> > > > > > > arch overriding BITOP_BITS_PER_WORD cannot re-use this
> > > > > > > header
> > > > > > > as-
> > > > > > > is.)
> > > > > > > 
> > > > > > > The same may, btw, be true for others of the new headers
> > > > > > > you
> > > > > > > add
> > > > > > > -
> > > > > > > the
> > > > > > > same #include would therefore be needed there as well.
> > > > > > Now it clear to me.
> > > > > > 
> > > > > > 
> > > > > > It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD,
> > > > > > and
> > > > > > BITS_PER_BYTE are defined in {arm, ppc,
> > > > > > riscv}/include/asm/bitops.h.
> > > > > > I expected that any architecture planning to use asm-
> > > > > > generic/bitops/bitops-bits.h would include it at the
> > > > > > beginning
> > > > > > of
> > > > > > <arch>/include/asm/bitops.h, similar to what is done for
> > > > > > RISC-
> > > > > > V:
> > > > > >    #ifndef _ASM_RISCV_BITOPS_H
> > > > > >    #define _ASM_RISCV_BITOPS_H
> > > > > >    
> > > > > >    #include <asm/system.h>
> > > > > >    
> > > > > >    #include <asm-generic/bitops/bitops-bits.h>
> > > > > >    ...
> > > > > > 
> > > > > > But in this case, to allow architecture overrides macros,
> > > > > > it is
> > > > > > necessary to update asm-generic/bitops/bitops-bits.h:
> > > > > >     #ifndef BITOP_BITS_PER_WORD
> > > > > >     #define BITOP_BITS_PER_WORD     32
> > > > > >     #endif
> > > > > >    ...
> > > > > > Therefore,  if an architecture needs to override something,
> > > > > > it
> > > > > > will
> > > > > > add
> > > > > > #define ... before #include <asm-generic/bitops/bitops-
> > > > > > bits.h>.
> > > > > > 
> > > > > > Does it make sense?
> > > > > 
> > > > > Sure. But then the arch also needs to provide a corresponding
> > > > > typedef
> > > > > (and bitops-bits.h the fallback one), for use wherever you
> > > > > use
> > > > > any of
> > > > > those #define-s.
> > > > Which one typedef is needed to provide?
> > > > <asm-generic/bitops/bitops-bits.h> contains only macros.
> > > 
> > > A new one, to replace where right now you use "unsigned int" and
> > > I
> > > initially said you need to use "uint32_t" instead. With what you
> > > said
> > > earlier, uint32_t won't work there (anymore).
> > Wouldn't it be enough just to "#include <xen/types.h>" in headers
> > where
> > "uint32_t" is used?
> 
> No, my point wasn't to make uint32_t available. We need a _separate_
> typedef which matches the #define-s. Otherwise, if an arch defines
> BITOP_BITS_PER_WORD to, say, 64, this generic code would do the wrong
> thing.
Oh, yeah this is true.

We have to introduce in bitops-bits.h:
   typedef uint_32t bitops_type; 

And then use it in function such as test_bit:
   static inline int test_bit(int nr, const volatile void *addr)
   {
       const volatile bitops_type *p = addr;
       return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD -
   1)));
   }

Thanks for clarification.

~ Oleksii
Jan Beulich Jan. 19, 2024, 9:20 a.m. UTC | #14
On 19.01.2024 10:16, Oleksii wrote:
> On Thu, 2024-01-18 at 12:01 +0100, Jan Beulich wrote:
>> On 18.01.2024 10:43, Oleksii wrote:
>>> On Wed, 2024-01-17 at 14:42 +0100, Jan Beulich wrote:
>>>> On 17.01.2024 12:37, Oleksii wrote:
>>>>>>>>
>>>>>>>>>> Also you want to make sure asm-generic/bitops/bitops-
>>>>>>>>>> bits.h
>>>>>>>>>> is
>>>>>>>>>> really in use here, or else an arch overriding / not
>>>>>>>>>> using
>>>>>>>>>> that
>>>>>>>>>> header may end up screwed.
>>>>>>>>> I am not really understand what do you mean. Could you
>>>>>>>>> please
>>>>>>>>> explain a
>>>>>>>>> little bit more.
>>>>>>>>
>>>>>>>> Whichever type you use here, it needs to be in sync with
>>>>>>>> BITOP_BITS_PER_WORD. Hence you want to include the
>>>>>>>> _local_
>>>>>>>> bitops-
>>>>>>>> bits.h
>>>>>>>> here, such that in case of an inconsistent override by an
>>>>>>>> arch
>>>>>>>> the
>>>>>>>> compiler would complain about the two differring #define-
>>>>>>>> s.
>>>>>>>> (IOW
>>>>>>>> an
>>>>>>>> arch overriding BITOP_BITS_PER_WORD cannot re-use this
>>>>>>>> header
>>>>>>>> as-
>>>>>>>> is.)
>>>>>>>>
>>>>>>>> The same may, btw, be true for others of the new headers
>>>>>>>> you
>>>>>>>> add
>>>>>>>> -
>>>>>>>> the
>>>>>>>> same #include would therefore be needed there as well.
>>>>>>> Now it clear to me.
>>>>>>>
>>>>>>>
>>>>>>> It seems like BITOP_BITS_PER_WORD, BITOP_MASK, BITOP_WORD,
>>>>>>> and
>>>>>>> BITS_PER_BYTE are defined in {arm, ppc,
>>>>>>> riscv}/include/asm/bitops.h.
>>>>>>> I expected that any architecture planning to use asm-
>>>>>>> generic/bitops/bitops-bits.h would include it at the
>>>>>>> beginning
>>>>>>> of
>>>>>>> <arch>/include/asm/bitops.h, similar to what is done for
>>>>>>> RISC-
>>>>>>> V:
>>>>>>>    #ifndef _ASM_RISCV_BITOPS_H
>>>>>>>    #define _ASM_RISCV_BITOPS_H
>>>>>>>    
>>>>>>>    #include <asm/system.h>
>>>>>>>    
>>>>>>>    #include <asm-generic/bitops/bitops-bits.h>
>>>>>>>    ...
>>>>>>>
>>>>>>> But in this case, to allow architecture overrides macros,
>>>>>>> it is
>>>>>>> necessary to update asm-generic/bitops/bitops-bits.h:
>>>>>>>     #ifndef BITOP_BITS_PER_WORD
>>>>>>>     #define BITOP_BITS_PER_WORD     32
>>>>>>>     #endif
>>>>>>>    ...
>>>>>>> Therefore,  if an architecture needs to override something,
>>>>>>> it
>>>>>>> will
>>>>>>> add
>>>>>>> #define ... before #include <asm-generic/bitops/bitops-
>>>>>>> bits.h>.
>>>>>>>
>>>>>>> Does it make sense?
>>>>>>
>>>>>> Sure. But then the arch also needs to provide a corresponding
>>>>>> typedef
>>>>>> (and bitops-bits.h the fallback one), for use wherever you
>>>>>> use
>>>>>> any of
>>>>>> those #define-s.
>>>>> Which one typedef is needed to provide?
>>>>> <asm-generic/bitops/bitops-bits.h> contains only macros.
>>>>
>>>> A new one, to replace where right now you use "unsigned int" and
>>>> I
>>>> initially said you need to use "uint32_t" instead. With what you
>>>> said
>>>> earlier, uint32_t won't work there (anymore).
>>> Wouldn't it be enough just to "#include <xen/types.h>" in headers
>>> where
>>> "uint32_t" is used?
>>
>> No, my point wasn't to make uint32_t available. We need a _separate_
>> typedef which matches the #define-s. Otherwise, if an arch defines
>> BITOP_BITS_PER_WORD to, say, 64, this generic code would do the wrong
>> thing.
> Oh, yeah this is true.
> 
> We have to introduce in bitops-bits.h:
>    typedef uint_32t bitops_type; 

Perhaps e.g.

typedef uint32_t bitops_uint_t;

though.

Jan

> And then use it in function such as test_bit:
>    static inline int test_bit(int nr, const volatile void *addr)
>    {
>        const volatile bitops_type *p = addr;
>        return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD -
>    1)));
>    }
> 
> Thanks for clarification.
> 
> ~ Oleksii
Oleksii Kurochko Jan. 19, 2024, 9:30 a.m. UTC | #15
On Fri, 2024-01-19 at 10:14 +0100, Jan Beulich wrote:
> On 19.01.2024 10:09, Oleksii wrote:
> > On Thu, 2024-01-18 at 12:03 +0100, Jan Beulich wrote:
> > > On 22.12.2023 16:12, Oleksii Kurochko wrote:
> > > > --- /dev/null
> > > > +++ b/xen/include/asm-generic/bitops/bitops-bits.h
> > > > @@ -0,0 +1,10 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +#ifndef _ASM_GENERIC_BITOPS_BITS_H_
> > > > +#define _ASM_GENERIC_BITOPS_BITS_H_
> > > > +
> > > > +#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
> > > 
> > > Btw, I can't spot a use of BITS_PER_BYTE. Why do you add it? And
> > > if
> > > it really needed adding, it surely wouldn't belong here.
> > It is used in common/bitmap.c and ns16550.c, and inside some arch
> > code,
> > but it is not used by RISC-V right now.
> > 
> > Would it be better to define it in config.h?
> 
> Yes, perhaps. Imo this shouldn't have a "generic" fallback; every
> arch
> should explicitly state this (along with e.g. BITS_PER_LONG).
Got it. Thanks.

~ Oleksii
diff mbox series

Patch

diff --git a/xen/arch/riscv/include/asm/bitops.h b/xen/arch/riscv/include/asm/bitops.h
new file mode 100644
index 0000000000..d210f529c8
--- /dev/null
+++ b/xen/arch/riscv/include/asm/bitops.h
@@ -0,0 +1,267 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2012 Regents of the University of California */
+
+#ifndef _ASM_RISCV_BITOPS_H
+#define _ASM_RISCV_BITOPS_H
+
+#include <asm/system.h>
+
+#include <asm-generic/bitops/bitops-bits.h>
+
+/* Based on linux/arch/include/linux/bits.h */
+
+#define BIT_MASK(nr)        (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr)        ((nr) / BITS_PER_LONG)
+
+#define __set_bit(n,p)      set_bit(n,p)
+#define __clear_bit(n,p)    clear_bit(n,p)
+
+/* Based on linux/arch/include/asm/bitops.h */
+
+#if ( BITS_PER_LONG == 64 )
+#define __AMO(op)   "amo" #op ".d"
+#elif ( BITS_PER_LONG == 32 )
+#define __AMO(op)   "amo" #op ".w"
+#else
+#error "Unexpected BITS_PER_LONG"
+#endif
+
+#define __test_and_op_bit_ord(op, mod, nr, addr, ord)		\
+({								\
+    unsigned long __res, __mask;				\
+    __mask = BIT_MASK(nr);					\
+    __asm__ __volatile__ (					\
+        __AMO(op) #ord " %0, %2, %1"			\
+        : "=r" (__res), "+A" (addr[BIT_WORD(nr)])	\
+        : "r" (mod(__mask))				\
+        : "memory");					\
+    ((__res & __mask) != 0);				\
+})
+
+#define __op_bit_ord(op, mod, nr, addr, ord)			\
+    __asm__ __volatile__ (					\
+        __AMO(op) #ord " zero, %1, %0"			\
+        : "+A" (addr[BIT_WORD(nr)])			\
+        : "r" (mod(BIT_MASK(nr)))			\
+        : "memory");
+
+#define __test_and_op_bit(op, mod, nr, addr) 			\
+    __test_and_op_bit_ord(op, mod, nr, addr, .aqrl)
+#define __op_bit(op, mod, nr, addr)				\
+    __op_bit_ord(op, mod, nr, addr, )
+
+/* Bitmask modifiers */
+#define __NOP(x)	(x)
+#define __NOT(x)	(~(x))
+
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation may be reordered on other architectures than x86.
+ */
+static inline int __test_and_set_bit(int nr, volatile void *p)
+{
+    volatile uint32_t *addr = p;
+
+    return __test_and_op_bit(or, __NOP, nr, addr);
+}
+
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation can be reordered on other architectures other than x86.
+ */
+static inline int __test_and_clear_bit(int nr, volatile void *p)
+{
+    volatile uint32_t *addr = p;
+
+    return __test_and_op_bit(and, __NOT, nr, addr);
+}
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Note: there are no guarantees that this function will not be reordered
+ * on non x86 architectures, so if you are writing portable code,
+ * make sure not to rely on its reordering guarantees.
+ *
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void set_bit(int nr, volatile void *p)
+{
+    volatile uint32_t *addr = p;
+
+    __op_bit(or, __NOP, nr, addr);
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * Note: there are no guarantees that this function will not be reordered
+ * on non x86 architectures, so if you are writing portable code,
+ * make sure not to rely on its reordering guarantees.
+ */
+static inline void clear_bit(int nr, volatile void *p)
+{
+    volatile uint32_t *addr = p;
+
+    __op_bit(and, __NOT, nr, addr);
+}
+
+#undef __test_and_op_bit
+#undef __op_bit
+#undef __NOP
+#undef __NOT
+#undef __AMO
+
+#define test_and_set_bit   __test_and_set_bit
+#define test_and_clear_bit __test_and_clear_bit
+
+/* Based on linux/include/asm-generic/bitops/find.h */
+
+#ifndef find_next_bit
+/**
+ * find_next_bit - find the next set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+extern unsigned long find_next_bit(const unsigned long *addr, unsigned long
+        size, unsigned long offset);
+#endif
+
+#ifndef find_next_zero_bit
+/**
+ * find_next_zero_bit - find the next cleared bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The bitmap size in bits
+ */
+extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned
+        long size, unsigned long offset);
+#endif
+
+/**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first set bit.
+ */
+extern unsigned long find_first_bit(const unsigned long *addr,
+                    unsigned long size);
+
+/**
+ * find_first_zero_bit - find the first cleared bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit number of the first cleared bit.
+ */
+extern unsigned long find_first_zero_bit(const unsigned long *addr,
+                     unsigned long size);
+
+/**
+ * ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Returns 0 if no bit exists, otherwise returns 1-indexed bit location.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+    int num = 0;
+
+#if BITS_PER_LONG == 64
+    if ((word & 0xffffffff) == 0) {
+        num += 32;
+        word >>= 32;
+    }
+#endif
+    if ((word & 0xffff) == 0) {
+        num += 16;
+        word >>= 16;
+    }
+    if ((word & 0xff) == 0) {
+        num += 8;
+        word >>= 8;
+    }
+    if ((word & 0xf) == 0) {
+        num += 4;
+        word >>= 4;
+    }
+    if ((word & 0x3) == 0) {
+        num += 2;
+        word >>= 2;
+    }
+    if ((word & 0x1) == 0)
+        num += 1;
+    return num;
+}
+
+/**
+ * ffsl - find first bit in long.
+ * @word: The word to search
+ *
+ * Returns 0 if no bit exists, otherwise returns 1-indexed bit location.
+ */
+static inline unsigned int ffsl(unsigned long word)
+{
+    int num = 1;
+
+    if (!word)
+        return 0;
+
+#if BITS_PER_LONG == 64
+    if ((word & 0xffffffff) == 0) {
+        num += 32;
+        word >>= 32;
+    }
+#endif
+    if ((word & 0xffff) == 0) {
+        num += 16;
+        word >>= 16;
+    }
+    if ((word & 0xff) == 0) {
+        num += 8;
+        word >>= 8;
+    }
+    if ((word & 0xf) == 0) {
+        num += 4;
+        word >>= 4;
+    }
+    if ((word & 0x3) == 0) {
+        num += 2;
+        word >>= 2;
+    }
+    if ((word & 0x1) == 0)
+        num += 1;
+    return num;
+}
+
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/flsl.h>
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/ffz.h>
+#include <asm-generic/bitops/find-first-bit-set.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/test-bit.h>
+
+#endif /* _ASM_RISCV_BITOPS_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-generic/bitops/bitops-bits.h b/xen/include/asm-generic/bitops/bitops-bits.h
new file mode 100644
index 0000000000..8a57e47c63
--- /dev/null
+++ b/xen/include/asm-generic/bitops/bitops-bits.h
@@ -0,0 +1,10 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_BITS_H_
+#define _ASM_GENERIC_BITOPS_BITS_H_
+
+#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
+
+#endif /* _ASM_GENERIC_BITOPS_BITS_H_ */
\ No newline at end of file
diff --git a/xen/include/asm-generic/bitops/ffs.h b/xen/include/asm-generic/bitops/ffs.h
new file mode 100644
index 0000000000..3f75fded14
--- /dev/null
+++ b/xen/include/asm-generic/bitops/ffs.h
@@ -0,0 +1,9 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_FFS_H_
+#define _ASM_GENERIC_BITOPS_FFS_H_
+
+#include <xen/macros.h>
+
+#define ffs(x) ({ unsigned int t_ = (x); fls(ISOLATE_LSB(t_)); })
+
+#endif /* _ASM_GENERIC_BITOPS_FFS_H_ */
diff --git a/xen/include/asm-generic/bitops/ffz.h b/xen/include/asm-generic/bitops/ffz.h
new file mode 100644
index 0000000000..92c35455d5
--- /dev/null
+++ b/xen/include/asm-generic/bitops/ffz.h
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_FFZ_H_
+#define _ASM_GENERIC_BITOPS_FFZ_H_
+
+/*
+ * ffz - find first zero in word.
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+#define ffz(x)  __ffs(~(x))
+
+#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */
\ No newline at end of file
diff --git a/xen/include/asm-generic/bitops/find-first-bit-set.h b/xen/include/asm-generic/bitops/find-first-bit-set.h
new file mode 100644
index 0000000000..8ae9751b11
--- /dev/null
+++ b/xen/include/asm-generic/bitops/find-first-bit-set.h
@@ -0,0 +1,17 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_
+#define _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_
+
+/**
+ * find_first_set_bit - find the first set bit in @word
+ * @word: the word to search
+ *
+ * Returns the bit-number of the first set bit (first bit being 0).
+ * The input must *not* be zero.
+ */
+static inline unsigned int find_first_set_bit(unsigned long word)
+{
+        return ffsl(word) - 1;
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FIND_FIRST_BIT_SET_H_ */
\ No newline at end of file
diff --git a/xen/include/asm-generic/bitops/fls.h b/xen/include/asm-generic/bitops/fls.h
new file mode 100644
index 0000000000..f232925080
--- /dev/null
+++ b/xen/include/asm-generic/bitops/fls.h
@@ -0,0 +1,18 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_FLS_H_
+#define _ASM_GENERIC_BITOPS_FLS_H_
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static inline int fls(unsigned int x)
+{
+    return generic_fls(x);
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FLS_H_ */
\ No newline at end of file
diff --git a/xen/include/asm-generic/bitops/flsl.h b/xen/include/asm-generic/bitops/flsl.h
new file mode 100644
index 0000000000..127221056e
--- /dev/null
+++ b/xen/include/asm-generic/bitops/flsl.h
@@ -0,0 +1,10 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_FLSL_H_
+#define _ASM_GENERIC_BITOPS_FLSL_H_
+
+static inline int flsl(unsigned long x)
+{
+    return generic_flsl(x);
+}
+
+#endif /* _ASM_GENERIC_BITOPS_FLSL_H_ */
\ No newline at end of file
diff --git a/xen/include/asm-generic/bitops/hweight.h b/xen/include/asm-generic/bitops/hweight.h
new file mode 100644
index 0000000000..0d7577054e
--- /dev/null
+++ b/xen/include/asm-generic/bitops/hweight.h
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_
+#define _ASM_GENERIC_BITOPS_HWEIGHT_H_
+
+/*
+ * 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)
+
+#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */
diff --git a/xen/include/asm-generic/bitops/test-bit.h b/xen/include/asm-generic/bitops/test-bit.h
new file mode 100644
index 0000000000..9fa36652e3
--- /dev/null
+++ b/xen/include/asm-generic/bitops/test-bit.h
@@ -0,0 +1,16 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_BITOPS_TESTBIT_H_
+#define _ASM_GENERIC_BITOPS_TESTBIT_H_
+
+/**
+ * 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 = addr;
+    return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD - 1)));
+}
+
+#endif /* _ASM_GENERIC_BITOPS_TESTBIT_H_ */
\ No newline at end of file