* [RFC 0/4] Added Interrupt controller emulation for loongarch kvm
@ 2024-07-17 3:29 Xianglai Li
2024-07-17 3:29 ` [RFC 1/4] hw/loongarch: Add KVM IPI device support Xianglai Li
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Xianglai Li @ 2024-07-17 3:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Song Gao, Huacai Chen, Jiaxun Yang,
Michael S. Tsirkin, Cornelia Huck, kvm, Bibo Mao
Before this, the interrupt controller simulation has been completed
in the user mode program. In order to reduce the loss caused by frequent
switching of the virtual machine monitor from kernel mode to user mode
when the guest accesses the interrupt controller, we add the interrupt
controller simulation in kvm.
In qemu side implementation is simple, just make a new IPI EXTIOI PCH KVM
related several classes, And the interface to access kvm related data is
implemented.
Most of the simulation work of the interrupt controller is done in kvm.
Because KVM the changes have not been the Linux community acceptance,
the patches of this series will have RFC label until KVM patch into the community.
For the implementation of kvm simulation, refer to the following documents.
IPI simulation implementation reference:
https://github.com/loongson/LoongArch-Documentation/tree/main/docs/Loongson-3A5000-usermanual-EN/inter-processor-interrupts-and-communication
EXTIOI simulation implementation reference:
https://github.com/loongson/LoongArch-Documentation/tree/main/docs/Loongson-3A5000-usermanual-EN/io-interrupts/extended-io-interrupts
PCH-PIC simulation implementation reference:
https://github.com/loongson/LoongArch-Documentation/blob/main/docs/Loongson-7A1000-usermanual-EN/interrupt-controller.adoc
For PCH-MSI, we used irqfd mechanism to send the interrupt signal
generated by user state to kernel state and then to EXTIOI without
maintaining PCH-MSI state in kernel state.
You can easily get the code from the link below:
the kernel:
https://github.com/lixianglai/linux
the branch is: interrupt
the qemu:
https://github.com/lixianglai/qemu
the branch is: interrupt
Please note that the code above is regularly updated based on community
reviews.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Song Gao <gaosong@loongson.cn>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: kvm@vger.kernel.org
Cc: Bibo Mao <maobibo@loongson.cn>
Xianglai Li (4):
hw/loongarch: Add KVM IPI device support
hw/loongarch: Add KVM extioi device support
hw/loongarch: Add KVM pch pic device support
hw/loongarch: Add KVM pch msi device support
hw/intc/Kconfig | 12 ++
hw/intc/loongarch_extioi_kvm.c | 141 +++++++++++++++++++
hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++
hw/intc/loongarch_pch_msi.c | 42 ++++--
hw/intc/loongarch_pch_pic.c | 20 ++-
hw/intc/loongarch_pch_pic_kvm.c | 189 +++++++++++++++++++++++++
hw/intc/meson.build | 3 +
hw/loongarch/virt.c | 141 ++++++++++++-------
include/hw/intc/loongarch_extioi.h | 34 ++++-
include/hw/intc/loongarch_pch_msi.h | 2 +-
include/hw/intc/loongarch_pch_pic.h | 51 ++++++-
include/hw/intc/loongson_ipi.h | 22 +++
include/hw/loongarch/virt.h | 15 ++
linux-headers/asm-loongarch/kvm.h | 7 +
linux-headers/linux/kvm.h | 6 +
15 files changed, 823 insertions(+), 69 deletions(-)
create mode 100644 hw/intc/loongarch_extioi_kvm.c
create mode 100644 hw/intc/loongarch_ipi_kvm.c
create mode 100644 hw/intc/loongarch_pch_pic_kvm.c
--
2.39.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC 1/4] hw/loongarch: Add KVM IPI device support
2024-07-17 3:29 [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Xianglai Li
@ 2024-07-17 3:29 ` Xianglai Li
2024-07-17 3:29 ` [RFC 2/4] hw/loongarch: Add KVM extioi " Xianglai Li
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Xianglai Li @ 2024-07-17 3:29 UTC (permalink / raw)
To: qemu-devel
Cc: Tianrui Zhao, Paolo Bonzini, Song Gao, Huacai Chen, Jiaxun Yang,
Michael S. Tsirkin, Cornelia Huck, kvm, Bibo Mao
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: Tianrui Zhao <zhaotianrui@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Song Gao <gaosong@loongson.cn>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: kvm@vger.kernel.org
Cc: Bibo Mao <maobibo@loongson.cn>
hw/intc/Kconfig | 4 +
hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/virt.c | 40 ++++--
include/hw/intc/loongson_ipi.h | 22 ++++
| 1 +
| 2 +
target/loongarch/kvm/kvm.c | 1 +
8 files changed, 265 insertions(+), 13 deletions(-)
create mode 100644 hw/intc/loongarch_ipi_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 58b6d3a710..19d6809129 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -90,6 +90,10 @@ config M68K_IRQC
config LOONGSON_IPI
bool
+config LOONGARCH_IPI_KVM
+ bool
+ default y
+
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..5dc78847e6
--- /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/loongson_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 afd1aa51ee..354d43b4f0 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -70,6 +70,7 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
if_true: files('spapr_xive_kvm.c'))
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_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/virt.c b/hw/loongarch/virt.c
index e592b1b6b7..2ae5298b62 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -48,6 +48,7 @@
#include "hw/block/flash.h"
#include "hw/virtio/virtio-iommu.h"
#include "qemu/error-report.h"
+#include "sysemu/kvm.h"
static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
{
@@ -788,15 +789,32 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
*/
/* Create IPI device */
- ipi = qdev_new(TYPE_LOONGSON_IPI);
- qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.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_kernel_irqchip_allowed()) {
+ ipi = qdev_new(TYPE_KVM_LOONGARCH_IPI);
+ qdev_prop_set_int32(ipi, "num-cpu", ms->smp.cpus);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+ } else {
+ ipi = qdev_new(TYPE_LOONGSON_IPI);
+ qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.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);
+ lacpu = LOONGARCH_CPU(cpu_state);
+ env = &(lacpu->env);
+
+ /* connect ipi irq to cpu irq */
+ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
+ env->ipistate = ipi;
+ }
+ }
/* Add cpu interrupt-controller */
fdt_add_cpuic_node(lvms, &cpuintc_phandle);
@@ -807,10 +825,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;
}
/* Create EXTIOI device */
diff --git a/include/hw/intc/loongson_ipi.h b/include/hw/intc/loongson_ipi.h
index 3f795edbf3..55d7435cfd 100644
--- a/include/hw/intc/loongson_ipi.h
+++ b/include/hw/intc/loongson_ipi.h
@@ -32,6 +32,7 @@
#define TYPE_LOONGSON_IPI "loongson_ipi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongsonIPI, LOONGSON_IPI)
+#define TYPE_KVM_LOONGARCH_IPI "loongarch-ipi-kvm"
typedef struct IPICore {
LoongsonIPI *ipi;
@@ -53,4 +54,25 @@ struct LoongsonIPI {
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
--git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h
index f9abef3823..91c6f591fb 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -108,4 +108,5 @@ struct kvm_iocsr_entry {
#define KVM_IRQCHIP_NUM_PINS 64
#define KVM_MAX_CORES 256
+#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 1
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
--git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index c93876ca0b..3714ff1a94 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1138,6 +1138,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 e1be6a6959..c07dcfd85f 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -719,6 +719,7 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
+ s->kernel_irqchip_allowed = false;
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
return 0;
}
--
2.39.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC 2/4] hw/loongarch: Add KVM extioi device support
2024-07-17 3:29 [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Xianglai Li
2024-07-17 3:29 ` [RFC 1/4] hw/loongarch: Add KVM IPI device support Xianglai Li
@ 2024-07-17 3:29 ` Xianglai Li
2024-07-17 3:29 ` [RFC 3/4] hw/loongarch: Add KVM pch pic " Xianglai Li
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Xianglai Li @ 2024-07-17 3:29 UTC (permalink / raw)
To: qemu-devel
Cc: Tianrui Zhao, Paolo Bonzini, Song Gao, Huacai Chen, Jiaxun Yang,
Michael S. Tsirkin, Cornelia Huck, kvm, Bibo Mao
Added extioi interrupt controller for kvm emulation.
The main process is to send the command word for
creating an extioi device to the kernel.
When the VM is saved, the ioctl obtains the related
data of the extioi interrupt controller in the kernel
and saves it. When the VM is recovered, the saved data
is sent to the kernel.
Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Song Gao <gaosong@loongson.cn>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: kvm@vger.kernel.org
Cc: Bibo Mao <maobibo@loongson.cn>
hw/intc/Kconfig | 4 +
hw/intc/loongarch_extioi_kvm.c | 141 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/virt.c | 48 +++++-----
include/hw/intc/loongarch_extioi.h | 34 ++++++-
include/hw/loongarch/virt.h | 15 +++
| 1 +
| 2 +
8 files changed, 223 insertions(+), 23 deletions(-)
create mode 100644 hw/intc/loongarch_extioi_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 19d6809129..c672774c6e 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -105,3 +105,7 @@ config LOONGARCH_PCH_MSI
config LOONGARCH_EXTIOI
bool
+
+config LOONGARCH_EXTIOI_KVM
+ bool
+ default y
diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c
new file mode 100644
index 0000000000..36f6683615
--- /dev/null
+++ b/hw/intc/loongarch_extioi_kvm.c
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm extioi 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_extioi.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
+static void kvm_extioi_access_regs(int fd, uint64_t addr,
+ void *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_extioi_pre_save(void *opaque)
+{
+ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque;
+ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START,
+ (void *)s->nodetype, false);
+ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, false);
+ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, false);
+ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, false);
+ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, false);
+ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START,
+ (void *)s->coremap, false);
+ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG,
+ (void *)s->sw_coremap, false);
+ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START,
+ (void *)s->coreisr, false);
+
+ return 0;
+}
+
+static int kvm_loongarch_extioi_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchExtIOI *s = (KVMLoongArchExtIOI *)opaque;
+ KVMLoongArchExtIOIClass *class = KVM_LOONGARCH_EXTIOI_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_extioi_access_regs(fd, EXTIOI_NODETYPE_START,
+ (void *)s->nodetype, true);
+ kvm_extioi_access_regs(fd, EXTIOI_IPMAP_START, (void *)s->ipmap, true);
+ kvm_extioi_access_regs(fd, EXTIOI_ENABLE_START, (void *)s->enable, true);
+ kvm_extioi_access_regs(fd, EXTIOI_BOUNCE_START, (void *)s->bounce, true);
+ kvm_extioi_access_regs(fd, EXTIOI_ISR_START, (void *)s->isr, true);
+ kvm_extioi_access_regs(fd, EXTIOI_COREMAP_START, (void *)s->coremap, true);
+ kvm_extioi_access_regs(fd, EXTIOI_SW_COREMAP_FLAG,
+ (void *)s->sw_coremap, true);
+ kvm_extioi_access_regs(fd, EXTIOI_COREISR_START, (void *)s->coreisr, true);
+
+ return 0;
+}
+
+static void kvm_loongarch_extioi_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ Error *err = NULL;
+ int ret;
+
+ extioi_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ if (!extioi_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_EXTIOI;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Creating the KVM extioi device failed");
+ return;
+ }
+ extioi_class->is_created = true;
+ extioi_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch extioi irqchip in KVM done!\n");
+ }
+}
+
+static const VMStateDescription vmstate_kvm_extioi_core = {
+ .name = "kvm-extioi-single",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_extioi_pre_save,
+ .post_load = kvm_loongarch_extioi_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(nodetype, KVMLoongArchExtIOI,
+ EXTIOI_IRQS_NODETYPE_COUNT / 2),
+ VMSTATE_UINT32_ARRAY(bounce, KVMLoongArchExtIOI,
+ EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_ARRAY(isr, KVMLoongArchExtIOI, EXTIOI_IRQS / 32),
+ VMSTATE_UINT32_2DARRAY(coreisr, KVMLoongArchExtIOI, EXTIOI_CPUS,
+ EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_ARRAY(enable, KVMLoongArchExtIOI, EXTIOI_IRQS / 32),
+ VMSTATE_UINT32_ARRAY(ipmap, KVMLoongArchExtIOI,
+ EXTIOI_IRQS_IPMAP_SIZE / 4),
+ VMSTATE_UINT32_ARRAY(coremap, KVMLoongArchExtIOI, EXTIOI_IRQS / 4),
+ VMSTATE_UINT8_ARRAY(sw_coremap, KVMLoongArchExtIOI, EXTIOI_IRQS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void kvm_loongarch_extioi_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchExtIOIClass *extioi_class = KVM_LOONGARCH_EXTIOI_CLASS(oc);
+
+ extioi_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_extioi_realize;
+ extioi_class->is_created = false;
+ dc->vmsd = &vmstate_kvm_extioi_core;
+}
+
+static const TypeInfo kvm_loongarch_extioi_info = {
+ .name = TYPE_KVM_LOONGARCH_EXTIOI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchExtIOI),
+ .class_size = sizeof(KVMLoongArchExtIOIClass),
+ .class_init = kvm_loongarch_extioi_class_init,
+};
+
+static void kvm_loongarch_extioi_register_types(void)
+{
+ type_register_static(&kvm_loongarch_extioi_info);
+}
+
+type_init(kvm_loongarch_extioi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 354d43b4f0..3f29b3f5fd 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -74,3 +74,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_IPI_KVM', if_true: files('loongarch_ipi_
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'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c'))
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 2ae5298b62..288aac5822 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -828,28 +828,34 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
}
/* Create EXTIOI device */
- extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
- qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
- if (virt_is_veiointc_enabled(lvms)) {
- qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
- }
- sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
- memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
- if (virt_is_veiointc_enabled(lvms)) {
- memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
- }
+ if (kvm_kernel_irqchip_allowed()) {
+ extioi = qdev_new(TYPE_KVM_LOONGARCH_EXTIOI);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
+ kvm_async_interrupts_allowed = true;
+ } else {
+ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
+ qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
+ if (virt_is_veiointc_enabled(lvms)) {
+ qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
+ }
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
+ memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+ if (virt_is_veiointc_enabled(lvms)) {
+ memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
+ }
- /*
- * connect ext irq to the cpu irq
- * cpu_pin[9:2] <= intc_pin[7:0]
- */
- for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
- cpudev = DEVICE(qemu_get_cpu(cpu));
- for (pin = 0; pin < LS3A_INTC_IP; pin++) {
- qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
- qdev_get_gpio_in(cpudev, pin + 2));
+ /*
+ * connect ext irq to the cpu irq
+ * cpu_pin[9:2] <= intc_pin[7:0]
+ */
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpudev = DEVICE(qemu_get_cpu(cpu));
+ for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+ qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
+ qdev_get_gpio_in(cpudev, pin + 2));
+ }
}
}
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
index eccc2e0d18..9f396f645c 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -15,7 +15,7 @@
#define EXTIOI_IRQS (256)
#define EXTIOI_IRQS_BITMAP_SIZE (256 / 8)
/* irq from EXTIOI is routed to no more than 4 cpus */
-#define EXTIOI_CPUS (4)
+#define EXTIOI_CPUS (256)
/* map to ipnum per 32 irqs */
#define EXTIOI_IRQS_IPMAP_SIZE (256 / 32)
#define EXTIOI_IRQS_COREMAP_SIZE 256
@@ -59,13 +59,16 @@
#define EXTIOI_VIRT_COREMAP_START (0x40)
#define EXTIOI_VIRT_COREMAP_END (0x240)
+#define EXTIOI_SW_COREMAP_FLAG (1 << 0)
+
typedef struct ExtIOICore {
uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
qemu_irq parent_irq[LS3A_INTC_IP];
} ExtIOICore;
-#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
+#define TYPE_LOONGARCH_EXTIOI "loongarch-extioi"
+#define TYPE_KVM_LOONGARCH_EXTIOI "loongarch-kvm-extioi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
struct LoongArchExtIOI {
SysBusDevice parent_obj;
@@ -87,4 +90,31 @@ struct LoongArchExtIOI {
MemoryRegion extioi_system_mem;
MemoryRegion virt_extend;
};
+
+struct KVMLoongArchExtIOI {
+ SysBusDevice parent_obj;
+ /* hardware state */
+ uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
+ uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
+ uint32_t isr[EXTIOI_IRQS / 32];
+ uint32_t coreisr[EXTIOI_CPUS][EXTIOI_IRQS_GROUP_COUNT];
+ uint32_t enable[EXTIOI_IRQS / 32];
+ uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4];
+ uint32_t coremap[EXTIOI_IRQS / 4];
+ uint8_t sw_coremap[EXTIOI_IRQS];
+};
+typedef struct KVMLoongArchExtIOI KVMLoongArchExtIOI;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchExtIOI, KVM_LOONGARCH_EXTIOI,
+ TYPE_KVM_LOONGARCH_EXTIOI)
+
+struct KVMLoongArchExtIOIClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+};
+typedef struct KVMLoongArchExtIOIClass KVMLoongArchExtIOIClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchExtIOIClass, KVM_LOONGARCH_EXTIOI,
+ TYPE_KVM_LOONGARCH_EXTIOI)
#endif /* LOONGARCH_EXTIOI_H */
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 8fdfacf268..3f658356fa 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -37,6 +37,21 @@
#define FDT_BASE 0x100000
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24
+#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff
+#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16
+#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff
+#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0
+#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff
+
+/* irq_type field */
+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0
+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1
+#define KVM_LOONGARCH_IRQ_TYPE_HT 2
+#define KVM_LOONGARCH_IRQ_TYPE_MSI 3
+#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4
+
struct LoongArchVirtMachineState {
/*< private >*/
MachineState parent_obj;
--git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h
index 91c6f591fb..c71221d1b0 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -109,4 +109,5 @@ struct kvm_iocsr_entry {
#define KVM_MAX_CORES 256
#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 1
+#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 1
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
--git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 3714ff1a94..1dca283ecd 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1140,6 +1140,8 @@ enum kvm_device_type {
#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_LA_EXTIOI,
+#define KVM_DEV_TYPE_LA_EXTIOI KVM_DEV_TYPE_LA_EXTIOI
KVM_DEV_TYPE_MAX,
};
--
2.39.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC 3/4] hw/loongarch: Add KVM pch pic device support
2024-07-17 3:29 [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Xianglai Li
2024-07-17 3:29 ` [RFC 1/4] hw/loongarch: Add KVM IPI device support Xianglai Li
2024-07-17 3:29 ` [RFC 2/4] hw/loongarch: Add KVM extioi " Xianglai Li
@ 2024-07-17 3:29 ` Xianglai Li
2024-07-17 3:29 ` [RFC 4/4] hw/loongarch: Add KVM pch msi " Xianglai Li
2024-07-17 7:58 ` [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Cornelia Huck
4 siblings, 0 replies; 6+ messages in thread
From: Xianglai Li @ 2024-07-17 3:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Song Gao, Huacai Chen, Jiaxun Yang,
Michael S. Tsirkin, Cornelia Huck, kvm, Bibo Mao
Added pch_pic interrupt controller for kvm emulation.
The main process is to send the command word for
creating an pch_pic device to the kernel,
Delivers the pch pic interrupt controller configuration
register base address to the kernel.
When the VM is saved, the ioctl obtains the pch_pic
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: Xianglai Li <lixianglai@loongson.cn>
---
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Song Gao <gaosong@loongson.cn>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: kvm@vger.kernel.org
Cc: Bibo Mao <maobibo@loongson.cn>
hw/intc/Kconfig | 4 +
hw/intc/loongarch_pch_pic.c | 20 ++-
hw/intc/loongarch_pch_pic_kvm.c | 189 ++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/loongarch/virt.c | 65 +++++-----
include/hw/intc/loongarch_pch_pic.h | 51 +++++++-
| 5 +
| 2 +
8 files changed, 304 insertions(+), 33 deletions(-)
create mode 100644 hw/intc/loongarch_pch_pic_kvm.c
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index c672774c6e..c9f96bffd6 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -98,6 +98,10 @@ config LOONGARCH_PCH_PIC
bool
select UNIMP
+config LOONGARCH_PCH_PIC_KVM
+ bool
+ default y
+
config LOONGARCH_PCH_MSI
select MSI_NONBROKEN
bool
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 2d5e65abff..b64e3db77f 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -16,18 +16,27 @@
#include "migration/vmstate.h"
#include "trace.h"
#include "qapi/error.h"
+#include "sysemu/kvm.h"
static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
{
uint64_t val;
int irq;
+ int kvm_irq;
if (level) {
val = mask & s->intirr & ~s->int_mask;
if (val) {
irq = ctz64(val);
s->intisr |= MAKE_64BIT_MASK(irq, 1);
- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
+ if (kvm_kernel_irqchip_allowed()) {
+ kvm_irq = (
+ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT)
+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq];
+ kvm_set_irq(kvm_state, kvm_irq, !!level);
+ } else {
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
+ }
}
} else {
/*
@@ -38,7 +47,14 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
if (val) {
irq = ctz64(val);
s->intisr &= ~MAKE_64BIT_MASK(irq, 1);
- qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
+ if (kvm_kernel_irqchip_allowed()) {
+ kvm_irq = (
+ KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT)
+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | s->htmsi_vector[irq];
+ kvm_set_irq(kvm_state, kvm_irq, !!level);
+ } else {
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
+ }
}
}
}
diff --git a/hw/intc/loongarch_pch_pic_kvm.c b/hw/intc/loongarch_pch_pic_kvm.c
new file mode 100644
index 0000000000..8f66d9a01f
--- /dev/null
+++ b/hw/intc/loongarch_pch_pic_kvm.c
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch kvm pch pic 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_pch_pic.h"
+#include "hw/sysbus.h"
+#include "linux/kvm.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+#include "hw/loongarch/virt.h"
+#include "hw/pci-host/ls7a.h"
+#include "qemu/error-report.h"
+
+static void kvm_pch_pic_access_regs(int fd, uint64_t addr,
+ void *val, int is_write)
+{
+ kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS,
+ addr, val, is_write, &error_abort);
+}
+
+static int kvm_loongarch_pch_pic_pre_save(void *opaque)
+{
+ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque;
+ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START,
+ (void *)&s->int_mask, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START,
+ (void *)&s->htmsi_en, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START,
+ (void *)&s->intedge, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START,
+ (void *)&s->auto_crtl0, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START,
+ (void *)&s->auto_crtl1, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START,
+ (void *)s->route_entry, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START,
+ (void *)s->htmsi_vector, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START,
+ (void *)&s->intirr, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START,
+ (void *)&s->intisr, false);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START,
+ (void *)&s->int_polarity, false);
+
+ return 0;
+}
+
+static int kvm_loongarch_pch_pic_post_load(void *opaque, int version_id)
+{
+ KVMLoongArchPCHPIC *s = (KVMLoongArchPCHPIC *)opaque;
+ KVMLoongArchPCHPICClass *class = KVM_LOONGARCH_PCH_PIC_GET_CLASS(s);
+ int fd = class->dev_fd;
+
+ kvm_pch_pic_access_regs(fd, PCH_PIC_MASK_START,
+ (void *)&s->int_mask, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_EN_START,
+ (void *)&s->htmsi_en, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_EDGE_START,
+ (void *)&s->intedge, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL0_START,
+ (void *)&s->auto_crtl0, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_AUTO_CTRL1_START,
+ (void *)&s->auto_crtl1, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_ROUTE_ENTRY_START,
+ (void *)s->route_entry, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_HTMSI_VEC_START,
+ (void *)s->htmsi_vector, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_IRR_START,
+ (void *)&s->intirr, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_INT_ISR_START,
+ (void *)&s->intisr, true);
+ kvm_pch_pic_access_regs(fd, PCH_PIC_POLARITY_START,
+ (void *)&s->int_polarity, true);
+
+ return 0;
+}
+
+static void kvm_pch_pic_handler(void *opaque, int irq, int level)
+{
+ int kvm_irq;
+
+ if (kvm_enabled()) {
+ kvm_irq = \
+ (KVM_LOONGARCH_IRQ_TYPE_IOAPIC << KVM_LOONGARCH_IRQ_TYPE_SHIFT)
+ | (0 << KVM_LOONGARCH_IRQ_VCPU_SHIFT) | irq;
+ kvm_set_irq(kvm_state, kvm_irq, !!level);
+ }
+}
+
+static void kvm_loongarch_pch_pic_realize(DeviceState *dev, Error **errp)
+{
+ KVMLoongArchPCHPICClass *pch_pic_class =
+ KVM_LOONGARCH_PCH_PIC_GET_CLASS(dev);
+ struct kvm_create_device cd = {0};
+ uint64_t pch_pic_base = VIRT_PCH_REG_BASE;
+ Error *err = NULL;
+ int ret;
+
+ pch_pic_class->parent_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ if (!pch_pic_class->is_created) {
+ cd.type = KVM_DEV_TYPE_LA_PCH_PIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+ if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Creating the KVM pch pic device failed");
+ return;
+ }
+ pch_pic_class->is_created = true;
+ pch_pic_class->dev_fd = cd.fd;
+ fprintf(stdout, "Create LoongArch pch pic irqchip in KVM done!\n");
+
+ ret = kvm_device_access(cd.fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL,
+ KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT,
+ &pch_pic_base, true, NULL);
+ if (ret < 0) {
+ error_report(
+ "KVM EXTIOI: failed to set the base address of EXTIOI");
+ exit(1);
+ }
+
+ qdev_init_gpio_in(dev, kvm_pch_pic_handler, VIRT_PCH_PIC_IRQ_NUM);
+ }
+}
+
+static const VMStateDescription vmstate_kvm_loongarch_pch_pic = {
+ .name = TYPE_LOONGARCH_PCH_PIC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = kvm_loongarch_pch_pic_pre_save,
+ .post_load = kvm_loongarch_pch_pic_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT64(int_mask, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(htmsi_en, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intedge, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intclr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(auto_crtl0, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(auto_crtl1, KVMLoongArchPCHPIC),
+ VMSTATE_UINT8_ARRAY(route_entry, KVMLoongArchPCHPIC, 64),
+ VMSTATE_UINT8_ARRAY(htmsi_vector, KVMLoongArchPCHPIC, 64),
+ VMSTATE_UINT64(last_intirr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intirr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(intisr, KVMLoongArchPCHPIC),
+ VMSTATE_UINT64(int_polarity, KVMLoongArchPCHPIC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+static void kvm_loongarch_pch_pic_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ KVMLoongArchPCHPICClass *pch_pic_class = KVM_LOONGARCH_PCH_PIC_CLASS(oc);
+
+ pch_pic_class->parent_realize = dc->realize;
+ dc->realize = kvm_loongarch_pch_pic_realize;
+ pch_pic_class->is_created = false;
+ dc->vmsd = &vmstate_kvm_loongarch_pch_pic;
+
+}
+
+static const TypeInfo kvm_loongarch_pch_pic_info = {
+ .name = TYPE_KVM_LOONGARCH_PCH_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMLoongArchPCHPIC),
+ .class_size = sizeof(KVMLoongArchPCHPICClass),
+ .class_init = kvm_loongarch_pch_pic_class_init,
+};
+
+static void kvm_loongarch_pch_pic_register_types(void)
+{
+ type_register_static(&kvm_loongarch_pch_pic_info);
+}
+
+type_init(kvm_loongarch_pch_pic_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 3f29b3f5fd..4fddc80383 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -75,3 +75,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_
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'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI_KVM', if_true: files('loongarch_extioi_kvm.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC_KVM', if_true: files('loongarch_pch_pic_kvm.c'))
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 288aac5822..9e9e8f5d14 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -862,40 +862,45 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
/* Add Extend I/O Interrupt Controller node */
fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle);
- pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
- num = VIRT_PCH_PIC_IRQ_NUM;
- qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
- d = SYS_BUS_DEVICE(pch_pic);
- sysbus_realize_and_unref(d, &error_fatal);
- memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
- sysbus_mmio_get_region(d, 0));
- memory_region_add_subregion(get_system_memory(),
+ if (kvm_kernel_irqchip_allowed()) {
+ pch_pic = qdev_new(TYPE_KVM_LOONGARCH_PCH_PIC);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(pch_pic), &error_fatal);
+ } else {
+ pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+ num = VIRT_PCH_PIC_IRQ_NUM;
+ qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
+ d = SYS_BUS_DEVICE(pch_pic);
+ sysbus_realize_and_unref(d, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
+ sysbus_mmio_get_region(d, 0));
+ memory_region_add_subregion(get_system_memory(),
VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
sysbus_mmio_get_region(d, 1));
- memory_region_add_subregion(get_system_memory(),
- VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
- sysbus_mmio_get_region(d, 2));
-
- /* Connect pch_pic irqs to extioi */
- for (i = 0; i < num; i++) {
- qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
- }
+ memory_region_add_subregion(get_system_memory(),
+ VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
+ sysbus_mmio_get_region(d, 2));
- /* Add PCH PIC node */
- fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
+ /* Connect pch_pic irqs to extioi */
+ for (i = 0; i < num; i++) {
+ qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
+ }
- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
- start = num;
- num = EXTIOI_IRQS - start;
- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
- d = SYS_BUS_DEVICE(pch_msi);
- sysbus_realize_and_unref(d, &error_fatal);
- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
- for (i = 0; i < num; i++) {
- /* Connect pch_msi irqs to extioi */
- qdev_connect_gpio_out(DEVICE(d), i,
- qdev_get_gpio_in(extioi, i + start));
+ /* Add PCH PIC node */
+ fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
+
+ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
+ start = num;
+ num = EXTIOI_IRQS - start;
+ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
+ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
+ d = SYS_BUS_DEVICE(pch_msi);
+ sysbus_realize_and_unref(d, &error_fatal);
+ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
+ for (i = 0; i < num; i++) {
+ /* Connect pch_msi irqs to extioi */
+ qdev_connect_gpio_out(DEVICE(d), i,
+ qdev_get_gpio_in(extioi, i + start));
+ }
}
/* Add PCH MSI node */
diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
index d5437e88f2..77f4cd74a1 100644
--- a/include/hw/intc/loongarch_pch_pic.h
+++ b/include/hw/intc/loongarch_pch_pic.h
@@ -7,7 +7,8 @@
#include "hw/sysbus.h"
-#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
+#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
+#define TYPE_KVM_LOONGARCH_PCH_PIC "loongarch_kvm_pch_pic"
#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
@@ -37,6 +38,19 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
#define PCH_PIC_INT_POL_LO 0x3e0
#define PCH_PIC_INT_POL_HI 0x3e4
+#define PCH_PIC_INT_ID_START PCH_PIC_INT_ID_LO
+#define PCH_PIC_MASK_START PCH_PIC_INT_MASK_LO
+#define PCH_PIC_HTMSI_EN_START PCH_PIC_HTMSI_EN_LO
+#define PCH_PIC_EDGE_START PCH_PIC_INT_EDGE_LO
+#define PCH_PIC_CLEAR_START PCH_PIC_INT_CLEAR_LO
+#define PCH_PIC_AUTO_CTRL0_START PCH_PIC_AUTO_CTRL0_LO
+#define PCH_PIC_AUTO_CTRL1_START PCH_PIC_AUTO_CTRL1_LO
+#define PCH_PIC_ROUTE_ENTRY_START PCH_PIC_ROUTE_ENTRY_OFFSET
+#define PCH_PIC_HTMSI_VEC_START PCH_PIC_HTMSI_VEC_OFFSET
+#define PCH_PIC_INT_IRR_START 0x380
+#define PCH_PIC_INT_ISR_START PCH_PIC_INT_STATUS_LO
+#define PCH_PIC_POLARITY_START PCH_PIC_INT_POL_LO
+
#define STATUS_LO_START 0
#define STATUS_HI_START 0x4
#define POL_LO_START 0x40
@@ -67,3 +81,38 @@ struct LoongArchPCHPIC {
MemoryRegion iomem8;
unsigned int irq_num;
};
+
+struct KVMLoongArchPCHPIC {
+ SysBusDevice parent_obj;
+ uint64_t int_mask; /*0x020 interrupt mask register*/
+ uint64_t htmsi_en; /*0x040 1=msi*/
+ uint64_t intedge; /*0x060 edge=1 level =0*/
+ uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
+ uint64_t auto_crtl0; /*0x0c0*/
+ uint64_t auto_crtl1; /*0x0e0*/
+ uint64_t last_intirr; /* edge detection */
+ uint64_t intirr; /* 0x380 interrupt request register */
+ uint64_t intisr; /* 0x3a0 interrupt service register */
+ /*
+ * 0x3e0 interrupt level polarity selection
+ * register 0 for high level trigger
+ */
+ uint64_t int_polarity;
+
+ uint8_t route_entry[64]; /*0x100 - 0x138*/
+ uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
+};
+typedef struct KVMLoongArchPCHPIC KVMLoongArchPCHPIC;
+DECLARE_INSTANCE_CHECKER(KVMLoongArchPCHPIC, KVM_LOONGARCH_PCH_PIC,
+ TYPE_KVM_LOONGARCH_PCH_PIC)
+
+struct KVMLoongArchPCHPICClass {
+ SysBusDeviceClass parent_class;
+ DeviceRealize parent_realize;
+
+ bool is_created;
+ int dev_fd;
+};
+typedef struct KVMLoongArchPCHPICClass KVMLoongArchPCHPICClass;
+DECLARE_CLASS_CHECKERS(KVMLoongArchPCHPICClass, KVM_LOONGARCH_PCH_PIC,
+ TYPE_KVM_LOONGARCH_PCH_PIC)
--git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h
index c71221d1b0..cd0aebd805 100644
--- a/linux-headers/asm-loongarch/kvm.h
+++ b/linux-headers/asm-loongarch/kvm.h
@@ -110,4 +110,9 @@ struct kvm_iocsr_entry {
#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 1
#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 1
+
+#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0
+#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0
+
+#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 1
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
--git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 1dca283ecd..48eaeb91f2 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -1138,6 +1138,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_PCH_PIC,
+#define KVM_DEV_TYPE_LA_PCH_PIC KVM_DEV_TYPE_LA_PCH_PIC
KVM_DEV_TYPE_LA_IPI,
#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI
KVM_DEV_TYPE_LA_EXTIOI,
--
2.39.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [RFC 4/4] hw/loongarch: Add KVM pch msi device support
2024-07-17 3:29 [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Xianglai Li
` (2 preceding siblings ...)
2024-07-17 3:29 ` [RFC 3/4] hw/loongarch: Add KVM pch pic " Xianglai Li
@ 2024-07-17 3:29 ` Xianglai Li
2024-07-17 7:58 ` [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Cornelia Huck
4 siblings, 0 replies; 6+ messages in thread
From: Xianglai Li @ 2024-07-17 3:29 UTC (permalink / raw)
To: qemu-devel
Cc: Paolo Bonzini, Song Gao, Huacai Chen, Jiaxun Yang,
Michael S. Tsirkin, Cornelia Huck, kvm, Bibo Mao
Added pch_msi interrupt controller handling
during kernel emulation of irq chip.
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
---
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Song Gao <gaosong@loongson.cn>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: kvm@vger.kernel.org
Cc: Bibo Mao <maobibo@loongson.cn>
hw/intc/loongarch_pch_msi.c | 42 +++++++++++++++++++++--------
hw/loongarch/virt.c | 34 +++++++++++++++--------
include/hw/intc/loongarch_pch_msi.h | 2 +-
target/loongarch/kvm/kvm.c | 1 -
4 files changed, 55 insertions(+), 24 deletions(-)
diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
index ecf3ed0267..c0a8b3a547 100644
--- a/hw/intc/loongarch_pch_msi.c
+++ b/hw/intc/loongarch_pch_msi.c
@@ -2,7 +2,7 @@
/*
* QEMU Loongson 7A1000 msi interrupt controller.
*
- * Copyright (C) 2021 Loongson Technology Corporation Limited
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
@@ -14,6 +14,8 @@
#include "hw/misc/unimp.h"
#include "migration/vmstate.h"
#include "trace.h"
+#include "sysemu/kvm.h"
+#include "hw/loongarch/virt.h"
static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
{
@@ -26,14 +28,24 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque;
int irq_num;
- /*
- * vector number is irq number from upper extioi intc
- * need subtract irq base to get msi vector offset
- */
- irq_num = (val & 0xff) - s->irq_base;
- trace_loongarch_msi_set_irq(irq_num);
- assert(irq_num < s->irq_num);
- qemu_set_irq(s->pch_msi_irq[irq_num], 1);
+ MSIMessage msg = {
+ .address = addr,
+ .data = val,
+ };
+
+ if (kvm_kernel_irqchip_allowed()) {
+ kvm_irqchip_send_msi(kvm_state, msg);
+ } else {
+ /*
+ * vector number is irq number from upper extioi intc
+ * need subtract irq base to get msi vector offset
+ */
+ irq_num = (val & 0xff) - s->irq_base;
+ trace_loongarch_msi_set_irq(irq_num);
+ assert(irq_num < s->irq_num);
+
+ qemu_set_irq(s->pch_msi_irq[irq_num], 1);
+ }
}
static const MemoryRegionOps loongarch_pch_msi_ops = {
@@ -45,8 +57,16 @@ static const MemoryRegionOps loongarch_pch_msi_ops = {
static void pch_msi_irq_handler(void *opaque, int irq, int level)
{
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
-
- qemu_set_irq(s->pch_msi_irq[irq], level);
+ MSIMessage msg = {
+ .address = 0,
+ .data = irq,
+ };
+
+ if (kvm_kernel_irqchip_allowed()) {
+ kvm_irqchip_send_msi(kvm_state, msg);
+ } else {
+ qemu_set_irq(s->pch_msi_irq[irq], level);
+ }
}
static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 9e9e8f5d14..750a60ba91 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -884,24 +884,36 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
for (i = 0; i < num; i++) {
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
}
+ }
- /* Add PCH PIC node */
- fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
+ /* Add PCH PIC node */
+ fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle);
- pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
- start = num;
- num = EXTIOI_IRQS - start;
- qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
- qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
- d = SYS_BUS_DEVICE(pch_msi);
- sysbus_realize_and_unref(d, &error_fatal);
- sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
+ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
+ num = VIRT_PCH_PIC_IRQ_NUM;
+ start = num;
+ num = EXTIOI_IRQS - start;
+ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
+ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
+ d = SYS_BUS_DEVICE(pch_msi);
+ sysbus_realize_and_unref(d, &error_fatal);
+
+ if (kvm_kernel_irqchip_allowed()) {
+ if (kvm_has_gsi_routing()) {
+ for (i = 0; i < 64; ++i) {
+ kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
+ }
+ kvm_gsi_routing_allowed = true;
+ }
+ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
+ } else {
+ /* Connect pch_msi irqs to extioi */
for (i = 0; i < num; i++) {
- /* Connect pch_msi irqs to extioi */
qdev_connect_gpio_out(DEVICE(d), i,
qdev_get_gpio_in(extioi, i + start));
}
}
+ sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
/* Add PCH MSI node */
fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle);
diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h
index b8586fb3b6..fd4ea97a83 100644
--- a/include/hw/intc/loongarch_pch_msi.h
+++ b/include/hw/intc/loongarch_pch_msi.h
@@ -7,7 +7,7 @@
#include "hw/sysbus.h"
-#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
+#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI)
/* MSI irq start from 32 to 255 */
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index c07dcfd85f..e1be6a6959 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -719,7 +719,6 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
- s->kernel_irqchip_allowed = false;
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
return 0;
}
--
2.39.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC 0/4] Added Interrupt controller emulation for loongarch kvm
2024-07-17 3:29 [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Xianglai Li
` (3 preceding siblings ...)
2024-07-17 3:29 ` [RFC 4/4] hw/loongarch: Add KVM pch msi " Xianglai Li
@ 2024-07-17 7:58 ` Cornelia Huck
4 siblings, 0 replies; 6+ messages in thread
From: Cornelia Huck @ 2024-07-17 7:58 UTC (permalink / raw)
To: Xianglai Li, qemu-devel
Cc: Paolo Bonzini, Song Gao, Huacai Chen, Jiaxun Yang,
Michael S. Tsirkin, kvm, Bibo Mao
On Wed, Jul 17 2024, Xianglai Li <lixianglai@loongson.cn> wrote:
> Before this, the interrupt controller simulation has been completed
> in the user mode program. In order to reduce the loss caused by frequent
> switching of the virtual machine monitor from kernel mode to user mode
> when the guest accesses the interrupt controller, we add the interrupt
> controller simulation in kvm.
>
> In qemu side implementation is simple, just make a new IPI EXTIOI PCH KVM
> related several classes, And the interface to access kvm related data is
> implemented.
>
> Most of the simulation work of the interrupt controller is done in kvm.
> Because KVM the changes have not been the Linux community acceptance,
> the patches of this series will have RFC label until KVM patch into the community.
>
> For the implementation of kvm simulation, refer to the following documents.
>
> IPI simulation implementation reference:
> https://github.com/loongson/LoongArch-Documentation/tree/main/docs/Loongson-3A5000-usermanual-EN/inter-processor-interrupts-and-communication
>
> EXTIOI simulation implementation reference:
> https://github.com/loongson/LoongArch-Documentation/tree/main/docs/Loongson-3A5000-usermanual-EN/io-interrupts/extended-io-interrupts
>
> PCH-PIC simulation implementation reference:
> https://github.com/loongson/LoongArch-Documentation/blob/main/docs/Loongson-7A1000-usermanual-EN/interrupt-controller.adoc
>
> For PCH-MSI, we used irqfd mechanism to send the interrupt signal
> generated by user state to kernel state and then to EXTIOI without
> maintaining PCH-MSI state in kernel state.
>
> You can easily get the code from the link below:
> the kernel:
> https://github.com/lixianglai/linux
> the branch is: interrupt
>
> the qemu:
> https://github.com/lixianglai/qemu
> the branch is: interrupt
>
> Please note that the code above is regularly updated based on community
> reviews.
>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Song Gao <gaosong@loongson.cn>
> Cc: Huacai Chen <chenhuacai@kernel.org>
> Cc: Jiaxun Yang <jiaxun.yang@flygoat.com>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Cornelia Huck <cohuck@redhat.com>
> Cc: kvm@vger.kernel.org
> Cc: Bibo Mao <maobibo@loongson.cn>
>
> Xianglai Li (4):
> hw/loongarch: Add KVM IPI device support
> hw/loongarch: Add KVM extioi device support
> hw/loongarch: Add KVM pch pic device support
> hw/loongarch: Add KVM pch msi device support
>
> hw/intc/Kconfig | 12 ++
> hw/intc/loongarch_extioi_kvm.c | 141 +++++++++++++++++++
> hw/intc/loongarch_ipi_kvm.c | 207 ++++++++++++++++++++++++++++
> hw/intc/loongarch_pch_msi.c | 42 ++++--
> hw/intc/loongarch_pch_pic.c | 20 ++-
> hw/intc/loongarch_pch_pic_kvm.c | 189 +++++++++++++++++++++++++
> hw/intc/meson.build | 3 +
> hw/loongarch/virt.c | 141 ++++++++++++-------
> include/hw/intc/loongarch_extioi.h | 34 ++++-
> include/hw/intc/loongarch_pch_msi.h | 2 +-
> include/hw/intc/loongarch_pch_pic.h | 51 ++++++-
> include/hw/intc/loongson_ipi.h | 22 +++
> include/hw/loongarch/virt.h | 15 ++
> linux-headers/asm-loongarch/kvm.h | 7 +
> linux-headers/linux/kvm.h | 6 +
Please split out any headers changes into a separate patch -- just put
them into a placeholder patch at the beginning of the series as long as
the changes are not yet upstream (and replace that with a full headers
sync later.)
> 15 files changed, 823 insertions(+), 69 deletions(-)
> create mode 100644 hw/intc/loongarch_extioi_kvm.c
> create mode 100644 hw/intc/loongarch_ipi_kvm.c
> create mode 100644 hw/intc/loongarch_pch_pic_kvm.c
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-07-17 7:58 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-17 3:29 [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Xianglai Li
2024-07-17 3:29 ` [RFC 1/4] hw/loongarch: Add KVM IPI device support Xianglai Li
2024-07-17 3:29 ` [RFC 2/4] hw/loongarch: Add KVM extioi " Xianglai Li
2024-07-17 3:29 ` [RFC 3/4] hw/loongarch: Add KVM pch pic " Xianglai Li
2024-07-17 3:29 ` [RFC 4/4] hw/loongarch: Add KVM pch msi " Xianglai Li
2024-07-17 7:58 ` [RFC 0/4] Added Interrupt controller emulation for loongarch kvm Cornelia Huck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).