Mailing List Archive

[PATCH v7 04/19] xen: introduce generic non-atomic test_*bit()
The patch introduces the following generic functions:
* test_bit
* generic__test_and_set_bit
* generic__test_and_clear_bit
* generic__test_and_change_bit

Also, the patch introduces the following generics which are
used by the functions mentioned above:
* BITOP_BITS_PER_WORD
* BITOP_MASK
* BITOP_WORD
* BITOP_TYPE

These functions and macros can be useful for architectures
that don't have corresponding arch-specific instructions.

Because of that x86 has the following check in the macros test_bit(),
__test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit():
if ( bitop_bad_size(addr) ) __bitop_bad_size();
It was necessary to move the check to generic code and define as 0
for other architectures as they do not require this check.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in V7:
- move everything to xen/bitops.h to follow the same approach for all generic
bit ops.
- put together BITOP_BITS_PER_WORD and bitops_uint_t.
- make BITOP_MASK more generic.
- drop #ifdef ... #endif around BITOP_MASK, BITOP_WORD as they are generic
enough.
- drop "_" for generic__{test_and_set_bit,...}().
- drop " != 0" for functions which return bool.
- add volatile during the cast for generic__{...}().
- update the commit message.
- update arch related code to follow the proposed generic approach.
---
Changes in V6:
- Nothing changed ( only rebase )
---
Changes in V5:
- new patch
---
xen/arch/arm/arm64/livepatch.c | 1 -
xen/arch/arm/include/asm/bitops.h | 67 -------------
xen/arch/ppc/include/asm/bitops.h | 64 -------------
xen/arch/ppc/include/asm/page.h | 2 +-
xen/arch/ppc/mm-radix.c | 2 +-
xen/arch/x86/include/asm/bitops.h | 28 ++----
xen/include/xen/bitops.h | 154 ++++++++++++++++++++++++++++++
7 files changed, 165 insertions(+), 153 deletions(-)

diff --git a/xen/arch/arm/arm64/livepatch.c b/xen/arch/arm/arm64/livepatch.c
index df2cebedde..4bc8ed9be5 100644
--- a/xen/arch/arm/arm64/livepatch.c
+++ b/xen/arch/arm/arm64/livepatch.c
@@ -10,7 +10,6 @@
#include <xen/mm.h>
#include <xen/vmap.h>

-#include <asm/bitops.h>
#include <asm/byteorder.h>
#include <asm/insn.h>
#include <asm/livepatch.h>
diff --git a/xen/arch/arm/include/asm/bitops.h b/xen/arch/arm/include/asm/bitops.h
index 5104334e48..8e16335e76 100644
--- a/xen/arch/arm/include/asm/bitops.h
+++ b/xen/arch/arm/include/asm/bitops.h
@@ -22,9 +22,6 @@
#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)
@@ -76,70 +73,6 @@ bool test_and_change_bit_timeout(int nr, volatile void *p,
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)));
-}
-
/*
* On ARMv5 and above those functions can be implemented around
* the clz instruction for much better code efficiency.
diff --git a/xen/arch/ppc/include/asm/bitops.h b/xen/arch/ppc/include/asm/bitops.h
index 989d341a44..a17060c7c2 100644
--- a/xen/arch/ppc/include/asm/bitops.h
+++ b/xen/arch/ppc/include/asm/bitops.h
@@ -15,9 +15,6 @@
#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) (1U << ((nr) % BITOP_BITS_PER_WORD))
-#define BITOP_WORD(nr) ((nr) / BITOP_BITS_PER_WORD)
#define BITS_PER_BYTE 8

/* PPC bit number conversion */
@@ -69,17 +66,6 @@ static inline void clear_bit(int nr, volatile void *addr)
clear_bits(BITOP_MASK(nr), (volatile unsigned int *)addr + BITOP_WORD(nr));
}

-/**
- * 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)));
-}
-
static inline unsigned int test_and_clear_bits(
unsigned int mask,
volatile unsigned int *p)
@@ -133,56 +119,6 @@ static inline int test_and_set_bit(unsigned int nr, volatile void *addr)
(volatile unsigned int *)addr + BITOP_WORD(nr)) != 0;
}

-/**
- * __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;
-}
-
-#define flsl(x) generic_flsl(x)
-#define fls(x) generic_fls(x)
-
-/* Based on linux/include/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))
-
/**
* hweightN - returns the hamming weight of a N-bit word
* @x: the word to weigh
diff --git a/xen/arch/ppc/include/asm/page.h b/xen/arch/ppc/include/asm/page.h
index 890e285051..482053b023 100644
--- a/xen/arch/ppc/include/asm/page.h
+++ b/xen/arch/ppc/include/asm/page.h
@@ -4,7 +4,7 @@

#include <xen/types.h>

-#include <asm/bitops.h>
+#include <xen/bitops.h>
#include <asm/byteorder.h>

#define PDE_VALID PPC_BIT(0)
diff --git a/xen/arch/ppc/mm-radix.c b/xen/arch/ppc/mm-radix.c
index daa411a6fa..3cd8c4635a 100644
--- a/xen/arch/ppc/mm-radix.c
+++ b/xen/arch/ppc/mm-radix.c
@@ -1,11 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <xen/bitops.h>
#include <xen/init.h>
#include <xen/kernel.h>
#include <xen/mm.h>
#include <xen/types.h>
#include <xen/lib.h>

-#include <asm/bitops.h>
#include <asm/byteorder.h>
#include <asm/early_printk.h>
#include <asm/page.h>
diff --git a/xen/arch/x86/include/asm/bitops.h b/xen/arch/x86/include/asm/bitops.h
index dd439b69a0..81b43da5db 100644
--- a/xen/arch/x86/include/asm/bitops.h
+++ b/xen/arch/x86/include/asm/bitops.h
@@ -175,7 +175,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
})

/**
- * __test_and_set_bit - Set a bit and return its old value
+ * arch__test_and_set_bit - Set a bit and return its old value
* @nr: Bit to set
* @addr: Address to count from
*
@@ -183,7 +183,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr)
* 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, void *addr)
+static inline int arch__test_and_set_bit(int nr, volatile void *addr)
{
int oldbit;

@@ -194,10 +194,7 @@ static inline int __test_and_set_bit(int nr, void *addr)

return oldbit;
}
-#define __test_and_set_bit(nr, addr) ({ \
- if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
- __test_and_set_bit(nr, addr); \
-})
+#define arch__test_and_set_bit arch__test_and_set_bit

/**
* test_and_clear_bit - Clear a bit and return its old value
@@ -224,7 +221,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr)
})

/**
- * __test_and_clear_bit - Clear a bit and return its old value
+ * arch__test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to set
* @addr: Address to count from
*
@@ -232,7 +229,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr)
* 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, void *addr)
+static inline int arch__test_and_clear_bit(int nr, volatile void *addr)
{
int oldbit;

@@ -243,13 +240,10 @@ static inline int __test_and_clear_bit(int nr, void *addr)

return oldbit;
}
-#define __test_and_clear_bit(nr, addr) ({ \
- if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
- __test_and_clear_bit(nr, addr); \
-})
+#define arch__test_and_clear_bit arch__test_and_clear_bit

/* WARNING: non atomic and it can be reordered! */
-static inline int __test_and_change_bit(int nr, void *addr)
+static inline int arch__test_and_change_bit(int nr, volatile void *addr)
{
int oldbit;

@@ -260,10 +254,7 @@ static inline int __test_and_change_bit(int nr, void *addr)

return oldbit;
}
-#define __test_and_change_bit(nr, addr) ({ \
- if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
- __test_and_change_bit(nr, addr); \
-})
+#define arch__test_and_change_bit arch__test_and_change_bit

