mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Will Deacon <will.deacon@arm.com>
To: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Daniel Lustig <dlustig@nvidia.com>, Arnd Bergmann <arnd@arndb.de>,
	Olof Johansson <olof@lixom.net>,
	linux-kernel@vger.kernel.org, patches@groups.riscv.org,
	peterz@infradead.org, boqun.feng@gmail.com
Subject: Re: [PATCH v9 05/12] RISC-V: Atomic and Locking Code
Date: Wed, 15 Nov 2017 18:06:01 +0000	[thread overview]
Message-ID: <20171115180600.GR19071@arm.com> (raw)
In-Reply-To: <mhng-f07acce6-f1e0-4f6b-ad20-7a6921f089ea@palmer-si-x1c4>

Hi Palmer,

On Tue, Nov 14, 2017 at 12:30:59PM -0800, Palmer Dabbelt wrote:
> On Tue, 24 Oct 2017 07:10:33 PDT (-0700), will.deacon@arm.com wrote:
> >On Tue, Sep 26, 2017 at 06:56:31PM -0700, Palmer Dabbelt wrote:
> >>+ATOMIC_OPS(add, add, +,  i)
> >>+ATOMIC_OPS(sub, add, +, -i)
> >>+ATOMIC_OPS(and, and, &,  i)
> >>+ATOMIC_OPS( or,  or, |,  i)
> >>+ATOMIC_OPS(xor, xor, ^,  i)
> >
> >What is the point in the c_op parameter to these things?
> 
> I guess there isn't one, it just lingered from a handful of refactorings.
> It's used in some of the other functions if we need to do a C operation
> after the atomic.  How does this look?
> 
> commit 5db229491a205ad0e1aa18287e3b342176c62d30 (HEAD -> staging-mm)
> Author: Palmer Dabbelt <palmer@dabbelt.com>
> Date:   Tue Nov 14 11:35:37 2017 -0800
> 
>    RISC-V: Remove c_op from ATOMIC_OP
> 
>    This was an unused macro parameter.
> 
>    Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>

You can do the same thing for FETCH_OP, I think.

> >>+ATOMIC_OPS(add, add, +,  i,      , _relaxed)
> >>+ATOMIC_OPS(add, add, +,  i, .aq  , _acquire)
> >>+ATOMIC_OPS(add, add, +,  i, .rl  , _release)
> >>+ATOMIC_OPS(add, add, +,  i, .aqrl,         )
> >
> >Have you checked that .aqrl is equivalent to "ordered", since there are
> >interpretations where that isn't the case. Specifically:
> >
> >// all variables zero at start of time
> >P0:
> >WRITE_ONCE(x) = 1;
> >atomic_add_return(y, 1);
> >WRITE_ONCE(z) = 1;
> >
> >P1:
> >READ_ONCE(z) // reads 1
> >smp_rmb();
> >READ_ONCE(x) // must not read 0
> 
> I haven't.  We don't quite have a formal memory model specification yet.
> I've added Daniel Lustig, who is creating that model.  He should have a
> better idea

Thanks. You really do need to ensure that, as it's heavily relied upon.

> >>+/* These barriers do not need to enforce ordering on devices, just memory. */
> >>+#define smp_mb()	RISCV_FENCE(rw,rw)
> >>+#define smp_rmb()	RISCV_FENCE(r,r)
> >>+#define smp_wmb()	RISCV_FENCE(w,w)
> >>+
> >>+/*
> >>+ * These fences exist to enforce ordering around the relaxed AMOs.  The
> >>+ * documentation defines that
> >>+ * "
> >>+ *     atomic_fetch_add();
> >>+ *   is equivalent to:
> >>+ *     smp_mb__before_atomic();
> >>+ *     atomic_fetch_add_relaxed();
> >>+ *     smp_mb__after_atomic();
> >>+ * "
> >>+ * So we emit full fences on both sides.
> >>+ */
> >>+#define __smb_mb__before_atomic()	smp_mb()
> >>+#define __smb_mb__after_atomic()	smp_mb()
> >
> >Now I'm confused, because you're also spitting out .aqrl for those afaict.
> >Do you really need full barriers *and* .aqrl, or am I misunderstanding
> >something here?
> 
> Here's the section of atomic_t.txt that I was reading
> 
>    The barriers:
>      smp_mb__{before,after}_atomic()
>    only apply to the RMW ops and can be used to augment/upgrade the ordering
>    inherent to the used atomic op. These barriers provide a full smp_mb().
>    These helper barriers exist because architectures have varying implicit
>    ordering on their SMP atomic primitives. For example our TSO architectures
>    provide full ordered atomics and these barriers are no-ops.
>    Thus:
>      atomic_fetch_add();
>    is equivalent to:
>      smp_mb__before_atomic();
>      atomic_fetch_add_relaxed();
>      smp_mb__after_atomic();
>    However the atomic_fetch_add() might be implemented more efficiently.
> 
> so I think what we've got there is correct: the barriers go with
> atomic_fetch_add_relaxed(), not atomic_fetch_add().  asm-generic/barrier.h
> has
> 
>    #ifndef __smp_mb__before_atomic
>    #define __smp_mb__before_atomic()       __smp_mb()
>    #endif
>    #ifndef __smp_mb__after_atomic
>    #define __smp_mb__after_atomic()        __smp_mb()
>    #endif
> 
> so I think we can just drop these entirely.  How does this look?
> 
> commit da682f7ee5d2af4aae7026ef40b5b5fb8e103938
> Author: Palmer Dabbelt <palmer@dabbelt.com>
> Date:   Tue Nov 14 11:49:42 2017 -0800
> 
>    RISC-V: Remove __smp_bp__{before,after}_atomic
> 
>    These duplicate the asm-generic definitions are therefor aren't useful.
> 
>    Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>

