Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/13] arm64: Preemptible this_cpu_*() operations
@ 2026-07-28 12:38 Mark Rutland
  2026-07-28 12:38 ` [RFC PATCH 01/13] arm64: preempt: Simplify and optimize __preempt_count_dec_and_test() Mark Rutland
                   ` (12 more replies)
  0 siblings, 13 replies; 22+ messages in thread
From: Mark Rutland @ 2026-07-28 12:38 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, vladimir.murzin, peterz, catalin.marinas, hca,
	linux-kernel, ruanjinjie, yang, maz, will, ardb

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, which has some unfortunate overhead. In
particular, re-enabling preemption requires a conditional call to
preempt_schedule[_notrace](), which has a number of adverse impacts on
code generation.

This series reworks arm64's this_cpu_*() operations such that they do
not need to disable preemption, avoiding the related overhead in the
fast paths. Instead, the ope register a "PCPU GPR" critical section,
during which which the entry code will apply a fixup to GPRs containing
the percpu offset and the generated percpu address.

The scheme is described in detail in patch 6, and is similar to the
approach Heiko Carstens applied to s390 [1].

For example, an outlined this_cpu_read() goes from:

| <outline_this_cpu_write_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
|        str     x1, [x0, x3]
|        ldr     x0, [x2, #8]
|        sub     x0, x0, #0x1
|        str     w0, [x2, #8]
|        cbz     x0, 1f
|        ldr     x0, [x2, #8]
|        cbnz    x0, 2f
| 1:     bl      preempt_schedule_notrace
| 2:     ldp     x29, x30, [sp], #16
|        autiasp
|        ret

... to:

| <outline_this_cpu_write_u64>:
|        mrs     x2, sp_el0
|        mov     w3, #0x7c60
|        strh    w3, [x2, #20]
|        mrs     x3, tpidr_el1
|        str     x1, [x0, x3]
|        strh    wzr, [x2, #20]
|        ret

Comparing defconfig before and after, the Image size is reduced by 64K, though
.text is only reduced by ~7.5K:

| [mark@lakrids:~/src/linux]% ls -al Image-defconfig-*
| -rw-r--r-- 1 mark mark 41552384 Jul 28 11:07 Image-defconfig-after
| -rw-r--r-- 1 mark mark 41617920 Jul 28 11:01 Image-defconfig-v7.2-rc4
| [mark@lakrids:~/src/linux]% ls -al vmlinux-defconfig-*
| -rwxr-xr-x 1 mark mark 158239216 Jul 28 11:07 vmlinux-defconfig-after
| -rwxr-xr-x 1 mark mark 158699800 Jul 28 11:01 vmlinux-defconfig-v7.2-rc4
| [mark@lakrids:~/src/linux]% size vmlinux-defconfig-*
|    text    data     bss     dec     hex filename
| 20323522        21028511         730840 42082873        2822239 vmlinux-defconfig-after
| 20331206        21028447         730840 42090493        2823ffd vmlinux-defconfig-v7.2-rc4

From looking at the generated code, there are some reasonable savings we
could make with a few changes to alternatives, notably:

* Patching the read of TPIDR_ELx using a callback. This would remove the
  need for replacement instructions, saving ~12K for defconfig, and
  meaning real instructions in .text would be packed more densely.
  There's work underway to apply similar patching for
  ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE.

* Allowing {relocation,veneer}-free replacement sequences to be placed
  in .altinst_rreplacement again. This would allow real instructions in
  .text to be packed more densely, with ~80K of .text moving into
  .altinstr_replacement where it would be freed after init.

  I've thrown togther a prototype [2].

I'm sending this as an RFC as:

(1) I haven't had the chance to benchmark this. While I think the
    changes look good from inspection, we should obviously get some
    actual performance figures.

(2) I haven't wired up everything for SDEI exception entry/return.
    This should only require some mechinical rework to the
    __sdei_asm_handler() assembly, and I've noted this as a TODO on
    patch 6.

    Patches 1 and 2 are complete as-is, and can be taken without the
    rest of the series.

(3) I'm not sure whether this_cpu_read() should use a plain LDR, or use
    LDA[P]R when LTO is in use to match READ_ONCE(). Using LDA[P]R 
    might require some refactoring of the existing READ_ONCE() code to
    share the logic.

    I've noted this as a question on patch 7.

Thanks,
Mark.

[1] https://lore.kernel.org/linux-s390/20260526055702.1429061-1-hca@linux.ibm.com/
[2] https://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git/log/?h=arm64/alternatives/cleanup
 
Mark Rutland (13):
  arm64: preempt: Simplify and optimize __preempt_count_dec_and_test()
  arm64: preempt: Treat should_resched() as unlikely
  arm64: ptrace: Always inline pt_regs_[read,write}_reg()
  arm64: percpu: Factor out percpu offset asm
  arm64: gpr-num: Add wxN aliases for wN registers
  arm64: percpu: Add infrastructure for preemptible this_cpu_*() ops
  arm64: percpu: Implement preemptible read/write ops
  arm64: percpu: Implement preemptible void RMW ops
  arm64: percpu: Implement preemptible return RMW ops
  arm64: percpu: Implement preemptible XCHG ops
  arm64: percpu: Implement preemptible CMPXCHG ops
  arm64: percpu: Implement preemptible CMPXCHG128 ops
  arm64: percpu: Remove _pcp_protect*() wrappers

 arch/arm64/include/asm/gpr-num.h     |   5 +
 arch/arm64/include/asm/percpu.h      | 437 +++++++++++++++++++++------
 arch/arm64/include/asm/preempt.h     |  29 +-
 arch/arm64/include/asm/ptrace.h      |  12 +-
 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 +
 8 files changed, 417 insertions(+), 120 deletions(-)

-- 
2.30.2



^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2026-07-28 16:52 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-28 12:38 ` [RFC PATCH 02/13] arm64: preempt: Treat should_resched() as unlikely Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 03/13] arm64: ptrace: Always inline pt_regs_[read,write}_reg() Mark Rutland
2026-07-28 12:38 ` [RFC PATCH 04/13] arm64: percpu: Factor out percpu offset asm Mark Rutland
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-07-28 16:51   ` Heiko Carstens
2026-07-28 12:38 ` [RFC PATCH 07/13] arm64: percpu: Implement preemptible read/write ops 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox