Re: [PATCH V4 07/22] LoongArch: Add atomic/locking headers

From: Huacai Chen
Date: Sat Oct 02 2021 - 07:48:15 EST


Hi, Peter,

On Fri, Oct 1, 2021 at 6:54 PM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:
>
> On Mon, Sep 27, 2021 at 02:42:44PM +0800, Huacai Chen wrote:
> > diff --git a/arch/loongarch/include/asm/bitops.h b/arch/loongarch/include/asm/bitops.h
> > new file mode 100644
> > index 000000000000..8b05d9683571
> > --- /dev/null
> > +++ b/arch/loongarch/include/asm/bitops.h
> > @@ -0,0 +1,220 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2020-2021 Loongson Technology Corporation Limited
> > + */
> > +#ifndef _ASM_BITOPS_H
> > +#define _ASM_BITOPS_H
> > +
> > +#ifndef _LINUX_BITOPS_H
> > +#error only <linux/bitops.h> can be included directly
> > +#endif
> > +
> > +#include <linux/compiler.h>
> > +#include <linux/types.h>
> > +#include <asm/barrier.h>
> > +#include <asm/byteorder.h>
> > +#include <asm/compiler.h>
> > +#include <asm/cpu-features.h>
> > +
> > +#if _LOONGARCH_SZLONG == 32
> > +#define __LL "ll.w "
> > +#define __SC "sc.w "
> > +#define __AMADD "amadd.w "
> > +#define __AMAND_SYNC "amand_db.w "
> > +#define __AMOR_SYNC "amor_db.w "
> > +#define __AMXOR_SYNC "amxor_db.w "
> > +#elif _LOONGARCH_SZLONG == 64
> > +#define __LL "ll.d "
> > +#define __SC "sc.d "
> > +#define __AMADD "amadd.d "
> > +#define __AMAND_SYNC "amand_db.d "
> > +#define __AMOR_SYNC "amor_db.d "
> > +#define __AMXOR_SYNC "amxor_db.d "
> > +#endif
> > +
> > +/*
> > + * set_bit - Atomically set a bit in memory
> > + * @nr: the bit to set
> > + * @addr: the address to start counting from
> > + */
> > +static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMOR_SYNC "$zero, %1, %0 \n"
> > + : "+ZB" (*m)
> > + : "r" (1UL << bit)
> > + : "memory");
> > +}
> > +
> > +/*
> > + * clear_bit - Clears a bit in memory
> > + * @nr: Bit to clear
> > + * @addr: Address to start counting from
> > + */
> > +static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMAND_SYNC "$zero, %1, %0 \n"
> > + : "+ZB" (*m)
> > + : "r" (~(1UL << bit))
> > + : "memory");
> > +}
> > +
> > +/*
> > + * clear_bit_unlock - Clears a bit in memory
> > + * @nr: Bit to clear
> > + * @addr: Address to start counting from
> > + */
> > +static inline void clear_bit_unlock(unsigned long nr, volatile unsigned long *addr)
> > +{
> > + clear_bit(nr, addr);
> > +}
> > +
> > +/*
> > + * change_bit - Toggle a bit in memory
> > + * @nr: Bit to change
> > + * @addr: Address to start counting from
> > + */
> > +static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMXOR_SYNC "$zero, %1, %0 \n"
> > + : "+ZB" (*m)
> > + : "r" (1UL << bit)
> > + : "memory");
> > +}
> > +
> > +/*
> > + * test_and_set_bit - Set a bit and return its old value
> > + * @nr: Bit to set
> > + * @addr: Address to count from
> > + */
> > +static inline int test_and_set_bit(unsigned long nr,
> > + volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + unsigned long res;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMOR_SYNC "%1, %2, %0 \n"
> > + : "+ZB" (*m), "=&r" (res)
> > + : "r" (1UL << bit)
> > + : "memory");
> > +
> > + res = res & (1UL << bit);
> > +
> > + return res != 0;
> > +}
> > +
> > +/*
> > + * test_and_set_bit_lock - Set a bit and return its old value
> > + * @nr: Bit to set
> > + * @addr: Address to count from
> > + */
> > +static inline int test_and_set_bit_lock(unsigned long nr,
> > + volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + unsigned long res;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMOR_SYNC "%1, %2, %0 \n"
> > + : "+ZB" (*m), "=&r" (res)
> > + : "r" (1UL << bit)
> > + : "memory");
> > +
> > + res = res & (1UL << bit);
> > +
> > + return res != 0;
> > +}
> > +/*
> > + * test_and_clear_bit - Clear a bit and return its old value
> > + * @nr: Bit to clear
> > + * @addr: Address to count from
> > + */
> > +static inline int test_and_clear_bit(unsigned long nr,
> > + volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + unsigned long res, temp;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMAND_SYNC "%1, %2, %0 \n"
> > + : "+ZB" (*m), "=&r" (temp)
> > + : "r" (~(1UL << bit))
> > + : "memory");
> > +
> > + res = temp & (1UL << bit);
> > +
> > + return res != 0;
> > +}
> > +
> > +/*
> > + * test_and_change_bit - Change a bit and return its old value
> > + * @nr: Bit to change
> > + * @addr: Address to count from
> > + */
> > +static inline int test_and_change_bit(unsigned long nr,
> > + volatile unsigned long *addr)
> > +{
> > + int bit = nr % BITS_PER_LONG;
> > + unsigned long res;
> > + volatile unsigned long *m = &addr[BIT_WORD(nr)];
> > +
> > + __asm__ __volatile__(
> > + " " __AMXOR_SYNC "%1, %2, %0 \n"
> > + : "+ZB" (*m), "=&r" (res)
> > + : "r" (1UL << bit)
> > + : "memory");
> > +
> > + res = res & (1UL << bit);
> > +
> > + return res != 0;
> > +}
>
> Why is asm-generic/bitops/atomic.h not working for you?
It seems that __clear_bit_unlock() needs an additional mb() after the
generic version, all other functions are the same as the generic
version.

Huacai
>