From e7844310d65fced89073e1a5fedb1d6fa406d4f6 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Fri, 26 Dec 2025 18:35:40 +0800 Subject: [PATCH] anolis: LoongArch: Fix AP booting issue in VM mode ANBZ: #31067 Native IPI is used for AP booting, because it is the booting interface between OS and BIOS firmware. The paravirt IPI is only used inside OS, and native IPI is necessary to boot AP. When booting AP, we write the kernel entry address in the HW mailbox of AP and send IPI interrupt to it. AP executes idle instruction and waits for interrupts or SW events, then clears IPI interrupt and jumps to the kernel entry from HW mailbox. Between writing HW mailbox and sending IPI, AP can be woken up by SW events and jumps to the kernel entry, so ACTION_BOOT_CPU IPI interrupt will keep pending during AP booting. And native IPI interrupt handler needs be registered so that it can clear pending native IPI, else there will be endless interrupts during AP booting stage. Here native IPI interrupt is initialized even if paravirt IPI is used. Cc: stable@vger.kernel.org Fixes: ("LoongArch: KVM: Add PV IPI support on guest side") Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen Signed-off-by: Xianglai Li Signed-off-by: Juxin Gao --- arch/loongarch/kernel/paravirt.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c index 9cc27c3feb69..56690e025258 100644 --- a/arch/loongarch/kernel/paravirt.c +++ b/arch/loongarch/kernel/paravirt.c @@ -50,11 +50,18 @@ static u64 paravt_steal_clock(int cpu) } #ifdef CONFIG_SMP +static struct smp_ops native_ops; + static void pv_send_ipi_single(int cpu, unsigned int action) { int min, old; irq_cpustat_t *info = &per_cpu(irq_stat, cpu); + if (unlikely(action == ACTION_BOOT_CPU)) { + native_ops.send_ipi_single(cpu, action); + return; + } + old = atomic_fetch_or(BIT(action), &info->message); if (old) return; @@ -74,6 +81,11 @@ static void pv_send_ipi_mask(const struct cpumask *mask, unsigned int action) if (cpumask_empty(mask)) return; + if (unlikely(action == ACTION_BOOT_CPU)) { + native_ops.send_ipi_mask(mask, action); + return; + } + action = BIT(action); for_each_cpu(i, mask) { info = &per_cpu(irq_stat, i); @@ -106,7 +118,7 @@ static void pv_send_ipi_mask(const struct cpumask *mask, unsigned int action) if (bitmap) kvm_hypercall3(KVM_HCALL_FUNC_IPI, (unsigned long)bitmap, - (unsigned long)(bitmap >> BITS_PER_LONG), min); + (unsigned long)(bitmap >> BITS_PER_LONG), min); } static irqreturn_t pv_ipi_interrupt(int irq, void *dev) @@ -129,6 +141,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev) info->ipi_irqs[IPI_CALL_FUNCTION]++; } + if (action & SMP_CLEAR_VECTOR) { + complete_irq_moving(); + info->ipi_irqs[IPI_CLEAR_VECTOR]++; + } + return IRQ_HANDLED; } @@ -136,6 +153,8 @@ static void pv_init_ipi(void) { int r, swi; + /* Init native ipi irq for ACTION_BOOT_CPU */ + native_ops.init_ipi(); swi = get_percpu_irq(INT_SWI0); if (swi < 0) panic("SWI0 IRQ mapping failed\n"); @@ -182,6 +201,7 @@ int __init pv_ipi_init(void) return 0; #ifdef CONFIG_SMP + native_ops = smp_ops; smp_ops.init_ipi = pv_init_ipi; smp_ops.send_ipi_single = pv_send_ipi_single; smp_ops.send_ipi_mask = pv_send_ipi_mask; -- Gitee