/**
* test_and_change_bit - Change a bit and return its new value
@@ -307,8 +298,7 @@ static inline int variable_test_bit(int nr, const volatile void *addr)
return oldbit;
}

-#define test_bit(nr, addr) ({ \
- if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
+#define arch_test_bit(nr, addr) ({ \
__builtin_constant_p(nr) ? \
constant_test_bit(nr, addr) : \
variable_test_bit(nr, addr); \
diff --git a/xen/include/xen/bitops.h b/xen/include/xen/bitops.h
index f14ad0d33a..685c7540cc 100644
--- a/xen/include/xen/bitops.h
+++ b/xen/include/xen/bitops.h
@@ -65,10 +65,164 @@ static inline int generic_flsl(unsigned long x)
* scope
*/

+#define BITOP_BITS_PER_WORD 32
+/* typedef uint32_t bitop_uint_t; */
+#define bitop_uint_t uint32_t
+
+#define BITOP_MASK(nr) ((bitop_uint_t)1 << ((nr) % BITOP_BITS_PER_WORD))
+
+#define BITOP_WORD(nr) ((nr) / BITOP_BITS_PER_WORD)
+
/* --------------------- Please tidy above here --------------------- */

#include <asm/bitops.h>

+#ifndef bitop_bad_size
+extern void __bitop_bad_size(void);
+#define bitop_bad_size(addr) 0
+#endif
+
+/**
+ * generic__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 always_inline __pure bool
+generic__test_and_set_bit(unsigned long nr, volatile void *addr)
+{
+ bitop_uint_t mask = BITOP_MASK(nr);
+ volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + BITOP_WORD(nr);
+ bitop_uint_t old = *p;
+
+ *p = old | mask;
+ return (old & mask);
+}
+
+/**
+ * generic__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 always_inline __pure bool
+generic__test_and_clear_bit(bitop_uint_t nr, volatile void *addr)
+{
+ bitop_uint_t mask = BITOP_MASK(nr);
+ volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + BITOP_WORD(nr);
+ bitop_uint_t old = *p;
+
+ *p = old & ~mask;
+ return (old & mask);
+}
+
+/* WARNING: non atomic and it can be reordered! */
+static always_inline __pure bool
+generic__test_and_change_bit(unsigned long nr, volatile void *addr)
+{
+ bitop_uint_t mask = BITOP_MASK(nr);
+ volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + BITOP_WORD(nr);
+ bitop_uint_t old = *p;
+
+ *p = old ^ mask;
+ return (old & mask);
+}
+/**
+ * generic_test_bit - Determine whether a bit is set
+ * @nr: bit number to test
+ * @addr: Address to start counting from
+ */
+static always_inline __pure int generic_test_bit(int nr, const volatile void *addr)
+{
+ const volatile bitop_uint_t *p = addr;
+ return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD - 1)));
+}
+
+static always_inline __pure bool
+__test_and_set_bit(unsigned long nr, volatile void *addr)
+{
+#ifndef arch__test_and_set_bit
+#define arch__test_and_set_bit generic__test_and_set_bit
+#endif
+
+ return arch__test_and_set_bit(nr, addr);
+}
+#define __test_and_set_bit(nr, addr) ({ \
+ if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
+ __test_and_set_bit(nr, addr); \
+})
+
+static always_inline __pure bool
+__test_and_clear_bit(bitop_uint_t nr, volatile void *addr)
+{
+#ifndef arch__test_and_clear_bit
+#define arch__test_and_clear_bit generic__test_and_clear_bit
+#endif
+
+ return arch__test_and_clear_bit(nr, addr);
+}
+#define __test_and_clear_bit(nr, addr) ({ \
+ if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
+ __test_and_clear_bit(nr, addr); \
+})
+
+static always_inline __pure bool
+__test_and_change_bit(unsigned long nr, volatile void *addr)
+{
+#ifndef arch__test_and_change_bit
+#define arch__test_and_change_bit generic__test_and_change_bit
+#endif
+
+ return arch__test_and_change_bit(nr, addr);
+}
+#define __test_and_change_bit(nr, addr) ({ \
+ if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
+ __test_and_change_bit(nr, addr); \
+})
+
+static always_inline __pure int test_bit(int nr, const volatile void *addr)
+{
+#ifndef arch_test_bit
+#define arch_test_bit generic_test_bit
+#endif
+
+ return arch_test_bit(nr, addr);
+}
+#define test_bit(nr, addr) ({ \
+ if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
+ test_bit(nr, addr); \
+})
+
+static always_inline __pure int fls(unsigned int x)
+{
+ if (__builtin_constant_p(x))
+ return generic_fls(x);
+
+#ifndef arch_fls
+#define arch_fls generic_fls
+#endif
+
+ return arch_fls(x);
+}
+
+static always_inline __pure int flsl(unsigned long x)
+{
+ if (__builtin_constant_p(x))
+ return generic_flsl(x);
+
+#ifndef arch_flsl
+#define arch_flsl generic_flsl
+#endif
+
+ return arch_flsl(x);
+}
+
/*
* Find First Set bit. Bits are labelled from 1.
*/
--
2.43.0
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On 03.04.2024 12:19, Oleksii Kurochko wrote:
> The patch introduces the following generic functions:
> * test_bit
> * generic__test_and_set_bit
> * generic__test_and_clear_bit
> * generic__test_and_change_bit
>
> Also, the patch introduces the following generics which are
> used by the functions mentioned above:
> * BITOP_BITS_PER_WORD
> * BITOP_MASK
> * BITOP_WORD
> * BITOP_TYPE
>
> These functions and macros can be useful for architectures
> that don't have corresponding arch-specific instructions.
>
> Because of that x86 has the following check in the macros test_bit(),
> __test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit():
> if ( bitop_bad_size(addr) ) __bitop_bad_size();
> It was necessary to move the check to generic code and define as 0
> for other architectures as they do not require this check.