Yes, that looks good to me. I was misunderstanding things, but you're right
that you don't need to do anything special for this.

> >>+
> >>+/*
> >>+ * These barriers prevent accesses performed outside a spinlock from being moved
> >>+ * inside a spinlock.  Since RISC-V sets the aq/rl bits on our spinlock only
> >>+ * enforce release consistency, we need full fences here.
> >>+ */
> >>+#define smb_mb__before_spinlock()	smp_mb()
> >
> >We killed this macro, so you don't need to define it.
> 
> Thanks!
> 
> commit 382a1f8b33a04fc0f991e062f70f4c65ca888bca
> Author: Palmer Dabbelt <palmer@dabbelt.com>
> Date:   Tue Nov 14 11:50:37 2017 -0800
> 
>    RISC-V: Remove smb_mb__{before,after}_spinlock()
> 
>    These are obselete.
> 
>    Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
> 
> diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h
> index 455ee16127fb..773c4e039cd7 100644
> --- a/arch/riscv/include/asm/barrier.h
> +++ b/arch/riscv/include/asm/barrier.h
> @@ -38,14 +38,6 @@
> #define smp_rmb()	RISCV_FENCE(r,r)
> #define smp_wmb()	RISCV_FENCE(w,w)
> 
> -/*
> - * These barriers prevent accesses performed outside a spinlock from being moved
> - * inside a spinlock.  Since RISC-V sets the aq/rl bits on our spinlock only
> - * enforce release consistency, we need full fences here.
> - */
> -#define smb_mb__before_spinlock()	smp_mb()
> -#define smb_mb__after_spinlock()	smp_mb()

You might still need the __after version, particularly if your lock
operation has only acquire semantics. The __before version has been removed.

> >>+#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);				\
> >>+})
> >
> >This looks broken to me -- the value-returning test bitops need to be fully
> >ordered.
> 
> Yep, you're right -- I just mis-read atomic_ops.rst (and re-misread it the
> first time when I went to check again).  I think this should do it
> 
> commit 9951b6ed76bffb714517d81d9ffceb0eb1796229
> Author: Palmer Dabbelt <palmer@dabbelt.com>
> Date:   Tue Nov 14 12:06:06 2017 -0800
> 
>    RISC-V: __test_and_op_bit_ord should be strongly ordered
> 
>    I mis-read the documentation.
> 
>    Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
> 
> diff --git a/arch/riscv/include/asm/bitops.h b/arch/riscv/include/asm/bitops.h
> index 7c281ef1d583..f30daf26f08f 100644
> --- a/arch/riscv/include/asm/bitops.h
> +++ b/arch/riscv/include/asm/bitops.h
> @@ -67,7 +67,7 @@
> 		: "memory");
> 
> #define __test_and_op_bit(op, mod, nr, addr) 			\
> -	__test_and_op_bit_ord(op, mod, nr, addr, )
> +	__test_and_op_bit_ord(op, mod, nr, addr, .aqrl)

Yes, modulo my earlier comment and litmus test.

> >>+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
> >>+#define arch_spin_is_locked(x)	((x)->lock != 0)
> >
> >Missing READ_ONCE.
> 
> Thanks!
> 
> commit 64e80b0bf3898a88de09f4e12090b002b57efede
> Author: Palmer Dabbelt <palmer@dabbelt.com>
> Date:   Tue Nov 14 12:18:49 2017 -0800
> 
>    RISC-V: Add READ_ONCE in arch_spin_is_locked()
>    Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>

Also looks good.

