Commit b6239f74 authored by Bibo Mao's avatar Bibo Mao Committed by Xianglai Li
Browse files

LoongArch: Fix AP booting issue in VM mode

mainline inclusion
from mainline-v6.12
commit 6ce031e5d6f475d476bab55ab7d8ea168fedc4c1
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAZJDO


CVE: NA

--------------------------------

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: 74c16b2e2b0c ("LoongArch: KVM: Add PV IPI support on guest side")
Signed-off-by: default avatarBibo Mao <maobibo@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
parent a5a22987
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -129,11 +129,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)
{
	unsigned 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;
@@ -152,6 +159,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);
@@ -213,6 +225,8 @@ static void pv_init_ipi(void)
{
	int r, swi0;

	/* Init native ipi irq for ACTION_BOOT_CPU */
	native_ops.init_ipi();
	swi0 = get_percpu_irq(INT_SWI0);
	if (swi0 < 0)
		panic("SWI0 IRQ mapping failed\n");
@@ -285,6 +299,7 @@ int __init pv_ipi_init(void)
		return 0;

#ifdef CONFIG_SMP
	native_ops		= mp_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;