Hmm, yes, the checks need to be in the outermost wrapper macros. While
you're abstracting other stuff to arch_*(), wouldn't it make sense to
also abstract this to e.g. arch_check_bitop_size(), with the expansion
simply being (effectively) empty in the generic fallback case?

> --- a/xen/include/xen/bitops.h
> +++ b/xen/include/xen/bitops.h
> @@ -65,10 +65,164 @@ static inline int generic_flsl(unsigned long x)
> * scope
> */
>
> +#define BITOP_BITS_PER_WORD 32
> +/* typedef uint32_t bitop_uint_t; */
> +#define bitop_uint_t uint32_t

So no arch overrides permitted anymore at all?

> +#define BITOP_MASK(nr) ((bitop_uint_t)1 << ((nr) % BITOP_BITS_PER_WORD))
> +
> +#define BITOP_WORD(nr) ((nr) / BITOP_BITS_PER_WORD)
> +
> /* --------------------- Please tidy above here --------------------- */
>
> #include <asm/bitops.h>
>
> +#ifndef bitop_bad_size
> +extern void __bitop_bad_size(void);

If not switching to arch_check_bitop_size() or alike as suggested above,
why exactly does this need duplicating here and in x86? Can't the decl
simply move ahead of the #include right above? (Sure, this will then
require that nothing needing any of the functions you move here would
still include asm/bitops.h; it would need to be xen/bitops.h everywhere.)

> +#define bitop_bad_size(addr) 0
> +#endif
> +
> +/**
> + * generic__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 always_inline __pure bool
> +generic__test_and_set_bit(unsigned long nr, volatile void *addr)

Does __pure actually fit with the use of volatile? The former says multiple
accesses may be folded; the latter says they must not be.

> +{
> + bitop_uint_t mask = BITOP_MASK(nr);
> + volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + BITOP_WORD(nr);

Nit: Slightly shorter line possible:

volatile bitop_uint_t *p = (volatile bitop_uint_t *)addr + BITOP_WORD(nr);

> + bitop_uint_t old = *p;
> +
> + *p = old | mask;
> + return (old & mask);
> +}
> +
> +/**
> + * generic__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 always_inline __pure bool
> +generic__test_and_clear_bit(bitop_uint_t nr, volatile void *addr)
> +{
> + bitop_uint_t mask = BITOP_MASK(nr);
> + volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + BITOP_WORD(nr);
> + bitop_uint_t old = *p;
> +
> + *p = old & ~mask;
> + return (old & mask);
> +}
> +
> +/* WARNING: non atomic and it can be reordered! */
> +static always_inline __pure bool
> +generic__test_and_change_bit(unsigned long nr, volatile void *addr)
> +{
> + bitop_uint_t mask = BITOP_MASK(nr);
> + volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + BITOP_WORD(nr);
> + bitop_uint_t old = *p;
> +
> + *p = old ^ mask;
> + return (old & mask);
> +}
> +/**
> + * generic_test_bit - Determine whether a bit is set
> + * @nr: bit number to test
> + * @addr: Address to start counting from
> + */
> +static always_inline __pure int generic_test_bit(int nr, const volatile void *addr)

Further up you use bool; why int here?

> +{
> + const volatile bitop_uint_t *p = addr;
> + return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD - 1)));

And reason not to use BITOP_MASK() here as well (once having switched to
bool return type)?

> +}
> +
> +static always_inline __pure bool
> +__test_and_set_bit(unsigned long nr, volatile void *addr)
> +{
> +#ifndef arch__test_and_set_bit
> +#define arch__test_and_set_bit generic__test_and_set_bit
> +#endif
> +
> + return arch__test_and_set_bit(nr, addr);
> +}
> +#define __test_and_set_bit(nr, addr) ({ \
> + if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
> + __test_and_set_bit(nr, addr); \
> +})
> +
> +static always_inline __pure bool
> +__test_and_clear_bit(bitop_uint_t nr, volatile void *addr)
> +{
> +#ifndef arch__test_and_clear_bit
> +#define arch__test_and_clear_bit generic__test_and_clear_bit
> +#endif
> +
> + return arch__test_and_clear_bit(nr, addr);
> +}
> +#define __test_and_clear_bit(nr, addr) ({ \
> + if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
> + __test_and_clear_bit(nr, addr); \
> +})
> +
> +static always_inline __pure bool
> +__test_and_change_bit(unsigned long nr, volatile void *addr)
> +{
> +#ifndef arch__test_and_change_bit
> +#define arch__test_and_change_bit generic__test_and_change_bit
> +#endif
> +
> + return arch__test_and_change_bit(nr, addr);
> +}
> +#define __test_and_change_bit(nr, addr) ({ \
> + if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
> + __test_and_change_bit(nr, addr); \
> +})
> +
> +static always_inline __pure int test_bit(int nr, const volatile void *addr)

Further up you use bool; why int here?

> +{
> +#ifndef arch_test_bit
> +#define arch_test_bit generic_test_bit
> +#endif
> +
> + return arch_test_bit(nr, addr);
> +}
> +#define test_bit(nr, addr) ({ \
> + if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
> + test_bit(nr, addr); \
> +})

From here onwards, ...

> +static always_inline __pure int fls(unsigned int x)
> +{
> + if (__builtin_constant_p(x))
> + return generic_fls(x);
> +
> +#ifndef arch_fls
> +#define arch_fls generic_fls
> +#endif
> +
> + return arch_fls(x);
> +}
> +
> +static always_inline __pure int flsl(unsigned long x)
> +{
> + if (__builtin_constant_p(x))
> + return generic_flsl(x);
> +
> +#ifndef arch_flsl
> +#define arch_flsl generic_flsl
> +#endif
> +
> + return arch_flsl(x);
> +}

... does all of this really belong here? Neither title nor description have
any hint towards this.

> /*
> * Find First Set bit. Bits are labelled from 1.
> */

This context suggests there's a dependency on an uncommitted patch. Nothing
above says so. I guess you have a remark in the cover letter, yet imo that's
only partly helpful.

Jan
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
> On 03.04.2024 12:19, Oleksii Kurochko wrote:
> > The patch introduces the following generic functions:
> > * test_bit
> > * generic__test_and_set_bit
> > * generic__test_and_clear_bit
> > * generic__test_and_change_bit
> >
> > Also, the patch introduces the following generics which are
> > used by the functions mentioned above:
> > * BITOP_BITS_PER_WORD
> > * BITOP_MASK
> > * BITOP_WORD
> > * BITOP_TYPE
> >
> > These functions and macros can be useful for architectures
> > that don't have corresponding arch-specific instructions.
> >
> > Because of that x86 has the following check in the macros
> > test_bit(),
> > __test_and_set_bit(), __test_and_clear_bit(),
> > __test_and_change_bit():
> >     if ( bitop_bad_size(addr) ) __bitop_bad_size();
> > It was necessary to move the check to generic code and define as 0
> > for other architectures as they do not require this check.
>
> Hmm, yes, the checks need to be in the outermost wrapper macros.
> While
> you're abstracting other stuff to arch_*(), wouldn't it make sense to
> also abstract this to e.g. arch_check_bitop_size(), with the
> expansion
> simply being (effectively) empty in the generic fallback case?
Probably it would be better to be consistent and introduce
arch_check_bitop_size().