> >>+static inline void arch_read_lock(arch_rwlock_t *lock)
> >>+{
> >>+	int tmp;
> >>+
> >>+	__asm__ __volatile__(
> >>+		"1:	lr.w	%1, %0\n"
> >>+		"	bltz	%1, 1b\n"
> >>+		"	addi	%1, %1, 1\n"
> >>+		"	sc.w.aq	%1, %1, %0\n"
> >>+		"	bnez	%1, 1b\n"
> >>+		: "+A" (lock->lock), "=&r" (tmp)
> >>+		:: "memory");
> >>+}
> >>+
> >>+static inline void arch_write_lock(arch_rwlock_t *lock)
> >>+{
> >>+	int tmp;
> >>+
> >>+	__asm__ __volatile__(
> >>+		"1:	lr.w	%1, %0\n"
> >>+		"	bnez	%1, 1b\n"
> >>+		"	li	%1, -1\n"
> >>+		"	sc.w.aq	%1, %1, %0\n"
> >>+		"	bnez	%1, 1b\n"
> >>+		: "+A" (lock->lock), "=&r" (tmp)
> >>+		:: "memory");
> >>+}
> >
> >I think you have the same starvation issues as we have on arm64 here. I
> >strongly recommend moving over to qrwlock :)

I still strongly recommend this!

> >
> >>+#ifndef _ASM_RISCV_TLBFLUSH_H
> >>+#define _ASM_RISCV_TLBFLUSH_H
> >>+
> >>+#ifdef CONFIG_MMU
> >>+
> >>+/* Flush entire local TLB */
> >>+static inline void local_flush_tlb_all(void)
> >>+{
> >>+	__asm__ __volatile__ ("sfence.vma" : : : "memory");
> >>+}
> >>+
> >>+/* Flush one page from local TLB */
> >>+static inline void local_flush_tlb_page(unsigned long addr)
> >>+{
> >>+	__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory");
> >>+}
> >
> >Is this serialised against prior updates to the page table (set_pte) and
> >also against subsequent instruction fetch?
> 
> This is a store -> (load, store) fence.  The ordering is between stores that
> touch paging data structures and the implicit loads that come from any
> memory access when paging is enabled.  As far as I can tell, it does not
> enforce any instruction fetch ordering constraints.

That sounds pretty suspicious to me. You need to ensure that speculative
instruction fetch doesn't fetch instructions from the old mapping. Also,
store -> (load, store) fences don't generally order the page table walk,
which is what you need to order here.

Will

  reply	other threads:[~2017-11-15 18:06 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-27  1:56 RISC-V Linux Port v9 Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 01/12] MAINTAINERS: Add RISC-V Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 02/12] lib: Add shared copies of some GCC library routines Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 03/12] dt-bindings: RISC-V CPU Bindings Palmer Dabbelt
2017-10-05 10:16   ` Mark Rutland
2017-11-20  7:35     ` [patches] " Jonathan Neuschäfer
2017-11-20 19:45       ` Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 04/12] RISC-V: Init and Halt Code Palmer Dabbelt
2017-10-05 11:01   ` Mark Rutland
2018-07-30 23:42     ` Palmer Dabbelt
2018-07-31 13:03       ` Mark Rutland
2017-09-27  1:56 ` [PATCH v9 05/12] RISC-V: Atomic and Locking Code Palmer Dabbelt
2017-10-24 14:10   ` Will Deacon
2017-11-14 20:30     ` Palmer Dabbelt
2017-11-15 18:06       ` Will Deacon [this message]
2017-11-15 19:48         ` [patches] " Palmer Dabbelt
2017-11-15 23:59           ` Daniel Lustig
2017-11-16  1:19             ` Boqun Feng
2017-11-16  1:31               ` Daniel Lustig
2017-11-16  1:52                 ` Boqun Feng
2017-11-16  6:40                   ` Daniel Lustig
2017-11-16 10:25                     ` Will Deacon
2017-11-16 17:12                       ` Daniel Lustig
2017-11-16  2:08             ` Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 06/12] RISC-V: Generic library routines and assembly Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 07/12] RISC-V: ELF and module implementation Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 08/12] RISC-V: Task implementation Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 09/12] RISC-V: Device, timer, IRQs, and the SBI Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 10/12] RISC-V: Paging and MMU Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 11/12] RISC-V: User-facing API Palmer Dabbelt
2017-09-27  1:56 ` [PATCH v9 12/12] RISC-V: Build Infrastructure Palmer Dabbelt
2017-09-27  6:08 ` RISC-V Linux Port v9 Arnd Bergmann
2017-10-05  0:21   ` Palmer Dabbelt
2017-10-05  7:34     ` Arnd Bergmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171115180600.GR19071@arm.com \
    --to=will.deacon@arm.com \
    --cc=arnd@arndb.de \
    --cc=boqun.feng@gmail.com \
    --cc=dlustig@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=olof@lixom.net \
    --cc=palmer@dabbelt.com \
    --cc=patches@groups.riscv.org \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome