[PATCH] LoongArch: Fix preemptible warnings in cacheinfo and local TLB flush

From: Tiezhu Yang

Date: Wed Nov 11 2026 - 06:38:39 EST


When CONFIG_DEBUG_PREEMPT is enabled on a Non-SMP kernel, calls to
smp_processor_id() (including via current_cpu_data) in preemptible
contexts trigger many "BUG: using smp_processor_id() in preemptible"
warnings during cacheinfo setup and local TLB flushes.

Moreover, accessing current CPU data without preemption disabled in
local TLB flushes is also unsafe on SMP systems.

Fix the callers properly:
- Use the passed-in 'cpu' parameter to index cpu_data[cpu] directly
in init_cache_level() and populate_cache_leaves().
- Protect the critical sections with get_cpu()/put_cpu() and reuse
cpu_data[cpu] in local_flush_tlb_{range, page}().
- Also convert local_flush_tlb_mm() to use get_cpu()/put_cpu() for
consistency.

This eliminates the warnings on Non-SMP builds while ensuring strict
preemption safety on SMP systems.

Fixes: b61a40afca16 ("LoongArch: Refactor cache probe and flush methods")
Fixes: 09cfefb7fa70 ("LoongArch: Add memory management")
Signed-off-by: Tiezhu Yang <yangtiezhu@xxxxxxxxxxx>
---
arch/loongarch/kernel/cacheinfo.c | 8 ++++----
arch/loongarch/mm/tlb.c | 22 +++++++++++-----------
2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/arch/loongarch/kernel/cacheinfo.c b/arch/loongarch/kernel/cacheinfo.c
index 8e231b0d2cd6..334d116e4c29 100644
--- a/arch/loongarch/kernel/cacheinfo.c
+++ b/arch/loongarch/kernel/cacheinfo.c
@@ -11,11 +11,11 @@

int init_cache_level(unsigned int cpu)
{
- int cache_present = current_cpu_data.cache_leaves_present;
+ int cache_present = cpu_data[cpu].cache_leaves_present;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);

this_cpu_ci->num_levels =
- current_cpu_data.cache_leaves[cache_present - 1].level;
+ cpu_data[cpu].cache_leaves[cache_present - 1].level;
this_cpu_ci->num_leaves = cache_present;

return 0;
@@ -67,10 +67,10 @@ static void cache_cpumap_setup(unsigned int cpu)

int populate_cache_leaves(unsigned int cpu)
{
- int i, cache_present = current_cpu_data.cache_leaves_present;
+ int i, cache_present = cpu_data[cpu].cache_leaves_present;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
struct cacheinfo *this_leaf = this_cpu_ci->info_list;
- struct cache_desc *cd, *cdesc = current_cpu_data.cache_leaves;
+ struct cache_desc *cd, *cdesc = cpu_data[cpu].cache_leaves;

for (i = 0; i < cache_present; i++) {
cd = cdesc + i;
diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c
index aaf7d685cc2a..ea52a55ca85e 100644
--- a/arch/loongarch/mm/tlb.c
+++ b/arch/loongarch/mm/tlb.c
@@ -40,25 +40,21 @@ EXPORT_SYMBOL(local_flush_tlb_kernel);
*/
void local_flush_tlb_mm(struct mm_struct *mm)
{
- int cpu;
-
- preempt_disable();
-
- cpu = smp_processor_id();
+ int cpu = get_cpu();

if (asid_valid(mm, cpu))
drop_mmu_context(mm, cpu);
else
cpumask_clear_cpu(cpu, mm_cpumask(mm));

- preempt_enable();
+ put_cpu();
}

void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
struct mm_struct *mm = vma->vm_mm;
- int cpu = smp_processor_id();
+ int cpu = get_cpu();

if (asid_valid(mm, cpu)) {
unsigned long size, flags;
@@ -67,9 +63,9 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
start = round_down(start, PAGE_SIZE << 1);
end = round_up(end, PAGE_SIZE << 1);
size = (end - start) >> (PAGE_SHIFT + 1);
- if (size <= (current_cpu_data.tlbsizestlbsets ?
- current_cpu_data.tlbsize / 8 :
- current_cpu_data.tlbsize / 2)) {
+ if (size <= (cpu_data[cpu].tlbsizestlbsets ?
+ cpu_data[cpu].tlbsize / 8 :
+ cpu_data[cpu].tlbsize / 2)) {
int asid = cpu_asid(cpu, mm);

while (start < end) {
@@ -83,6 +79,8 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
} else {
cpumask_clear_cpu(cpu, mm_cpumask(mm));
}
+
+ put_cpu();
}

void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
@@ -112,7 +110,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)

void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
- int cpu = smp_processor_id();
+ int cpu = get_cpu();

if (asid_valid(vma->vm_mm, cpu)) {
int newpid;
@@ -123,6 +121,8 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
} else {
cpumask_clear_cpu(cpu, mm_cpumask(vma->vm_mm));
}
+
+ put_cpu();
}

/*
--
2.42.0