>
> > --- a/xen/include/xen/bitops.h
> > +++ b/xen/include/xen/bitops.h
> > @@ -65,10 +65,164 @@ static inline int generic_flsl(unsigned long
> > x)
> >   * scope
> >   */
> >  
> > +#define BITOP_BITS_PER_WORD 32
> > +/* typedef uint32_t bitop_uint_t; */
> > +#define bitop_uint_t uint32_t
>
> So no arch overrides permitted anymore at all?
Not really, I agree that it is ugly, but I expected that arch will use
undef to override.

>
> > +#define BITOP_MASK(nr)  ((bitop_uint_t)1 << ((nr) %
> > BITOP_BITS_PER_WORD))
> > +
> > +#define BITOP_WORD(nr)  ((nr) / BITOP_BITS_PER_WORD)
> > +
> >  /* --------------------- Please tidy above here ------------------
> > --- */
> >  
> >  #include <asm/bitops.h>
> >  
> > +#ifndef bitop_bad_size
> > +extern void __bitop_bad_size(void);
>
> If not switching to arch_check_bitop_size() or alike as suggested
> above,
> why exactly does this need duplicating here and in x86? Can't the
> decl
> simply move ahead of the #include right above? (Sure, this will then
> require that nothing needing any of the functions you move here would
> still include asm/bitops.h; it would need to be xen/bitops.h
> everywhere.)
It could be done in way you suggest, I just wanted to keep changes
minimal ( without going and switching asm/bitops.h -> xen/bitops.h ),
but we can consider such option.

>
> > +#define bitop_bad_size(addr) 0
> > +#endif
> > +
> > +/**
> > + * generic__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 always_inline __pure bool
> > +generic__test_and_set_bit(unsigned long nr, volatile void *addr)
>
> Does __pure actually fit with the use of volatile? The former says
> multiple
> accesses may be folded; the latter says they must not be.
Overlooked that, __pure should be dropped.

>
> > +{
> > +    bitop_uint_t mask = BITOP_MASK(nr);
> > +    volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) +
> > BITOP_WORD(nr);
>
> Nit: Slightly shorter line possible:
>
>     volatile bitop_uint_t *p = (volatile bitop_uint_t *)addr +
> BITOP_WORD(nr);
>
> > +    bitop_uint_t old = *p;
> > +
> > +    *p = old | mask;
> > +    return (old & mask);
> > +}
> > +
> > +/**
> > + * generic__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 always_inline __pure bool
> > +generic__test_and_clear_bit(bitop_uint_t nr, volatile void *addr)
> > +{
> > +    bitop_uint_t mask = BITOP_MASK(nr);
> > +    volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) +
> > BITOP_WORD(nr);
> > +    bitop_uint_t old = *p;
> > +
> > +    *p = old & ~mask;
> > +    return (old & mask);
> > +}
> > +
> > +/* WARNING: non atomic and it can be reordered! */
> > +static always_inline __pure bool
> > +generic__test_and_change_bit(unsigned long nr, volatile void
> > *addr)
> > +{
> > +    bitop_uint_t mask = BITOP_MASK(nr);
> > +    volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) +
> > BITOP_WORD(nr);
> > +    bitop_uint_t old = *p;
> > +
> > +    *p = old ^ mask;
> > +    return (old & mask);
> > +}
> > +/**
> > + * generic_test_bit - Determine whether a bit is set
> > + * @nr: bit number to test
> > + * @addr: Address to start counting from
> > + */
> > +static always_inline __pure int generic_test_bit(int nr, const
> > volatile void *addr)
>
> Further up you use bool; why int here?
No specific reason, I have to update everything to bool.

>
> > +{
> > +    const volatile bitop_uint_t *p = addr;
> > +    return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD -
> > 1)));
>
> And reason not to use BITOP_MASK() here as well (once having switched
> to
> bool return type)?
It seems we can use BITOP_MASK() this implementation was copied from
arch specific code.

>
> > +}
> > +
> > +static always_inline __pure bool
> > +__test_and_set_bit(unsigned long nr, volatile void *addr)
> > +{
> > +#ifndef arch__test_and_set_bit
> > +#define arch__test_and_set_bit generic__test_and_set_bit
> > +#endif
> > +
> > +    return arch__test_and_set_bit(nr, addr);
> > +}
> > +#define __test_and_set_bit(nr, addr) ({             \
> > +    if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
> > +    __test_and_set_bit(nr, addr);                   \
> > +})
> > +
> > +static always_inline __pure bool
> > +__test_and_clear_bit(bitop_uint_t nr, volatile void *addr)
> > +{
> > +#ifndef arch__test_and_clear_bit
> > +#define arch__test_and_clear_bit generic__test_and_clear_bit
> > +#endif
> > +
> > +    return arch__test_and_clear_bit(nr, addr);
> > +}
> > +#define __test_and_clear_bit(nr, addr) ({           \
> > +    if ( bitop_bad_size(addr) ) __bitop_bad_size(); \
> > +    __test_and_clear_bit(nr, addr);                 \
> > +})
> > +
> > +static always_inline __pure bool
> > +__test_and_change_bit(unsigned long nr, volatile void *addr)
> > +{
> > +#ifndef arch__test_and_change_bit
> > +#define arch__test_and_change_bit generic__test_and_change_bit
> > +#endif
> > +
> > +    return arch__test_and_change_bit(nr, addr);
> > +}
> > +#define __test_and_change_bit(nr, addr) ({              \
> > +    if ( bitop_bad_size(addr) ) __bitop_bad_size();     \
> > +    __test_and_change_bit(nr, addr);                    \
> > +})
> > +
> > +static always_inline __pure int test_bit(int nr, const volatile
> > void *addr)
>
> Further up you use bool; why int here?
>
> > +{
> > +#ifndef arch_test_bit
> > +#define arch_test_bit generic_test_bit
> > +#endif
> > +
> > +    return arch_test_bit(nr, addr);
> > +}
> > +#define test_bit(nr, addr) ({                           \
> > +    if ( bitop_bad_size(addr) ) __bitop_bad_size();     \
> > +    test_bit(nr, addr);                                 \
> > +})
>
> From here onwards, ...
>
> > +static always_inline __pure int fls(unsigned int x)
> > +{
> > +    if (__builtin_constant_p(x))
> > +        return generic_fls(x);
> > +
> > +#ifndef arch_fls
> > +#define arch_fls generic_fls
> > +#endif
> > +
> > +    return arch_fls(x);
> > +}
> > +
> > +static always_inline __pure int flsl(unsigned long x)
> > +{
> > +    if (__builtin_constant_p(x))
> > +        return generic_flsl(x);
> > +
> > +#ifndef arch_flsl
> > +#define arch_flsl generic_flsl
> > +#endif
> > +
> > +    return arch_flsl(x);
> > +}
>
> ... does all of this really belong here? Neither title nor
> description have
> any hint towards this.
No, it should be a part of the [PATCH v7 05/19] xen/bitops: implement
fls{l}() in common logic. An issue during rebase. I'll update that.

