qemu/hw-loongarch-Add-KVM-IPI-device-support.patch

401 lines
13 KiB
Diff
Raw Normal View History

QEMU update to version 8.2.0-27: - fix compile error on loongarch - hw/loongarch: fix cpu hotplug reset - hw/loongarch/boot: Use warn_report when no kernel filename - hw/loongarch: clean code - hw/loongarch: Add KVM pch msi device support - hw/loongarch: Add KVM pch pic device support - hw/loongarch: Add KVM extioi device support - hw/loongarch: Add KVM IPI device support - hw/loongarch/virt: Update the ACPI table for hotplug cpu - hw/loongarch/virt: Add basic CPU plug support - hw/loongarch/virt: Add CPU topology support - accel/kvm/kvm-all: Fixes the missing break in vCPU unpark logic - gdbstub: Add helper function to unregister GDB register space - physmem: Add helper function to destroy CPU AddressSpace - hw/acpi: Update CPUs AML with cpu-(ctrl)dev change - hw/acpi: Update ACPI GED framework to support vCPU Hotplug - hw/acpi: Move CPU ctrl-dev MMIO region len macro to common header file - accel/kvm: Extract common KVM vCPU {creation,parking} code - target/loongarch: Add steal time support on migration - linux-headers: loongarch: Add kvm_para.h and unistd_64.h - target/loongarch/kvm: Implement LoongArch PMU extension - target/loongarch: Implement lbt registers save/restore function - target/loongarch: Add loongson binary translation feature - sync loongarch linux-headers - target/loongarch: Avoid bits shift exceeding width of bool type - target/loongarch: Use explicit little-endian LD/ST API - target/loongarch: fix -Werror=maybe-uninitialized false-positive - target/loongarch: Support QMP dump-guest-memory - target/loongarch/kvm: Add vCPU reset function - target/loongarch: Add compatible support about VM reboot - target/loongarch: Fix cpu_reset set wrong CSR_CRMD - target/loongarch: Set CSR_PRCFG1 and CSR_PRCFG2 values - target/loongarch: Remove avail_64 in trans_srai_w() and simplify it - target/loongarch/kvm: Add software breakpoint support - target/loongarch: Add loongarch vector property unconditionally - target/loongarch/kvm: Fix VM recovery from disk failures - target/loongarch: Put cpucfg operation before CSR register - target/loongarch: Add TCG macro in structure CPUArchState - hw/arm/virt-acpi-build.c: Migrate SPCR creation to common location - hw/loongarch/virt: Add FDT table support with acpi ged pm register - hw/loongarch/virt: Add description for virt machine type - hw/loongarch: Add acpi SPCR table support - hw/loongarch: virt: pass random seed to fdt - hw/loongarch: virt: support up to 4 serial ports - hw/loongarch: Remove default enable with VIRTIO_VGA device - hw/loongarch: Fix length for lowram in ACPI SRAT - hw/loongarch/virt: Remove unused assignment - hw/loongarch: Change the tpm support by default - hw/loongarch/boot.c: fix out-of-bound reading - hw/loongarch/virt: Use MemTxAttrs interface for misc ops - tests/libqos: Add loongarch virt machine node - hw/loongarch: Remove minimum and default memory size - hw/loongarch: Refine system dram memory region - hw/loongarch: Refine fwcfg memory map - hw/loongarch: Refine fadt memory table for numa memory - hw/loongarch: Refine acpi srat table for numa memory - hw/loongarch: Add VM mode in IOCSR feature register in kvm mode - hw/loongarch: Refine default numa id calculation - hw/loongarch: Rename LoongArchMachineState with LoongArchVirtMachineState - hw/loongarch: Rename LOONGARCH_MACHINE with LOONGARCH_VIRT_MACHINE - hw/loongarch: move memory map to boot.c - loongarch: switch boards to "default y" - hw/loongarch: Add cells missing from rtc node - hw/loongarch: Add cells missing from uart node - hw/loongarch: fdt remove unused irqchip node - hw/loongarch: fdt adds pcie irq_map node - hw/loongarch: fdt adds pch_msi Controller - hw/loongarch: fdt adds pch_pic Controller - hw/loongarch: fdt adds Extend I/O Interrupt Controller - hw/loongarch: fdt adds cpu interrupt controller node - hw/loongarch: Init efi_fdt table - hw/loongarch: Init efi_initrd table - hw/loongarch: Init efi_boot_memmap table - hw/loongarch: Init efi_system_table - hw/loongarch: Add init_cmdline - hw/loongarch: Add slave cpu boot_code - hw/loongarch: Add load initrd - hw/loongarch: Move boot functions to boot.c Signed-off-by: Xianglai Li <lixianglai@loongson.cn> (cherry picked from commit 04ca9e6c8ff19630116722240ae0136cea831c5c)
2024-12-13 19:50:22 +08:00
From 24e4e6742bdc8d804760e84f4e4bde5460e1e024 Mon Sep 17 00:00:00 2001
From: gaosong <gaosong@loongson.cn>
Date: Sun, 8 Sep 2024 09:29:00 +0800
Subject: [PATCH 72/78] hw/loongarch: Add KVM IPI device support
Added ipi interrupt controller for kvm emulation.
The main process is to send the command word for
creating an ipi device to the kernel.
When the VM is saved, the ioctl obtains the ipi
interrupt controller data in the kernel and saves it.
When the VM is recovered, the saved data is sent to the kernel.
Signed-off-by: gaosong <gaosong@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
hw/intc/Kconfig | 3 +
hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/Kconfig | 1 +
hw/loongarch/virt.c | 35 ++++--
include/hw/intc/loongarch_ipi.h | 23 ++++
linux-headers/linux/kvm.h | 2 +
target/loongarch/kvm/kvm.c | 4 +
8 files changed, 263 insertions(+), 13 deletions(-)
create mode 100644 hw/intc/loongarch_ipi_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 97d550b06b..cbba74c22e 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -93,6 +93,9 @@ config NIOS2_VIC
config LOONGARCH_IPI
bool
+config LOONGARCH_IPI_KVM
+ bool
+
config LOONGARCH_PCH_PIC
bool
select UNIMP
diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c
new file mode 100644
index 0000000000..fd308eb0c0
--- /dev/null
+++ b/hw/intc/loongarch_ipi_kvm.c
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm ipi interrupt support
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "qemu/typedefs.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
+#define IPI_DEV_FD_UNDEF -1
+
+static void kvm_ipi_access_regs(int fd, uint64_t addr,
+ uint32_t *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_ipi_pre_save(void *opaque)
+{
+ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque;
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi);
+ IPICore *cpu;
+ uint64_t attr;
+ int cpu_id = 0;
+ int fd = ipi_class->dev_fd;
+
+ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) {
+ cpu = &ipi->cpu[cpu_id];
+ attr = (cpu_id << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->status, false);
+
+ attr = (cpu_id << 16) | CORE_EN_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->en, false);
+
+ attr = (cpu_id << 16) | CORE_SET_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->set, false);
+
+ attr = (cpu_id << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->clear, false);
+
+ attr = (cpu_id << 16) | CORE_BUF_20;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_28;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_30;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], false);
+
+ attr = (cpu_id << 16) | CORE_BUF_38;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], false);
+ }
+
+ return 0;
+}
+
+static int kvm_loongarch_ipi_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchIPI *ipi = (KVMLoongArchIPI *)opaque;
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(ipi);
+ IPICore *cpu;
+ uint64_t attr;
+ int cpu_id = 0;
+ int fd = ipi_class->dev_fd;
+
+ for (cpu_id = 0; cpu_id < ipi->num_cpu; cpu_id++) {
+ cpu = &ipi->cpu[cpu_id];
+ attr = (cpu_id << 16) | CORE_STATUS_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->status, true);
+
+ attr = (cpu_id << 16) | CORE_EN_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->en, true);
+
+ attr = (cpu_id << 16) | CORE_SET_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->set, true);
+
+ attr = (cpu_id << 16) | CORE_CLEAR_OFF;
+ kvm_ipi_access_regs(fd, attr, &cpu->clear, true);
+
+ attr = (cpu_id << 16) | CORE_BUF_20;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[0], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_28;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[2], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_30;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[4], true);
+
+ attr = (cpu_id << 16) | CORE_BUF_38;
+ kvm_ipi_access_regs(fd, attr, &cpu->buf[6], true);
+ }
+
+ return 0;
+}
+
+static void kvm_loongarch_ipi_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchIPI *ipi = KVM_LOONGARCH_IPI(dev);
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ Error *err = NULL;
+ int ret;
+
+ if (ipi->num_cpu == 0) {
+ error_setg(errp, "num-cpu must be at least 1");
+ return;
+ }
+
+ ipi_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ ipi->cpu = g_new0(IPICore, ipi->num_cpu);
+ if (ipi->cpu == NULL) {
+ error_setg(errp, "Memory allocation for ExtIOICore faile");
+ return;
+ }
+
+ if (!ipi_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_IPI;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno, "Creating the KVM device failed");
+ return;
+ }
+ ipi_class->is_created = true;
+ ipi_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch IPI irqchip in KVM done!\n");
+ }
+
+ assert(ipi_class->dev_fd != IPI_DEV_FD_UNDEF);
+}
+
+static Property kvm_loongarch_ipi_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", KVMLoongArchIPI, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_kvm_ipi_core = {
+ .name = "kvm-ipi-single",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(status, IPICore),
+ VMSTATE_UINT32(en, IPICore),
+ VMSTATE_UINT32(set, IPICore),
+ VMSTATE_UINT32(clear, IPICore),
+ VMSTATE_UINT32_ARRAY(buf, IPICore, 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_kvm_loongarch_ipi = {
+ .name = TYPE_KVM_LOONGARCH_IPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_ipi_pre_save,
+ .post_load = kvm_loongarch_ipi_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, KVMLoongArchIPI, num_cpu,
+ vmstate_kvm_ipi_core, IPICore),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void kvm_loongarch_ipi_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchIPIClass *ipi_class = KVM_LOONGARCH_IPI_CLASS(oc);
+
+ ipi_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_ipi_realize;
+
+ ipi_class->is_created = false;
+ ipi_class->dev_fd = IPI_DEV_FD_UNDEF;
+
+ device_class_set_props(dc, kvm_loongarch_ipi_properties);
+
+ dc->vmsd = &vmstate_kvm_loongarch_ipi;
+}
+
+static const TypeInfo kvm_loongarch_ipi_info = {
+ .name = TYPE_KVM_LOONGARCH_IPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchIPI),
+ .class_size = sizeof(KVMLoongArchIPIClass),
+ .class_init = kvm_loongarch_ipi_class_init,
+};
+
+static void kvm_loongarch_ipi_register_types(void)
+{
+ type_register_static(&kvm_loongarch_ipi_info);
+}
+
+type_init(kvm_loongarch_ipi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index ed355941d1..9deeeb51bb 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -70,6 +70,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_kvm.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index b42a8573d4..1e761624c6 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -14,6 +14,7 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
+ select LOONGARCH_IPI_KVM if KVM
select LS7A_RTC
select SMBIOS
select ACPI_CPU_HOTPLUG
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 6159fd9470..f065eb75f8 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -829,16 +829,28 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
* +--------+ +---------+ +---------+
*/
- /* Create IPI device */
- ipi = qdev_new(TYPE_LOONGARCH_IPI);
- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
-
- /* IPI iocsr memory region */
- memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
- memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ ipi = qdev_new(TYPE_KVM_LOONGARCH_IPI);
+ qdev_prop_set_int32(ipi, "num-cpu", ms->smp.max_cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+ } else {
+ ipi = qdev_new(TYPE_LOONGARCH_IPI);
+ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.max_cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+
+ /* IPI iocsr memory region */
+ memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
+ memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpu_state = qemu_get_cpu(cpu);
+ cpudev = DEVICE(cpu_state);
+
+ /* connect ipi irq to cpu irq */
+ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
+ }
+ }
/* Add cpu interrupt-controller */
fdt_add_cpuic_node(lvms, &cpuintc_phandle);
@@ -849,9 +861,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
lacpu = LOONGARCH_CPU(cpu_state);
env = &(lacpu->env);
env->address_space_iocsr = &lvms->as_iocsr;
-
- /* connect ipi irq to cpu irq */
- qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
env->ipistate = ipi;
}
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
index 1c1e834849..601b4f18a7 100644
--- a/include/hw/intc/loongarch_ipi.h
+++ b/include/hw/intc/loongarch_ipi.h
@@ -32,6 +32,7 @@
#define TYPE_LOONGARCH_IPI "loongarch_ipi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
+#define TYPE_KVM_LOONGARCH_IPI "loongarch-ipi-kvm"
typedef struct IPICore {
uint32_t status;
@@ -51,4 +52,26 @@ struct LoongArchIPI {
IPICore *cpu;
};
+struct KVMLoongArchIPI {
+ SysBusDevice parent_obj;
+ uint32_t num_cpu;
+ IPICore *cpu;
+};
+typedef struct KVMLoongArchIPI KVMLoongArchIPI;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchIPI, KVM_LOONGARCH_IPI,
+ TYPE_KVM_LOONGARCH_IPI)
+
+struct KVMLoongArchIPIClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+
+};
+typedef struct KVMLoongArchIPIClass KVMLoongArchIPIClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchIPIClass, KVM_LOONGARCH_IPI,
+ TYPE_KVM_LOONGARCH_IPI)
+
+
#endif
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index eb30402c2d..ea1f821a9f 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1470,6 +1470,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME
KVM_DEV_TYPE_RISCV_AIA,
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
+ KVM_DEV_TYPE_LA_IPI,
+#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI
KVM_DEV_TYPE_MAX,
};
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 550f14269e..ab1ea3d4fd 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1066,6 +1066,10 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
+ if(!kvm_vm_check_attr(kvm_state, KVM_LOONGARCH_VM_HAVE_IRQCHIP, KVM_LOONGARCH_VM_HAVE_IRQCHIP)) {
+ s->kernel_irqchip_allowed = false;
+ }
+
return 0;
}
--
2.39.1