Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Vladimir Murzin <vladimir.murzin@arm.com>
To: Mark Rutland <mark.rutland@arm.com>,
	linux-arm-kernel@lists.infradead.org
Cc: peterz@infradead.org, maz@kernel.org, hca@linux.ibm.com,
	linux-kernel@vger.kernel.org, ruanjinjie@huawei.com,
	yang@os.amperecomputing.com, catalin.marinas@arm.com,
	will@kernel.org, ardb@kernel.org
Subject: Re: [RFC PATCH 06/13] arm64: percpu: Add infrastructure for preemptible this_cpu_*() ops
Date: Wed, 29 Jul 2026 15:25:52 +0100	[thread overview]
Message-ID: <ea269924-b563-44b9-bdf3-31072ec93375@arm.com> (raw)
In-Reply-To: <20260728123859.2911495-7-mark.rutland@arm.com>

On 7/28/26 13:38, Mark Rutland wrote:
> Currently arm64's this_cpu_*() ops transiently disable preemption in
> order to guarantee that the address generation and memory access(es)
> occur on the same CPU.
> 
> Transiently disabling preemption can be  expensive. When re-enabling
> preemption it is necessary to make a conditional function call to
> preempt_schedule[_notrace]() in order to handle the rare case that the
> task needs to be rescheduled. The potential function call has a number
> of negative effects on code generation (e.g. due to the need to create a
> stack frame and spill registers), and the conditionality can result in
> poor code generation and/or poor branch prediction.
> 
> This patch adds infrastructure for a scheme where this_cpu_*() ops do
> not need to transiently disable preemption, avoiding the negative
> impacts described above.
> 
> Each operation registers a critical section during which the exception
> return code will adjust the offset and addresses if preemption occurs
> mid-sequence. The critical section is registered/unregistered with a
> small prologue and epilogue which encodes three distinct GPRRs (<pcp>,
> <off>, <addr>) into a new thread_info::pcp_gprs field:
> 
>          // Prologue. Enable fixups for <off> and <addr>.
>          mrs	<tsk>, sp_el0
>          mov	<tmp>, #__VAL_PCPU_GPRS(<pcp>, <off>, <addr>)
>          strh	<tmp>, [<tsk>, #TSK_TI_PCPU_GPRS]
> 
>          // Generate cpu-specific address
>          mrs	<off>, TPIDR_ELx
>          add	<addr>, <pcp>, <off>
> 
>          // Perform access sequence
>          ldr	<val>, [<addr>]
> 
>          // Epilogue. Disable fixups
>          strh	wzr, [<tsk>, #TSK_TI_PCPU_GPRS]
> 
> If an exception is taken from within the critical section, the exception
> return code will adjust <off> to be the current CPU's offset, and will
> adjust <addr> to be (<pcp> + <off>). Distinct registers are used for
> <pcp>, <off>, and <addr>, so that the fixup can be applied safely at any
> point during the critical section.
> 
> To ensure that this_cpu_*() operations within exception handlers work
> correctly and do not corrupt state, thread_info::pcpu_gprs is saved
> into a new pt_regs::pcpu_gprs field upon exception entry, and restored
> upon exception return.
> 
> Looking at a simple this_cpu_operation:
> 
> | void outline_this_cpu_add_u64(u64 __percpu *p, u64 v)
> | {
> | 	this_cpu_add(*p, v);
> | }
> 
> Atop v7.2-rc4, with GCC 15.2.0 and defconfig, this is compiled as:
> 
> | <outline_this_cpu_add_u64>:
> |        paciasp
> |        stp     x29, x30, [sp, #-16]!
> |        mrs     x2, sp_el0
> |        mov     x29, sp
> |        ldr     w3, [x2, #8]
> |        add     w3, w3, #0x1
> |        str     w3, [x2, #8]
> |        mrs     x3, tpidr_el1
> |        add     x0, x0, x3
> | 1:     ldxr    x5, [x0]
> |        add     x5, x5, x1
> |        stxr    w4, x5, [x0]
> |        cbnz    w4, 1b
> |        ldr     x0, [x2, #8]
> |        sub     x0, x0, #0x1
> |        str     w0, [x2, #8]
> |        cbz     x0, 2f
> |        ldr     x0, [x2, #8]
> |        cbnz    x0, 3f
> | 2:     bl      preempt_schedule_notrace
> | 3:     ldp     x29, x30, [sp], #16
> |        autiasp
> |        ret
> 
> With the scheme added in this patch, this can be compiled as:
> 
> | <outline_this_cpu_add_u64>:
> |        mrs     x2, sp_el0
> |        mov     x4, #0xc80
> |        strh    w4, [x2, #20]
> |        mrs     x4, tpidr_el1
> |        add     x3, x0, x4
> | 1:     ldxr    x6, [x3]
> |        add     x6, x6, x1
> |        stxr    w5, x6, [x3]
> |        cbnz    w5, 1b
> |        strh    wzr, [x2, #20]
> |        ret
> 
> TODO: Save/restore the PCPU GPRs in __sdei_asm_handler(). This will
> require some mechanical rework to the __sdei_asm_handler() assembly.
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com>
> Cc: Ard Biesheuvel <ardb@kernel.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Jinjie Ruan <ruanjinjie@huawei.com>
> Cc: Marc Zyngier <maz@kernel.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Vladimir Murzin <vladimir.murzin@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: Yang Shi <yang@os.amperecomputing.com>
> ---
>  arch/arm64/include/asm/percpu.h      | 43 ++++++++++++++++++++++++++++
>  arch/arm64/include/asm/ptrace.h      |  5 ++++
>  arch/arm64/include/asm/thread_info.h |  1 +
>  arch/arm64/kernel/asm-offsets.c      |  2 ++
>  arch/arm64/kernel/entry-common.c     | 38 ++++++++++++++++++++++++
>  arch/arm64/kernel/entry.S            | 13 +++++++++
>  6 files changed, 102 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
> index 98823c97d534c..0871dcc41d759 100644
> --- a/arch/arm64/include/asm/percpu.h
> +++ b/arch/arm64/include/asm/percpu.h
> @@ -5,10 +5,12 @@
>  #ifndef __ASM_PERCPU_H
>  #define __ASM_PERCPU_H
>  
> +#include <linux/bits.h>
>  #include <linux/preempt.h>
>  
>  #include <asm/alternative.h>
>  #include <asm/cmpxchg.h>
> +#include <asm/gpr-num.h>
>  #include <asm/stack_pointer.h>
>  #include <asm/sysreg.h>
>  
> @@ -51,6 +53,47 @@ static inline unsigned long __kern_my_cpu_offset(void)
>  	return off;
>  }
>  
> +#define PCPU_GPR_PCP			GENMASK(4, 0)
> +#define PCPU_GPR_OFF			GENMASK(9, 5)
> +#define PCPU_GPR_ADDR			GENMASK(14, 10)
> +
> +#define __VAL_PCPU_GPRS(pcp, off, addr)				\
> +	"("							\
> +		"(.L__gpr_num_" pcp  " << 0) | "		\
> +		"(.L__gpr_num_" off  " << 5) | "		\
> +		"(.L__gpr_num_" addr " << 10)"			\
> +	")"

Later in the patch, there is a comment stating that these registers
are not expected to overlap. I can also see that early-clobber
constraints are applied to the output registers later in the patch
series, so the code is correct.

However, would it be possible to add assertions that detect register
overlap, perhaps something like:

".if (.L__gpr_num_" pcp "== .L__gpr_num_" off ") ||"	\
"    (.L__gpr_num_" pcp "== .L__gpr_num_" addr ") ||"	\
"    (.L__gpr_num_" off "== .L__gpr_num_" addr")"	\
".error "inline asm registers overlap"			\
".endif"						\

or any other (better) way.

Such assertions would serve both as documentation and as a strong
guarantee that the registers are distinct.


Cheers
Vladimir


  parent reply	other threads:[~2026-07-29 14:26 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-28 12:38 [RFC PATCH 00/13] arm64: Preemptible this_cpu_*() operations Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 01/13] arm64: preempt: Simplify and optimize __preempt_count_dec_and_test() Mark Rutland
2026-07-29  3:56   ` Jinjie Ruan
2026-07-28 12:38 ` [RFC PATCH 02/13] arm64: preempt: Treat should_resched() as unlikely Mark Rutland
2026-07-29  4:00   ` Jinjie Ruan
2026-07-28 12:38 ` [RFC PATCH 03/13] arm64: ptrace: Always inline pt_regs_[read,write}_reg() Mark Rutland
2026-07-29  4:02   ` Jinjie Ruan
2026-07-28 12:38 ` [RFC PATCH 04/13] arm64: percpu: Factor out percpu offset asm Mark Rutland
2026-07-29  4:03   ` Jinjie Ruan
2026-07-28 12:38 ` [RFC PATCH 05/13] arm64: gpr-num: Add wxN aliases for wN registers Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 06/13] arm64: percpu: Add infrastructure for preemptible this_cpu_*() ops Mark Rutland
2026-07-28 14:19   ` Peter Zijlstra
2026-07-28 14:30     ` Peter Zijlstra
2026-07-28 16:03       ` Mark Rutland
2026-07-28 16:49         ` Peter Zijlstra
2026-07-28 15:53     ` Mark Rutland
2026-07-28 16:46       ` Peter Zijlstra
2026-07-28 16:49       ` Peter Zijlstra
2026-08-04 13:23         ` Mark Rutland
2026-07-28 16:51   ` Heiko Carstens
2026-07-29  8:16     ` Heiko Carstens
2026-07-29 14:25   ` Vladimir Murzin [this message]
2026-07-30 10:59     ` Mark Rutland
2026-07-30 12:04       ` Vladimir Murzin
2026-07-28 12:38 ` [RFC PATCH 07/13] arm64: percpu: Implement preemptible read/write ops Mark Rutland
2026-07-28 21:47   ` David Laight
2026-08-04 15:00     ` Mark Rutland
2026-07-28 22:05   ` David Laight
2026-08-04 15:05     ` Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 08/13] arm64: percpu: Implement preemptible void RMW ops Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 09/13] arm64: percpu: Implement preemptible return " Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 10/13] arm64: percpu: Implement preemptible XCHG ops Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 11/13] arm64: percpu: Implement preemptible CMPXCHG ops Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 12/13] arm64: percpu: Implement preemptible CMPXCHG128 ops Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 13/13] arm64: percpu: Remove _pcp_protect*() wrappers Mark Rutland

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=ea269924-b563-44b9-bdf3-31072ec93375@arm.com \
    --to=vladimir.murzin@arm.com \
    --cc=ardb@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=hca@linux.ibm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=peterz@infradead.org \
    --cc=ruanjinjie@huawei.com \
    --cc=will@kernel.org \
    --cc=yang@os.amperecomputing.com \
    /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