>
> >  /*
> >   * Find First Set bit.  Bits are labelled from 1.
> >   */
>
> This context suggests there's a dependency on an uncommitted patch.
> Nothing
> above says so. I guess you have a remark in the cover letter, yet imo
> that's
> only partly helpful.
Is it really a hard dependency?
The current patch series really depends on ffs{l}() and that was
mentioned in the cover letter ( I'll reword the cover letter to explain
why exactly this dependency is needed ), but this patch isn't really
depends on Andrew's patch series, where ffs{l}() are introduced.

~ Oleksii
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On 04.04.2024 17:45, Oleksii wrote:
> On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
>> On 03.04.2024 12:19, Oleksii Kurochko wrote:
>>> --- a/xen/include/xen/bitops.h
>>> +++ b/xen/include/xen/bitops.h
>>> @@ -65,10 +65,164 @@ static inline int generic_flsl(unsigned long
>>> x)
>>>   * scope
>>>   */
>>>  
>>> +#define BITOP_BITS_PER_WORD 32
>>> +/* typedef uint32_t bitop_uint_t; */
>>> +#define bitop_uint_t uint32_t
>>
>> So no arch overrides permitted anymore at all?
> Not really, I agree that it is ugly, but I expected that arch will use
> undef to override.

Which would be fine in principle, just that Misra wants us to avoid #undef-s
(iirc).

>>>  /*
>>>   * Find First Set bit.  Bits are labelled from 1.
>>>   */
>>
>> This context suggests there's a dependency on an uncommitted patch.
>> Nothing
>> above says so. I guess you have a remark in the cover letter, yet imo
>> that's
>> only partly helpful.
> Is it really a hard dependency?
> The current patch series really depends on ffs{l}() and that was
> mentioned in the cover letter ( I'll reword the cover letter to explain
> why exactly this dependency is needed ), but this patch isn't really
> depends on Andrew's patch series, where ffs{l}() are introduced.

If anyone acked this patch, and if it otherwise looked independent, it would
be a candidate for committing. Just that it won't apply for a non-obvious
reason.

Jan
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
> On 04.04.2024 17:45, Oleksii wrote:
> > On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
> > > On 03.04.2024 12:19, Oleksii Kurochko wrote:
> > > > --- a/xen/include/xen/bitops.h
> > > > +++ b/xen/include/xen/bitops.h
> > > > @@ -65,10 +65,164 @@ static inline int generic_flsl(unsigned
> > > > long
> > > > x)
> > > >   * scope
> > > >   */
> > > >  
> > > > +#define BITOP_BITS_PER_WORD 32
> > > > +/* typedef uint32_t bitop_uint_t; */
> > > > +#define bitop_uint_t uint32_t
> > >
> > > So no arch overrides permitted anymore at all?
> > Not really, I agree that it is ugly, but I expected that arch will
> > use
> > undef to override.
>
> Which would be fine in principle, just that Misra wants us to avoid
> #undef-s
> (iirc).
Could you please give me a recommendation how to do that better?

The reason why I put this defintions before inclusion of asm/bitops.h
as RISC-V specific code uses these definitions inside it, so they
should be defined before asm/bitops.h; other option is to define these
definitions inside asm/bitops.h for each architecture.

>
> > > >  /*
> > > >   * Find First Set bit.  Bits are labelled from 1.
> > > >   */
> > >
> > > This context suggests there's a dependency on an uncommitted
> > > patch.
> > > Nothing
> > > above says so. I guess you have a remark in the cover letter, yet
> > > imo
> > > that's
> > > only partly helpful.
> > Is it really a hard dependency?
> > The current patch series really depends on ffs{l}() and that was
> > mentioned in the cover letter ( I'll reword the cover letter to
> > explain
> > why exactly this dependency is needed ), but this patch isn't
> > really
> > depends on Andrew's patch series, where ffs{l}() are introduced.
>
> If anyone acked this patch, and if it otherwise looked independent,
> it would
> be a candidate for committing. Just that it won't apply for a non-
> obvious
> reason.
I didn't think about the it won't apply. In this I have to definitely
mention this moment in cover letter. Thanks.

~ Oleksii
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On 04.04.2024 18:24, Oleksii wrote:
> On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
>> On 04.04.2024 17:45, Oleksii wrote:
>>> On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
>>>> On 03.04.2024 12:19, Oleksii Kurochko wrote:
>>>>> --- a/xen/include/xen/bitops.h
>>>>> +++ b/xen/include/xen/bitops.h
>>>>> @@ -65,10 +65,164 @@ static inline int generic_flsl(unsigned
>>>>> long
>>>>> x)
>>>>>   * scope
>>>>>   */
>>>>>  
>>>>> +#define BITOP_BITS_PER_WORD 32
>>>>> +/* typedef uint32_t bitop_uint_t; */
>>>>> +#define bitop_uint_t uint32_t
>>>>
>>>> So no arch overrides permitted anymore at all?
>>> Not really, I agree that it is ugly, but I expected that arch will
>>> use
>>> undef to override.
>>
>> Which would be fine in principle, just that Misra wants us to avoid
>> #undef-s
>> (iirc).
> Could you please give me a recommendation how to do that better?
>
> The reason why I put this defintions before inclusion of asm/bitops.h
> as RISC-V specific code uses these definitions inside it, so they
> should be defined before asm/bitops.h; other option is to define these
> definitions inside asm/bitops.h for each architecture.

Earlier on you had it that other way already (in a different header,
but the principle is the same): Move the generic definitions immediately
past inclusion of asm/bitops.h and frame them with #ifndef.

