| 
    
 [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 2/5] xen/ppc: Implement bitops.h
 On 01.09.2023 20:25, Shawn Anastasio wrote:
> Implement bitops.h, based on Linux's implementation as of commit
> 5321d1b1afb9a17302c6cec79f0cbf823eb0d3fc. Though it is based off of
> Linux's implementation, this code diverges significantly in a number of
> ways:
>   - Bitmap entries changed to 32-bit words to match X86 and Arm on Xen
>   - PPC32-specific code paths dropped
>   - Formatting completely re-done to more closely line up with Xen.
>     Including 4 space indentation.
Isn't ...
> Signed-off-by: Shawn Anastasio <sanastasio@xxxxxxxxxxxxxxxxxxxxx>
> ---
> v3:
>   - Fix style of inline asm blocks.
>   - Fix underscore-prefixed macro parameters/variables
>   - Use __builtin_popcount for hweight* implementation
... this also a divergence worth calling out?
> --- a/xen/arch/ppc/include/asm/bitops.h
> +++ b/xen/arch/ppc/include/asm/bitops.h
> @@ -1,9 +1,333 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Adapted from Linux's arch/powerpc/include/asm/bitops.h.
> + *
> + * Merged version by David Gibson <david@xxxxxxxxxxxxxxxxxxxxx>.
> + * Based on ppc64 versions by: Dave Engebretsen, Todd Inglett, Don
> + * Reed, Pat McCarthy, Peter Bergner, Anton Blanchard.  They
> + * originally took it from the ppc32 code.
> + */
>  #ifndef _ASM_PPC_BITOPS_H
>  #define _ASM_PPC_BITOPS_H
> 
> +#include <asm/memory.h>
> +
> +#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))
With the switch to 32-bit operations, doesn't this want to be 1U?
> +#define BITOP_WORD(nr)          ((nr) / BITOP_BITS_PER_WORD)
> +#define BITS_PER_BYTE           8
> +
>  /* PPC bit number conversion */
> -#define PPC_BITLSHIFT(be)    (BITS_PER_LONG - 1 - (be))
> -#define PPC_BIT(bit)         (1UL << PPC_BITLSHIFT(bit))
> -#define PPC_BITMASK(bs, be)  ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
> +#define PPC_BITLSHIFT(be)    (BITS_PER_LONG - 1 - (be))
> +#define PPC_BIT(bit)         (1UL << PPC_BITLSHIFT(bit))
> +#define PPC_BITMASK(bs, be)  ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
> +
> +/* Macro for generating the ***_bits() functions */
> +#define DEFINE_BITOP(fn, op, prefix)                                         
>   \
> +static inline void fn(unsigned long mask,                                    
>   \
> +                      volatile unsigned int *p_)                             
>   \
> +{                                                                            
>   \
> +    unsigned long old;                                                       
>   \
> +    unsigned int *p = (unsigned int *)p_;                                    
>   \
> +    asm volatile ( prefix                                                    
>   \
> +                   "1: lwarx %0,0,%3,0\n"                                    
>   \
> +                   #op "%I2 %0,%0,%2\n"                                      
>   \
> +                   "stwcx. %0,0,%3\n"                                        
>   \
> +                   "bne- 1b\n"                                               
>   \
> +                   : "=&r" (old), "+m" (*p)                                  
>   \
> +                   : "rK" (mask), "r" (p)                                    
>   \
> +                   : "cc", "memory" );                                       
>   \
> +}
> +
> +DEFINE_BITOP(set_bits, or, "")
> +DEFINE_BITOP(change_bits, xor, "")
> +
> +#define DEFINE_CLROP(fn, prefix)                                             
>   \
> +static inline void fn(unsigned long mask, volatile unsigned int *_p)         
>   \
Leftover leading underscore.
> +{                                                                            
>   \
> +    unsigned long old;                                                       
>   \
> +    unsigned int *p = (unsigned int *)_p;                                    
>   \
> +    asm volatile ( prefix                                                    
>   \
> +                   "1: lwarx %0,0,%3,0\n"                                    
>   \
> +                   "andc %0,%0,%2\n"                                         
>   \
> +                   "stwcx. %0,0,%3\n"                                        
>   \
> +                   "bne- 1b\n"                                               
>   \
> +                   : "=&r" (old), "+m" (*p)                                  
>   \
> +                   : "r" (mask), "r" (p)                                     
>   \
> +                   : "cc", "memory" );                                       
>   \
> +}
> +
> +DEFINE_CLROP(clear_bits, "")
> +
> +static inline void set_bit(int nr, volatile void *addr)
> +{
> +    set_bits(BITOP_MASK(nr), (volatile unsigned int *)addr + BITOP_WORD(nr));
> +}
> +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 long *p = (const volatile unsigned long *)addr;
> +    return 1 & (p[BITOP_WORD(nr)] >> (nr & (BITOP_BITS_PER_WORD - 1)));
> +}
> +
> +static inline unsigned long test_and_clear_bits(unsigned long mask, volatile 
> void *_p)
Again. And there are more. Yet here (and below) ...
> +{
> +    unsigned long old, t;
> +    unsigned int *p = (unsigned int *)_p;
> +
> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER
> +                   "1: lwarx %0,0,%3,0\n"
> +                   "andc %1,%0,%2\n"
> +                   "stwcx. %1,0,%3\n"
> +                   "bne- 1b\n"
> +                   PPC_ATOMIC_EXIT_BARRIER
> +                   : "=&r" (old), "=&r" (t)
> +                   : "r" (mask), "r" (p)
> +                   : "cc", "memory" );
... do you actually need the helper variable, when there's no "+m"
constraint operand?
> +    return (old & mask);
> +}
> +
> +static inline int test_and_clear_bit(unsigned int nr,
> +                                     volatile void *addr)
> +{
> +    return test_and_clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
> +}
> +
> +#define DEFINE_TESTOP(fn, op, eh)                                            
>   \
> +static inline unsigned long fn(unsigned long mask, volatile unsigned int 
> *_p)  \
> +{                                                                            
>   \
> +    unsigned long old, t;                                                    
>   \
> +    unsigned int *p = (unsigned int *)_p;                                    
>   \
> +    asm volatile ( PPC_ATOMIC_ENTRY_BARRIER                                  
>   \
> +                   "1: lwarx %0,0,%3,%4\n"                                   
>   \
> +                   #op "%I2 %1,%0,%2\n"                                      
>   \
> +                   "stwcx. %1,0,%3\n"                                        
>   \
> +                   "bne- 1b\n"                                               
>   \
> +                   PPC_ATOMIC_EXIT_BARRIER                                   
>   \
> +                   : "=&r" (old), "=&r" (t)                                  
>   \
> +                   : "rK" (mask), "r" (p), "n" (eh)                          
>   \
> +                   : "cc", "memory" );                                       
>   \
> +    return (old & mask);                                                     
>   \
> +}
> +
> +DEFINE_TESTOP(test_and_set_bits, or, 0)
Why can't test_and_clear_bits() not use this macro-ization? And if it
can't and hence there's only this single use, wouldn't it make sense
to avoid going through a macro here, too?
> +static inline int test_and_set_bit(unsigned long nr, volatile void *addr)
> +{
> +    return test_and_set_bits(BITOP_MASK(nr), (volatile unsigned int *)addr +
> +                                             BITOP_WORD(nr)) != 0;
This wants wrapping differently, e.g.
static inline int test_and_set_bit(unsigned long nr, volatile void *addr)
{
    return test_and_set_bits(BITOP_MASK(nr),
                             (volatile unsigned int *)addr +
                             BITOP_WORD(nr)) != 0;
}
or
static inline int test_and_set_bit(unsigned long nr, volatile void *addr)
{
    return test_and_set_bits(
               BITOP_MASK(nr),
               (volatile unsigned int *)addr + BITOP_WORD(nr)) != 0;
}
> +#define flsl(x) generic_flsl(x)
> +#define fls(x) generic_fls(x)
> +#define ffs(x) ({ unsigned int t_ = (x); fls(t_ & - t_); })
> +#define ffsl(x) ({ unsigned long t_ = (x); flsl(t_ & - t_); })
Nit: No blanks after unary operators, please.
> +/* 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))
Nit: Stray double padding blank?
Jan
 
 
  | 
  
![]()  | 
            
         Lists.xenproject.org is hosted with RackSpace, monitoring our  |