[PATCH 07/11] arm64: mm: introduce __per_cpu_local_off

From: Yang Shi

Date: Wed Apr 29 2026 - 13:16:16 EST


this_cpu_*() ops will use it to get the local percpu address. It has
the same value for all CPUs.

Also introduce pcpu_local_base, which is the base address of local
percpu map.

Signed-off-by: Yang Shi <yang@xxxxxxxxxxxxxxxxxxxxxx>
---
arch/arm64/kernel/smp.c | 4 ++++
include/linux/percpu.h | 2 ++
mm/percpu.c | 3 +++
3 files changed, 9 insertions(+)

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 4caa6ebec12f..62afabf86ba1 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -825,6 +825,9 @@ extern int cpu_to_node_map[NR_CPUS];

unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(__per_cpu_offset);
+/* Used to calculate pcpu local address, the offset is same for all CPUs */
+unsigned long __per_cpu_local_off __read_mostly;
+EXPORT_SYMBOL(__per_cpu_local_off);

int early_cpu_to_node(int cpu)
{
@@ -847,6 +850,7 @@ void __init setup_per_cpu_areas(void)
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
for_each_possible_cpu(cpu)
__per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
+ __per_cpu_local_off = (unsigned long)pcpu_local_base - (unsigned long)__per_cpu_start;
}

static const char *ipi_types[MAX_IPI] __tracepoint_string = {
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index dba050f5b548..e29ebd265087 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -74,6 +74,8 @@

extern void *pcpu_base_addr;
extern const unsigned long *pcpu_unit_offsets;
+/* percpu local mapping base */
+extern void *pcpu_local_base;

struct pcpu_group_info {
int nr_units; /* aligned # of units */
diff --git a/mm/percpu.c b/mm/percpu.c
index 5148c5ccf9e3..17d0c2b0de5a 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -145,6 +145,8 @@ static unsigned int pcpu_high_unit_cpu __ro_after_init;

/* the address of the first chunk which starts with the kernel static area */
void *pcpu_base_addr __ro_after_init;
+/* The address of the first chunk local mapping */
+void *pcpu_local_base __ro_after_init;

static const int *pcpu_unit_map __ro_after_init; /* cpu -> unit */
const unsigned long *pcpu_unit_offsets __ro_after_init; /* cpu -> unit offset */
@@ -3297,6 +3299,7 @@ int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_to_node_fn_t
ai->reserved_size, ai->dyn_size);

pcpu_setup_first_chunk(ai, vm.addr, pcpu_vm.addr);
+ pcpu_local_base = pcpu_vm.addr;
goto out_free_ar;

enomem:
--
2.47.0