Jan
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On Fri, 2024-04-05 at 08:11 +0200, Jan Beulich wrote:
> On 04.04.2024 18:24, Oleksii wrote:
> > On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
> > > On 04.04.2024 17:45, Oleksii wrote:
> > > > On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
> > > > > On 03.04.2024 12:19, Oleksii Kurochko wrote:
> > > > > > --- a/xen/include/xen/bitops.h
> > > > > > +++ b/xen/include/xen/bitops.h
> > > > > > @@ -65,10 +65,164 @@ static inline int
> > > > > > generic_flsl(unsigned
> > > > > > long
> > > > > > x)
> > > > > >   * scope
> > > > > >   */
> > > > > >  
> > > > > > +#define BITOP_BITS_PER_WORD 32
> > > > > > +/* typedef uint32_t bitop_uint_t; */
> > > > > > +#define bitop_uint_t uint32_t
> > > > >
> > > > > So no arch overrides permitted anymore at all?
> > > > Not really, I agree that it is ugly, but I expected that arch
> > > > will
> > > > use
> > > > undef to override.
> > >
> > > Which would be fine in principle, just that Misra wants us to
> > > avoid
> > > #undef-s
> > > (iirc).
> > Could you please give me a recommendation how to do that better?
> >
> > The reason why I put this defintions before inclusion of
> > asm/bitops.h
> > as RISC-V specific code uses these definitions inside it, so they
> > should be defined before asm/bitops.h; other option is to define
> > these
> > definitions inside asm/bitops.h for each architecture.
>
> Earlier on you had it that other way already (in a different header,
> but the principle is the same): Move the generic definitions
> immediately
> past inclusion of asm/bitops.h and frame them with #ifndef.
It can be done in this way:
xen/bitops.h:
...
#include <asm/bitops.h>

#ifndef BITOP_TYPE
#define BITOP_BITS_PER_WORD 32
/* typedef uint32_t bitop_uint_t; */
#define bitop_uint_t uint32_t
#endif
...

But then RISC-V will fail as it is using bitop_uint_t inside
asm/bitops.h.
So, at least, for RISC-V it will be needed to add asm/bitops.h:
#define BITOP_BITS_PER_WORD 32
/* typedef uint32_t bitop_uint_t; */
#define bitop_uint_t uint32_t


It seems to me that this breaks the idea of having these macro
definitions generic, as RISC-V will redefine BITOP_BITS_PER_WORD and
bitop_uint_t with the same values as the generic ones.

~ Oleksii

>
> Jan
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On 05.04.2024 09:56, Oleksii wrote:
> On Fri, 2024-04-05 at 08:11 +0200, Jan Beulich wrote:
>> On 04.04.2024 18:24, Oleksii wrote:
>>> On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
>>>> On 04.04.2024 17:45, Oleksii wrote:
>>>>> On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
>>>>>> On 03.04.2024 12:19, Oleksii Kurochko wrote:
>>>>>>> --- a/xen/include/xen/bitops.h
>>>>>>> +++ b/xen/include/xen/bitops.h
>>>>>>> @@ -65,10 +65,164 @@ static inline int
>>>>>>> generic_flsl(unsigned
>>>>>>> long
>>>>>>> x)
>>>>>>>   * scope
>>>>>>>   */
>>>>>>>  
>>>>>>> +#define BITOP_BITS_PER_WORD 32
>>>>>>> +/* typedef uint32_t bitop_uint_t; */
>>>>>>> +#define bitop_uint_t uint32_t
>>>>>>
>>>>>> So no arch overrides permitted anymore at all?
>>>>> Not really, I agree that it is ugly, but I expected that arch
>>>>> will
>>>>> use
>>>>> undef to override.
>>>>
>>>> Which would be fine in principle, just that Misra wants us to
>>>> avoid
>>>> #undef-s
>>>> (iirc).
>>> Could you please give me a recommendation how to do that better?
>>>
>>> The reason why I put this defintions before inclusion of
>>> asm/bitops.h
>>> as RISC-V specific code uses these definitions inside it, so they
>>> should be defined before asm/bitops.h; other option is to define
>>> these
>>> definitions inside asm/bitops.h for each architecture.
>>
>> Earlier on you had it that other way already (in a different header,
>> but the principle is the same): Move the generic definitions
>> immediately
>> past inclusion of asm/bitops.h and frame them with #ifndef.
> It can be done in this way:
> xen/bitops.h:
> ...
> #include <asm/bitops.h>
>
> #ifndef BITOP_TYPE
> #define BITOP_BITS_PER_WORD 32
> /* typedef uint32_t bitop_uint_t; */
> #define bitop_uint_t uint32_t
> #endif
> ...
>
> But then RISC-V will fail as it is using bitop_uint_t inside
> asm/bitops.h.
> So, at least, for RISC-V it will be needed to add asm/bitops.h:
> #define BITOP_BITS_PER_WORD 32
> /* typedef uint32_t bitop_uint_t; */
> #define bitop_uint_t uint32_t
>
>
> It seems to me that this breaks the idea of having these macro
> definitions generic, as RISC-V will redefine BITOP_BITS_PER_WORD and
> bitop_uint_t with the same values as the generic ones.

I don't follow. Right now patch 7 has

#undef BITOP_BITS_PER_WORD
#undef bitop_uint_t

#define BITOP_BITS_PER_WORD BITS_PER_LONG
#define bitop_uint_t unsigned long

You'd drop the #undef-s and keep the #define-s. You want to override them
both, after all.

A problem would arise for _another_ arch wanting to use these (default)
types in its asm/bitops.h. Which then could still be solved by having a
types-only header. Recall the discussion on the last summit of us meaning
to switch to such a model anyway (perhaps it being xen/types/bitops.h and
asm/types/bitops.h then), in a broader fashion? IOW for now you could use
the simple approach as long as no other arch needs the types in its
asm/bitops.h. Later we would introduce the types-only headers, thus
catering for possible future uses.

Jan
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On Fri, 2024-04-05 at 10:05 +0200, Jan Beulich wrote:
> On 05.04.2024 09:56, Oleksii wrote:
> > On Fri, 2024-04-05 at 08:11 +0200, Jan Beulich wrote:
> > > On 04.04.2024 18:24, Oleksii wrote:
> > > > On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
> > > > > On 04.04.2024 17:45, Oleksii wrote:
> > > > > > On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
> > > > > > > On 03.04.2024 12:19, Oleksii Kurochko wrote:
> > > > > > > > --- a/xen/include/xen/bitops.h
> > > > > > > > +++ b/xen/include/xen/bitops.h
> > > > > > > > @@ -65,10 +65,164 @@ static inline int
> > > > > > > > generic_flsl(unsigned
> > > > > > > > long
> > > > > > > > x)
> > > > > > > >   * scope
> > > > > > > >   */
> > > > > > > >  
> > > > > > > > +#define BITOP_BITS_PER_WORD 32
> > > > > > > > +/* typedef uint32_t bitop_uint_t; */
> > > > > > > > +#define bitop_uint_t uint32_t
> > > > > > >
> > > > > > > So no arch overrides permitted anymore at all?
> > > > > > Not really, I agree that it is ugly, but I expected that
> > > > > > arch
> > > > > > will
> > > > > > use
> > > > > > undef to override.
> > > > >
> > > > > Which would be fine in principle, just that Misra wants us to
> > > > > avoid
> > > > > #undef-s
> > > > > (iirc).
> > > > Could you please give me a recommendation how to do that
> > > > better?
> > > >
> > > > The reason why I put this defintions before inclusion of
> > > > asm/bitops.h
> > > > as RISC-V specific code uses these definitions inside it, so
> > > > they
> > > > should be defined before asm/bitops.h; other option is to
> > > > define
> > > > these
> > > > definitions inside asm/bitops.h for each architecture.
> > >
> > > Earlier on you had it that other way already (in a different
> > > header,
> > > but the principle is the same): Move the generic definitions
> > > immediately
> > > past inclusion of asm/bitops.h and frame them with #ifndef.
> > It can be done in this way:
> > xen/bitops.h:
> >    ...
> >    #include <asm/bitops.h>
> >   
> >    #ifndef BITOP_TYPE
> >    #define BITOP_BITS_PER_WORD 32
> >    /* typedef uint32_t bitop_uint_t; */
> >    #define bitop_uint_t uint32_t
> >    #endif
> >    ...
> >   
> > But then RISC-V will fail as it is using bitop_uint_t inside
> > asm/bitops.h.
> > So, at least, for RISC-V it will be needed to add asm/bitops.h:
> >    #define BITOP_BITS_PER_WORD 32
> >    /* typedef uint32_t bitop_uint_t; */
> >    #define bitop_uint_t uint32_t
> >   
> >
> > It seems to me that this breaks the idea of having these macro
> > definitions generic, as RISC-V will redefine BITOP_BITS_PER_WORD
> > and
> > bitop_uint_t with the same values as the generic ones.
>
> I don't follow. Right now patch 7 has
>
> #undef BITOP_BITS_PER_WORD
> #undef bitop_uint_t
>
> #define BITOP_BITS_PER_WORD BITS_PER_LONG
> #define bitop_uint_t unsigned long
>
> You'd drop the #undef-s and keep the #define-s. You want to override
> them
> both, after all.
>
> A problem would arise for _another_ arch wanting to use these
> (default)
> types in its asm/bitops.h. Which then could still be solved by having
> a
> types-only header.
This problem arise now for Arm and PPC which use BITOP_BITS_PER_WORD
inside it. Then it is needed to define BITOP_BITS_PER_WORD=32 in
asm/bitops.h for Arm and PPC. If it is okay, then I will happy to
follow this approach.

> Recall the discussion on the last summit of us meaning
> to switch to such a model anyway (perhaps it being xen/types/bitops.h
> and
> asm/types/bitops.h then), in a broader fashion? IOW for now you could
> use
> the simple approach as long as no other arch needs the types in its
> asm/bitops.h. Later we would introduce the types-only headers, thus
> catering for possible future uses.
Do we really need asm/types/bitops.h? Can't we just do the following in
asm/bitops.h:
#ifndef BITOP_TYPE
#include <xen/types/bitops.h>
#endif

~ Oleksii
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On Fri, 2024-04-05 at 13:53 +0200, Oleksii wrote:
> On Fri, 2024-04-05 at 10:05 +0200, Jan Beulich wrote:
> > On 05.04.2024 09:56, Oleksii wrote:
> > > On Fri, 2024-04-05 at 08:11 +0200, Jan Beulich wrote:
> > > > On 04.04.2024 18:24, Oleksii wrote:
> > > > > On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
> > > > > > On 04.04.2024 17:45, Oleksii wrote:
> > > > > > > On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
> > > > > > > > On 03.04.2024 12:19, Oleksii Kurochko wrote:
> > > > > > > > > --- a/xen/include/xen/bitops.h
> > > > > > > > > +++ b/xen/include/xen/bitops.h
> > > > > > > > > @@ -65,10 +65,164 @@ static inline int
> > > > > > > > > generic_flsl(unsigned
> > > > > > > > > long
> > > > > > > > > x)
> > > > > > > > >   * scope
> > > > > > > > >   */
> > > > > > > > >  
> > > > > > > > > +#define BITOP_BITS_PER_WORD 32
> > > > > > > > > +/* typedef uint32_t bitop_uint_t; */
> > > > > > > > > +#define bitop_uint_t uint32_t
> > > > > > > >
> > > > > > > > So no arch overrides permitted anymore at all?
> > > > > > > Not really, I agree that it is ugly, but I expected that
> > > > > > > arch
> > > > > > > will
> > > > > > > use
> > > > > > > undef to override.
> > > > > >
> > > > > > Which would be fine in principle, just that Misra wants us
> > > > > > to
> > > > > > avoid
> > > > > > #undef-s
> > > > > > (iirc).
> > > > > Could you please give me a recommendation how to do that
> > > > > better?
> > > > >
> > > > > The reason why I put this defintions before inclusion of
> > > > > asm/bitops.h
> > > > > as RISC-V specific code uses these definitions inside it, so
> > > > > they
> > > > > should be defined before asm/bitops.h; other option is to
> > > > > define
> > > > > these
> > > > > definitions inside asm/bitops.h for each architecture.
> > > >
> > > > Earlier on you had it that other way already (in a different
> > > > header,
> > > > but the principle is the same): Move the generic definitions
> > > > immediately
> > > > past inclusion of asm/bitops.h and frame them with #ifndef.
> > > It can be done in this way:
> > > xen/bitops.h:
> > >    ...
> > >    #include <asm/bitops.h>
> > >   
> > >    #ifndef BITOP_TYPE
> > >    #define BITOP_BITS_PER_WORD 32
> > >    /* typedef uint32_t bitop_uint_t; */
> > >    #define bitop_uint_t uint32_t
> > >    #endif
> > >    ...
> > >   
> > > But then RISC-V will fail as it is using bitop_uint_t inside
> > > asm/bitops.h.
> > > So, at least, for RISC-V it will be needed to add asm/bitops.h:
> > >    #define BITOP_BITS_PER_WORD 32
> > >    /* typedef uint32_t bitop_uint_t; */
> > >    #define bitop_uint_t uint32_t
> > >   
> > >
> > > It seems to me that this breaks the idea of having these macro
> > > definitions generic, as RISC-V will redefine BITOP_BITS_PER_WORD
> > > and
> > > bitop_uint_t with the same values as the generic ones.
> >
> > I don't follow. Right now patch 7 has
> >
> > #undef BITOP_BITS_PER_WORD
> > #undef bitop_uint_t
> >
> > #define BITOP_BITS_PER_WORD BITS_PER_LONG
> > #define bitop_uint_t unsigned long
> >
> > You'd drop the #undef-s and keep the #define-s. You want to
> > override
> > them
> > both, after all.
> >
> > A problem would arise for _another_ arch wanting to use these
> > (default)
> > types in its asm/bitops.h. Which then could still be solved by
> > having
> > a
> > types-only header.
> This problem arise now for Arm and PPC which use BITOP_BITS_PER_WORD
> inside it. Then it is needed to define BITOP_BITS_PER_WORD=32 in
> asm/bitops.h for Arm and PPC. If it is okay, then I will happy to
> follow this approach.
>
> >  Recall the discussion on the last summit of us meaning
> > to switch to such a model anyway (perhaps it being
> > xen/types/bitops.h
> > and
> > asm/types/bitops.h then), in a broader fashion? IOW for now you
> > could
> > use
> > the simple approach as long as no other arch needs the types in its
> > asm/bitops.h. Later we would introduce the types-only headers, thus
> > catering for possible future uses.
> Do we really need asm/types/bitops.h? Can't we just do the following
> in
> asm/bitops.h:
>   #ifndef BITOP_TYPE
>   #include <xen/types/bitops.h>
>   #endif
Or as an options just update <xen/types.h> with after inclusion of
<asm/types.h>:
#ifndef BITOP_TYPE
#define BITOP_BITS_PER_WORD 32
/* typedef uint32_t bitop_uint_t; */
#define bitop_uint_t uint32_t
#endif

And then just include <xen/types.h> to <<xen/bitops.h>.

~ Oleksii
>
> ~ Oleksii
Re: [PATCH v7 04/19] xen: introduce generic non-atomic test_*bit() [ In reply to ]
On 05.04.2024 13:56, Oleksii wrote:
> On Fri, 2024-04-05 at 13:53 +0200, Oleksii wrote:
>> On Fri, 2024-04-05 at 10:05 +0200, Jan Beulich wrote:
>>> On 05.04.2024 09:56, Oleksii wrote:
>>>> On Fri, 2024-04-05 at 08:11 +0200, Jan Beulich wrote:
>>>>> On 04.04.2024 18:24, Oleksii wrote:
>>>>>> On Thu, 2024-04-04 at 18:12 +0200, Jan Beulich wrote:
>>>>>>> On 04.04.2024 17:45, Oleksii wrote:
>>>>>>>> On Thu, 2024-04-04 at 15:22 +0200, Jan Beulich wrote:
>>>>>>>>> On 03.04.2024 12:19, Oleksii Kurochko wrote:
>>>>>>>>>> --- a/xen/include/xen/bitops.h
>>>>>>>>>> +++ b/xen/include/xen/bitops.h
>>>>>>>>>> @@ -65,10 +65,164 @@ static inline int
>>>>>>>>>> generic_flsl(unsigned
>>>>>>>>>> long
>>>>>>>>>> x)
>>>>>>>>>>   * scope
>>>>>>>>>>   */
>>>>>>>>>>  
>>>>>>>>>> +#define BITOP_BITS_PER_WORD 32
>>>>>>>>>> +/* typedef uint32_t bitop_uint_t; */
>>>>>>>>>> +#define bitop_uint_t uint32_t
>>>>>>>>>
>>>>>>>>> So no arch overrides permitted anymore at all?
>>>>>>>> Not really, I agree that it is ugly, but I expected that
>>>>>>>> arch
>>>>>>>> will
>>>>>>>> use
>>>>>>>> undef to override.
>>>>>>>
>>>>>>> Which would be fine in principle, just that Misra wants us
>>>>>>> to
>>>>>>> avoid
>>>>>>> #undef-s
>>>>>>> (iirc).
>>>>>> Could you please give me a recommendation how to do that
>>>>>> better?
>>>>>>
>>>>>> The reason why I put this defintions before inclusion of
>>>>>> asm/bitops.h
>>>>>> as RISC-V specific code uses these definitions inside it, so
>>>>>> they
>>>>>> should be defined before asm/bitops.h; other option is to
>>>>>> define
>>>>>> these
>>>>>> definitions inside asm/bitops.h for each architecture.
>>>>>
>>>>> Earlier on you had it that other way already (in a different
>>>>> header,
>>>>> but the principle is the same): Move the generic definitions
>>>>> immediately
>>>>> past inclusion of asm/bitops.h and frame them with #ifndef.
>>>> It can be done in this way:
>>>> xen/bitops.h:
>>>>    ...
>>>>    #include <asm/bitops.h>
>>>>   
>>>>    #ifndef BITOP_TYPE
>>>>    #define BITOP_BITS_PER_WORD 32
>>>>    /* typedef uint32_t bitop_uint_t; */
>>>>    #define bitop_uint_t uint32_t
>>>>    #endif
>>>>    ...
>>>>   
>>>> But then RISC-V will fail as it is using bitop_uint_t inside
>>>> asm/bitops.h.
>>>> So, at least, for RISC-V it will be needed to add asm/bitops.h:
>>>>    #define BITOP_BITS_PER_WORD 32
>>>>    /* typedef uint32_t bitop_uint_t; */
>>>>    #define bitop_uint_t uint32_t
>>>>   
>>>>
>>>> It seems to me that this breaks the idea of having these macro
>>>> definitions generic, as RISC-V will redefine BITOP_BITS_PER_WORD
>>>> and
>>>> bitop_uint_t with the same values as the generic ones.
>>>
>>> I don't follow. Right now patch 7 has
>>>
>>> #undef BITOP_BITS_PER_WORD
>>> #undef bitop_uint_t
>>>
>>> #define BITOP_BITS_PER_WORD BITS_PER_LONG
>>> #define bitop_uint_t unsigned long
>>>
>>> You'd drop the #undef-s and keep the #define-s. You want to
>>> override
>>> them
>>> both, after all.
>>>
>>> A problem would arise for _another_ arch wanting to use these
>>> (default)
>>> types in its asm/bitops.h. Which then could still be solved by
>>> having
>>> a
>>> types-only header.
>> This problem arise now for Arm and PPC which use BITOP_BITS_PER_WORD
>> inside it. Then it is needed to define BITOP_BITS_PER_WORD=32 in
>> asm/bitops.h for Arm and PPC. If it is okay, then I will happy to
>> follow this approach.
>>
>>>  Recall the discussion on the last summit of us meaning
>>> to switch to such a model anyway (perhaps it being
>>> xen/types/bitops.h
>>> and
>>> asm/types/bitops.h then), in a broader fashion? IOW for now you
>>> could
>>> use
>>> the simple approach as long as no other arch needs the types in its
>>> asm/bitops.h. Later we would introduce the types-only headers, thus
>>> catering for possible future uses.
>> Do we really need asm/types/bitops.h? Can't we just do the following
>> in
>> asm/bitops.h:
>>   #ifndef BITOP_TYPE
>>   #include <xen/types/bitops.h>
>>   #endif

This might do, yes.

> Or as an options just update <xen/types.h> with after inclusion of
> <asm/types.h>:
> #ifndef BITOP_TYPE
> #define BITOP_BITS_PER_WORD 32
> /* typedef uint32_t bitop_uint_t; */
> #define bitop_uint_t uint32_t
> #endif
>
> And then just include <xen/types.h> to <<xen/bitops.h>.

That's a (transient) option as well, I guess.

Jan