From 8bf8814ab1aba0243127bcada19414dddbfe9e51 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:21 +0800 Subject: [PATCH 01/14] hw/intc/loongarch_extioi: Add kernel irqchip realize function Function kvm_extioi_realize() is added if kvm_irqchip_in_kernel is set. It is to create and initialize ExtIOI device in kernel mode. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-2-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_extioi.c | 31 ++++++++++++-------- hw/intc/loongarch_extioi_kvm.c | 46 ++++++++++++++++++++++++++++++ hw/intc/meson.build | 2 ++ include/hw/intc/loongarch_extioi.h | 3 ++ 4 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 hw/intc/loongarch_extioi_kvm.c diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index 7c38c4c9b7..837f649d6c 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -12,6 +12,7 @@ #include "hw/irq.h" #include "hw/loongarch/virt.h" #include "system/address-spaces.h" +#include "system/kvm.h" #include "hw/intc/loongarch_extioi.h" #include "trace.h" @@ -351,23 +352,29 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp) return; } - for (i = 0; i < EXTIOI_IRQS; i++) { - sysbus_init_irq(sbd, &s->irq[i]); - } - - qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS); - memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops, - s, "extioi_system_mem", 0x900); - sysbus_init_mmio(sbd, &s->extioi_system_mem); - if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) { - memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops, - s, "extioi_virt", EXTIOI_VIRT_SIZE); - sysbus_init_mmio(sbd, &s->virt_extend); s->features |= EXTIOI_VIRT_HAS_FEATURES; } else { s->status |= BIT(EXTIOI_ENABLE); } + + if (kvm_irqchip_in_kernel()) { + kvm_extioi_realize(dev, errp); + } else { + for (i = 0; i < EXTIOI_IRQS; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } + + qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS); + memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops, + s, "extioi_system_mem", 0x900); + sysbus_init_mmio(sbd, &s->extioi_system_mem); + if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) { + memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops, + s, "extioi_virt", EXTIOI_VIRT_SIZE); + sysbus_init_mmio(sbd, &s->virt_extend); + } + } } static void loongarch_extioi_unrealize(DeviceState *dev) diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c new file mode 100644 index 0000000000..e6d5dd379a --- /dev/null +++ b/hw/intc/loongarch_extioi_kvm.c @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch EXTIOI interrupt kvm support + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qemu/typedefs.h" +#include "hw/intc/loongarch_extioi.h" +#include "linux/kvm.h" +#include "qapi/error.h" +#include "system/kvm.h" + +void kvm_extioi_realize(DeviceState *dev, Error **errp) +{ + LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev); + LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev); + int ret; + + ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false); + if (ret < 0) { + fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n", + strerror(-ret)); + abort(); + } + + les->dev_fd = ret; + ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, + KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU, + &lecs->num_cpu, true, NULL); + if (ret < 0) { + fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n", + strerror(-ret)); + abort(); + } + + ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, + KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE, + &lecs->features, true, NULL); + if (ret < 0) { + fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n", + strerror(-ret)); + abort(); + } +} diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 602da304b0..70e7548c52 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -74,3 +74,5 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.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', 'loongarch_extioi_common.c')) +specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'], + if_true: files('loongarch_extioi_kvm.c')) diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h index 4a6ae903e9..69565e14ab 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -15,6 +15,7 @@ OBJECT_DECLARE_TYPE(LoongArchExtIOIState, LoongArchExtIOIClass, LOONGARCH_EXTIOI struct LoongArchExtIOIState { LoongArchExtIOICommonState parent_obj; + int dev_fd; }; struct LoongArchExtIOIClass { @@ -25,4 +26,6 @@ struct LoongArchExtIOIClass { ResettablePhases parent_phases; }; +void kvm_extioi_realize(DeviceState *dev, Error **errp); + #endif /* LOONGARCH_EXTIOI_H */ From 228c5413fb50ab43644689f4959c3ef1ef7571ea Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:22 +0800 Subject: [PATCH 02/14] hw/intc/loongarch_extioi: Add kernel irqchip save and restore function Add save and store funtction if kvm_irqchip_in_kernel() return true, it is to get and set ExtIOI irqchip state from KVM kernel. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-3-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_extioi.c | 14 +++++ hw/intc/loongarch_extioi_kvm.c | 90 ++++++++++++++++++++++++++++++ include/hw/intc/loongarch_extioi.h | 2 + 3 files changed, 106 insertions(+) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index 837f649d6c..7be0685f36 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -393,11 +393,24 @@ static void loongarch_extioi_reset_hold(Object *obj, ResetType type) } } +static int vmstate_extioi_pre_save(void *opaque) +{ + if (kvm_irqchip_in_kernel()) { + return kvm_extioi_get(opaque); + } + + return 0; +} + static int vmstate_extioi_post_load(void *opaque, int version_id) { LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque); int i, start_irq; + if (kvm_irqchip_in_kernel()) { + return kvm_extioi_put(opaque, version_id); + } + for (i = 0; i < (EXTIOI_IRQS / 4); i++) { start_irq = i * 4; extioi_update_sw_coremap(s, start_irq, s->coremap[i], false); @@ -423,6 +436,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, const void *data) &lec->parent_unrealize); resettable_class_set_parent_phases(rc, NULL, loongarch_extioi_reset_hold, NULL, &lec->parent_phases); + lecc->pre_save = vmstate_extioi_pre_save; lecc->post_load = vmstate_extioi_post_load; } diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c index e6d5dd379a..f4c618ca4c 100644 --- a/hw/intc/loongarch_extioi_kvm.c +++ b/hw/intc/loongarch_extioi_kvm.c @@ -12,6 +12,96 @@ #include "qapi/error.h" #include "system/kvm.h" +static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write) +{ + kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS, + addr, val, write, &error_abort); +} + +static void kvm_extioi_access_sw_state(int fd, uint64_t addr, + void *val, bool write) +{ + kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS, + addr, val, write, &error_abort); +} + +static void kvm_extioi_access_sw_status(void *opaque, bool write) +{ + LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque); + LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque); + int addr; + + addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE; + kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write); +} + +static void kvm_extioi_access_regs(void *opaque, bool write) +{ + LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque); + LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque); + int fd = les->dev_fd; + int addr, offset, cpu; + + for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) { + offset = (addr - EXTIOI_NODETYPE_START) / 4; + kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write); + } + + for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) { + offset = (addr - EXTIOI_IPMAP_START) / 4; + kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write); + } + + for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) { + offset = (addr - EXTIOI_ENABLE_START) / 4; + kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write); + } + + for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) { + offset = (addr - EXTIOI_BOUNCE_START) / 4; + kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write); + } + + for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) { + offset = (addr - EXTIOI_ISR_START) / 4; + kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write); + } + + for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) { + offset = (addr - EXTIOI_COREMAP_START) / 4; + kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write); + } + + for (cpu = 0; cpu < lecs->num_cpu; cpu++) { + for (addr = EXTIOI_COREISR_START; + addr < EXTIOI_COREISR_END; addr += 4) { + offset = (addr - EXTIOI_COREISR_START) / 4; + kvm_extioi_access_reg(fd, (cpu << 16) | addr, + &lecs->cpu[cpu].coreisr[offset], write); + } + } +} + +int kvm_extioi_get(void *opaque) +{ + kvm_extioi_access_regs(opaque, false); + kvm_extioi_access_sw_status(opaque, false); + return 0; +} + +int kvm_extioi_put(void *opaque, int version_id) +{ + LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque); + int fd = les->dev_fd; + + kvm_extioi_access_regs(opaque, true); + kvm_extioi_access_sw_status(opaque, true); + kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, + KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED, + NULL, true, &error_abort); + return 0; +} + void kvm_extioi_realize(DeviceState *dev, Error **errp) { LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev); diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h index 69565e14ab..9be1d736ea 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -27,5 +27,7 @@ struct LoongArchExtIOIClass { }; void kvm_extioi_realize(DeviceState *dev, Error **errp); +int kvm_extioi_get(void *opaque); +int kvm_extioi_put(void *opaque, int version_id); #endif /* LOONGARCH_EXTIOI_H */ From 412f655566bfadfe85d6f52a7e4420b418f261c3 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:23 +0800 Subject: [PATCH 03/14] hw/intc/loongarch_ipi: Add kernel irqchip realize function Function kvm_ipi_realize() is added if kvm_irqchip_in_kernel() return true. It is to create and initialize IPI device in kernel mode. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-4-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_ipi.c | 5 +++++ hw/intc/loongarch_ipi_kvm.c | 27 +++++++++++++++++++++++++++ hw/intc/loongson_ipi_common.c | 5 +++++ hw/intc/meson.build | 2 ++ include/hw/intc/loongarch_ipi.h | 3 +++ 5 files changed, 42 insertions(+) create mode 100644 hw/intc/loongarch_ipi_kvm.c diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 74372a2039..159ba91fb6 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -11,6 +11,7 @@ #include "qapi/error.h" #include "hw/intc/loongarch_ipi.h" #include "hw/qdev-properties.h" +#include "system/kvm.h" #include "target/loongarch/cpu.h" static AddressSpace *get_iocsr_as(CPUState *cpu) @@ -91,6 +92,10 @@ static void loongarch_ipi_realize(DeviceState *dev, Error **errp) lics->cpu[i].ipi = lics; qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1); } + + if (kvm_irqchip_in_kernel()) { + kvm_ipi_realize(dev, errp); + } } static void loongarch_ipi_reset_hold(Object *obj, ResetType type) diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c new file mode 100644 index 0000000000..51e9c7ed1e --- /dev/null +++ b/hw/intc/loongarch_ipi_kvm.c @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch IPI interrupt KVM support + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/intc/loongarch_ipi.h" +#include "system/kvm.h" +#include "target/loongarch/cpu.h" + +void kvm_ipi_realize(DeviceState *dev, Error **errp) +{ + LoongarchIPIState *lis = LOONGARCH_IPI(dev); + int ret; + + ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_IPI, false); + if (ret < 0) { + fprintf(stderr, "IPI KVM_CREATE_DEVICE failed: %s\n", + strerror(-ret)); + abort(); + } + + lis->dev_fd = ret; +} diff --git a/hw/intc/loongson_ipi_common.c b/hw/intc/loongson_ipi_common.c index f32661c40f..ff2cc8bc91 100644 --- a/hw/intc/loongson_ipi_common.c +++ b/hw/intc/loongson_ipi_common.c @@ -11,6 +11,7 @@ #include "hw/irq.h" #include "qemu/log.h" #include "migration/vmstate.h" +#include "system/kvm.h" #include "trace.h" MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data, @@ -255,6 +256,10 @@ static void loongson_ipi_common_realize(DeviceState *dev, Error **errp) LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + if (kvm_irqchip_in_kernel()) { + return; + } + memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev), &loongson_ipi_iocsr_ops, s, "loongson_ipi_iocsr", 0x48); diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 70e7548c52..1cc999771d 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -71,6 +71,8 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c')) specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) +specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_IPI'], + if_true: files('loongarch_ipi_kvm.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.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', 'loongarch_extioi_common.c')) diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h index a7c6bf85d3..608cd09a78 100644 --- a/include/hw/intc/loongarch_ipi.h +++ b/include/hw/intc/loongarch_ipi.h @@ -16,6 +16,7 @@ OBJECT_DECLARE_TYPE(LoongarchIPIState, LoongarchIPIClass, LOONGARCH_IPI) struct LoongarchIPIState { LoongsonIPICommonState parent_obj; + int dev_fd; }; struct LoongarchIPIClass { @@ -24,4 +25,6 @@ struct LoongarchIPIClass { ResettablePhases parent_phases; }; +void kvm_ipi_realize(DeviceState *dev, Error **errp); + #endif From 14be318c952ce2c29f2a69204a23c0008f779a3f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:24 +0800 Subject: [PATCH 04/14] hw/intc/loongson_ipi: Add load and save interface with ipi_common class Add pre_save and post_load interfaces with ipi_common class, here only framework ipi_common adds these interfaces. The defailed implementation is LoongArchIPI child device in later. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-5-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongson_ipi_common.c | 28 +++++++++++++++++++++++++++ include/hw/intc/loongson_ipi_common.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/hw/intc/loongson_ipi_common.c b/hw/intc/loongson_ipi_common.c index ff2cc8bc91..8cd78d4858 100644 --- a/hw/intc/loongson_ipi_common.c +++ b/hw/intc/loongson_ipi_common.c @@ -282,10 +282,38 @@ static void loongson_ipi_common_unrealize(DeviceState *dev) g_free(s->cpu); } +static int loongson_ipi_common_pre_save(void *opaque) +{ + IPICore *ipicore = (IPICore *)opaque; + LoongsonIPICommonState *s = ipicore->ipi; + LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s); + + if (licc->pre_save) { + return licc->pre_save(s); + } + + return 0; +} + +static int loongson_ipi_common_post_load(void *opaque, int version_id) +{ + IPICore *ipicore = (IPICore *)opaque; + LoongsonIPICommonState *s = ipicore->ipi; + LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s); + + if (licc->post_load) { + return licc->post_load(s, version_id); + } + + return 0; +} + static const VMStateDescription vmstate_ipi_core = { .name = "ipi-single", .version_id = 2, .minimum_version_id = 2, + .pre_save = loongson_ipi_common_pre_save, + .post_load = loongson_ipi_common_post_load, .fields = (const VMStateField[]) { VMSTATE_UINT32(status, IPICore), VMSTATE_UINT32(en, IPICore), diff --git a/include/hw/intc/loongson_ipi_common.h b/include/hw/intc/loongson_ipi_common.h index b587f9c571..e58ce2aa1c 100644 --- a/include/hw/intc/loongson_ipi_common.h +++ b/include/hw/intc/loongson_ipi_common.h @@ -48,6 +48,8 @@ struct LoongsonIPICommonClass { AddressSpace *(*get_iocsr_as)(CPUState *cpu); int (*cpu_by_arch_id)(LoongsonIPICommonState *lics, int64_t id, int *index, CPUState **pcs); + int (*pre_save)(void *opaque); + int (*post_load)(void *opaque, int version_id); }; MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data, From f936caa315750406f50feb1ac9c93770b47ebe96 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:25 +0800 Subject: [PATCH 05/14] hw/intc/loongarch_ipi: Add kernel irqchip save and restore function Add save and store funtction if kvm_irqchip_in_kernel() return true, it is to get and set IPI irqchip state from KVM kernel. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-6-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_ipi.c | 20 ++++++++++++ hw/intc/loongarch_ipi_kvm.c | 54 +++++++++++++++++++++++++++++++++ include/hw/intc/loongarch_ipi.h | 2 ++ 3 files changed, 76 insertions(+) diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 159ba91fb6..0ea91ea054 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -171,6 +171,24 @@ static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev, core->cpu = NULL; } +static int loongarch_ipi_pre_save(void *opaque) +{ + if (kvm_irqchip_in_kernel()) { + return kvm_ipi_get(opaque); + } + + return 0; +} + +static int loongarch_ipi_post_load(void *opaque, int version_id) +{ + if (kvm_irqchip_in_kernel()) { + return kvm_ipi_put(opaque, version_id); + } + + return 0; +} + static void loongarch_ipi_class_init(ObjectClass *klass, const void *data) { LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); @@ -187,6 +205,8 @@ static void loongarch_ipi_class_init(ObjectClass *klass, const void *data) licc->cpu_by_arch_id = loongarch_cpu_by_arch_id; hc->plug = loongarch_ipi_cpu_plug; hc->unplug = loongarch_ipi_cpu_unplug; + licc->pre_save = loongarch_ipi_pre_save; + licc->post_load = loongarch_ipi_post_load; } static const TypeInfo loongarch_ipi_types[] = { diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c index 51e9c7ed1e..b615060d83 100644 --- a/hw/intc/loongarch_ipi_kvm.c +++ b/hw/intc/loongarch_ipi_kvm.c @@ -11,6 +11,60 @@ #include "system/kvm.h" #include "target/loongarch/cpu.h" +static void kvm_ipi_access_reg(int fd, uint64_t addr, uint32_t *val, bool write) +{ + kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS, + addr, val, write, &error_abort); +} + +static void kvm_ipi_access_regs(void *opaque, bool write) +{ + LoongsonIPICommonState *ipi = (LoongsonIPICommonState *)opaque; + LoongarchIPIState *lis = LOONGARCH_IPI(opaque); + IPICore *core; + uint64_t attr; + int cpu, fd = lis->dev_fd; + + for (cpu = 0; cpu < ipi->num_cpu; cpu++) { + core = &ipi->cpu[cpu]; + attr = (cpu << 16) | CORE_STATUS_OFF; + kvm_ipi_access_reg(fd, attr, &core->status, write); + + attr = (cpu << 16) | CORE_EN_OFF; + kvm_ipi_access_reg(fd, attr, &core->en, write); + + attr = (cpu << 16) | CORE_SET_OFF; + kvm_ipi_access_reg(fd, attr, &core->set, write); + + attr = (cpu << 16) | CORE_CLEAR_OFF; + kvm_ipi_access_reg(fd, attr, &core->clear, write); + + attr = (cpu << 16) | CORE_BUF_20; + kvm_ipi_access_reg(fd, attr, &core->buf[0], write); + + attr = (cpu << 16) | CORE_BUF_28; + kvm_ipi_access_reg(fd, attr, &core->buf[2], write); + + attr = (cpu << 16) | CORE_BUF_30; + kvm_ipi_access_reg(fd, attr, &core->buf[4], write); + + attr = (cpu << 16) | CORE_BUF_38; + kvm_ipi_access_reg(fd, attr, &core->buf[6], write); + } +} + +int kvm_ipi_get(void *opaque) +{ + kvm_ipi_access_regs(opaque, false); + return 0; +} + +int kvm_ipi_put(void *opaque, int version_id) +{ + kvm_ipi_access_regs(opaque, true); + return 0; +} + void kvm_ipi_realize(DeviceState *dev, Error **errp) { LoongarchIPIState *lis = LOONGARCH_IPI(dev); diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h index 608cd09a78..5175a6b004 100644 --- a/include/hw/intc/loongarch_ipi.h +++ b/include/hw/intc/loongarch_ipi.h @@ -26,5 +26,7 @@ struct LoongarchIPIClass { }; void kvm_ipi_realize(DeviceState *dev, Error **errp); +int kvm_ipi_get(void *opaque); +int kvm_ipi_put(void *opaque, int version_id); #endif From 5b0e05b9023793197b82fd6feb275459adc9e10c Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:26 +0800 Subject: [PATCH 06/14] hw/intc/loongarch_pch_msi: Inject MSI interrupt to kernel If kvm_irqchip_in_kernel() return true, MSI interrupt can be injected with API kvm_irqchip_send_msi() to KVM. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-7-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_msi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c index 06eb944da0..f6d163158d 100644 --- a/hw/intc/loongarch_pch_msi.c +++ b/hw/intc/loongarch_pch_msi.c @@ -13,6 +13,7 @@ #include "hw/pci/msi.h" #include "hw/misc/unimp.h" #include "migration/vmstate.h" +#include "system/kvm.h" #include "trace.h" static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size) @@ -26,6 +27,15 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr, LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque; int irq_num; + if (kvm_irqchip_in_kernel()) { + MSIMessage msg; + + msg.address = addr; + msg.data = val; + kvm_irqchip_send_msi(kvm_state, msg); + return; + } + /* * vector number is irq number from upper extioi intc * need subtract irq base to get msi vector offset From b758e28974614a15e70fbc983e28fe77852564ee Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:27 +0800 Subject: [PATCH 07/14] hw/intc/loongarch_pch: Add kernel irqchip realize function Function kvm_pic_realize() is added if kvm_irqchip_in_kernel() return true. It is to notify KVM kernel to create and initialize PCH PCI device in kernel mode. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-8-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 14 ++++++++--- hw/intc/loongarch_pic_kvm.c | 38 +++++++++++++++++++++++++++++ hw/intc/meson.build | 2 ++ include/hw/intc/loongarch_pch_pic.h | 3 +++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 hw/intc/loongarch_pic_kvm.c diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index ebb33ed0b0..6ac3a72c31 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -10,6 +10,7 @@ #include "qemu/log.h" #include "hw/irq.h" #include "hw/intc/loongarch_pch_pic.h" +#include "system/kvm.h" #include "trace.h" #include "qapi/error.h" @@ -275,10 +276,15 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out(dev, s->parent_irq, s->irq_num); qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num); - memory_region_init_io(&s->iomem, OBJECT(dev), - &loongarch_pch_pic_ops, - s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE); - sysbus_init_mmio(sbd, &s->iomem); + + if (kvm_irqchip_in_kernel()) { + kvm_pic_realize(dev, errp); + } else { + memory_region_init_io(&s->iomem, OBJECT(dev), + &loongarch_pch_pic_ops, + s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE); + sysbus_init_mmio(sbd, &s->iomem); + } } static void loongarch_pic_class_init(ObjectClass *klass, const void *data) diff --git a/hw/intc/loongarch_pic_kvm.c b/hw/intc/loongarch_pic_kvm.c new file mode 100644 index 0000000000..ee77f04a13 --- /dev/null +++ b/hw/intc/loongarch_pic_kvm.c @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch kvm pch pic interrupt support + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/boards.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/loongarch/virt.h" +#include "hw/pci-host/ls7a.h" +#include "system/kvm.h" + +void kvm_pic_realize(DeviceState *dev, Error **errp) +{ + LoongarchPICState *lps = LOONGARCH_PIC(dev); + uint64_t pch_pic_base = VIRT_PCH_REG_BASE; + int ret; + + ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_PCHPIC, false); + if (ret < 0) { + fprintf(stderr, "Create KVM_LOONGARCH_PCHPIC failed: %s\n", + strerror(-ret)); + abort(); + } + + lps->dev_fd = ret; + ret = kvm_device_access(lps->dev_fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL, + KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT, + &pch_pic_base, true, NULL); + if (ret < 0) { + fprintf(stderr, "KVM_LOONGARCH_PCH_PIC_INIT failed: %s\n", + strerror(-ret)); + abort(); + } +} diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 1cc999771d..3137521a4a 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -74,6 +74,8 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_IPI'], if_true: files('loongarch_ipi_kvm.c')) specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.c')) +specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_PCH_PIC'], + if_true: files('loongarch_pic_kvm.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', 'loongarch_extioi_common.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'], diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h index 839a59a43b..4b52f1165f 100644 --- a/include/hw/intc/loongarch_pch_pic.h +++ b/include/hw/intc/loongarch_pch_pic.h @@ -16,6 +16,7 @@ OBJECT_DECLARE_TYPE(LoongarchPICState, LoongarchPICClass, LOONGARCH_PIC) struct LoongarchPICState { LoongArchPICCommonState parent_obj; + int dev_fd; }; struct LoongarchPICClass { @@ -25,4 +26,6 @@ struct LoongarchPICClass { ResettablePhases parent_phases; }; +void kvm_pic_realize(DeviceState *dev, Error **errp); + #endif /* HW_LOONGARCH_PCH_PIC_H */ From 11a04c9f40ac479f68139f6801da314591e67ae1 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:28 +0800 Subject: [PATCH 08/14] hw/intc/loongarch_pch: Add kernel irqchip save and restore function Add save and store funtction if kvm_irqchip_in_kernel() return true, it is to get and set PCH PCI irqchip state from KVM kernel. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-9-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 22 ++++++++++++ hw/intc/loongarch_pic_kvm.c | 47 ++++++++++++++++++++++++++ include/hw/intc/loongarch_pch_pic.h | 2 ++ include/hw/intc/loongarch_pic_common.h | 1 + 4 files changed, 72 insertions(+) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 6ac3a72c31..13b5766444 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -287,16 +287,38 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp) } } +static int loongarch_pic_pre_save(LoongArchPICCommonState *opaque) +{ + if (kvm_irqchip_in_kernel()) { + return kvm_pic_get(opaque); + } + + return 0; +} + +static int loongarch_pic_post_load(LoongArchPICCommonState *opaque, + int version_id) +{ + if (kvm_irqchip_in_kernel()) { + return kvm_pic_put(opaque, version_id); + } + + return 0; +} + static void loongarch_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass); + LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); resettable_class_set_parent_phases(rc, NULL, loongarch_pic_reset_hold, NULL, &lpc->parent_phases); device_class_set_parent_realize(dc, loongarch_pic_realize, &lpc->parent_realize); + lpcc->pre_save = loongarch_pic_pre_save; + lpcc->post_load = loongarch_pic_post_load; } static const TypeInfo loongarch_pic_types[] = { diff --git a/hw/intc/loongarch_pic_kvm.c b/hw/intc/loongarch_pic_kvm.c index ee77f04a13..3eef81a9bb 100644 --- a/hw/intc/loongarch_pic_kvm.c +++ b/hw/intc/loongarch_pic_kvm.c @@ -13,6 +13,53 @@ #include "hw/pci-host/ls7a.h" #include "system/kvm.h" +static void kvm_pch_pic_access_reg(int fd, uint64_t addr, void *val, bool write) +{ + kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS, + addr, val, write, &error_abort); +} + +static void kvm_pch_pic_access(void *opaque, bool write) +{ + LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque); + LoongarchPICState *lps = LOONGARCH_PIC(opaque); + int fd = lps->dev_fd; + int addr, offset; + + kvm_pch_pic_access_reg(fd, PCH_PIC_INT_MASK, &s->int_mask, write); + kvm_pch_pic_access_reg(fd, PCH_PIC_HTMSI_EN, &s->htmsi_en, write); + kvm_pch_pic_access_reg(fd, PCH_PIC_INT_EDGE, &s->intedge, write); + kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL0, &s->auto_crtl0, write); + kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL1, &s->auto_crtl1, write); + + for (addr = PCH_PIC_ROUTE_ENTRY; + addr < PCH_PIC_ROUTE_ENTRY_END; addr++) { + offset = addr - PCH_PIC_ROUTE_ENTRY; + kvm_pch_pic_access_reg(fd, addr, &s->route_entry[offset], write); + } + + for (addr = PCH_PIC_HTMSI_VEC; addr < PCH_PIC_HTMSI_VEC_END; addr++) { + offset = addr - PCH_PIC_HTMSI_VEC; + kvm_pch_pic_access_reg(fd, addr, &s->htmsi_vector[offset], write); + } + + kvm_pch_pic_access_reg(fd, PCH_PIC_INT_REQUEST, &s->intirr, write); + kvm_pch_pic_access_reg(fd, PCH_PIC_INT_STATUS, &s->intisr, write); + kvm_pch_pic_access_reg(fd, PCH_PIC_INT_POL, &s->int_polarity, write); +} + +int kvm_pic_get(void *opaque) +{ + kvm_pch_pic_access(opaque, false); + return 0; +} + +int kvm_pic_put(void *opaque, int version_id) +{ + kvm_pch_pic_access(opaque, true); + return 0; +} + void kvm_pic_realize(DeviceState *dev, Error **errp) { LoongarchPICState *lps = LOONGARCH_PIC(dev); diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h index 4b52f1165f..a46b6f8985 100644 --- a/include/hw/intc/loongarch_pch_pic.h +++ b/include/hw/intc/loongarch_pch_pic.h @@ -27,5 +27,7 @@ struct LoongarchPICClass { }; void kvm_pic_realize(DeviceState *dev, Error **errp); +int kvm_pic_get(void *opaque); +int kvm_pic_put(void *opaque, int version_id); #endif /* HW_LOONGARCH_PCH_PIC_H */ diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index 9349a055d0..f774c975d4 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -23,6 +23,7 @@ #define PCH_PIC_ROUTE_ENTRY_END 0x13f #define PCH_PIC_HTMSI_VEC 0x200 #define PCH_PIC_HTMSI_VEC_END 0x23f +#define PCH_PIC_INT_REQUEST 0x380 #define PCH_PIC_INT_STATUS 0x3a0 #define PCH_PIC_INT_POL 0x3e0 From 0dd6798a1adda03dcfa6304437faa8e62a193d9c Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:29 +0800 Subject: [PATCH 09/14] hw/intc/loongarch_pch: Inject irq line interrupt to kernel If kvm_irqchip_in_kernel() return true, irq line interrupt can be injected with API kvm_set_irq() to KVM. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-10-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 13b5766444..1adef980d4 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -49,6 +49,11 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level) assert(irq < s->irq_num); trace_loongarch_pch_pic_irq_handler(irq, level); + if (kvm_irqchip_in_kernel()) { + kvm_set_irq(kvm_state, irq, !!level); + return; + } + if (s->intedge & mask) { /* Edge triggered */ if (level) { From c642ddf19b248bb668e40a8d15089b877e4057fa Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:30:30 +0800 Subject: [PATCH 10/14] hw/loongarch/virt: Add reset support for kernel irqchip When system reboot, interrupt controller is restored to initial state. However if interrupt controller extioi/ipi/pch_pic is emulated in kernel, it should notify kvm to do so. Here suspend and restore API is used for reset, set initial state in qemu user space and restore API is used to notify kvm to reload register state. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063033.2557365-11-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_extioi.c | 4 ++++ hw/intc/loongarch_extioi_kvm.c | 4 ++++ hw/intc/loongarch_ipi.c | 4 ++++ hw/intc/loongarch_ipi_kvm.c | 4 ++++ hw/intc/loongarch_pch_pic.c | 4 ++++ hw/intc/loongarch_pic_kvm.c | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index 7be0685f36..8b8ac6b187 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -391,6 +391,10 @@ static void loongarch_extioi_reset_hold(Object *obj, ResetType type) if (lec->parent_phases.hold) { lec->parent_phases.hold(obj, type); } + + if (kvm_irqchip_in_kernel()) { + kvm_extioi_put(obj, 0); + } } static int vmstate_extioi_pre_save(void *opaque) diff --git a/hw/intc/loongarch_extioi_kvm.c b/hw/intc/loongarch_extioi_kvm.c index f4c618ca4c..0133540c45 100644 --- a/hw/intc/loongarch_extioi_kvm.c +++ b/hw/intc/loongarch_extioi_kvm.c @@ -94,6 +94,10 @@ int kvm_extioi_put(void *opaque, int version_id) LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque); int fd = les->dev_fd; + if (fd == 0) { + return 0; + } + kvm_extioi_access_regs(opaque, true); kvm_extioi_access_sw_status(opaque, true); kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL, diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 0ea91ea054..fc8005c944 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -122,6 +122,10 @@ static void loongarch_ipi_reset_hold(Object *obj, ResetType type) core->clear = 0; memset(core->buf, 0, sizeof(core->buf)); } + + if (kvm_irqchip_in_kernel()) { + kvm_ipi_put(obj, 0); + } } static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev, diff --git a/hw/intc/loongarch_ipi_kvm.c b/hw/intc/loongarch_ipi_kvm.c index b615060d83..4cb3acc921 100644 --- a/hw/intc/loongarch_ipi_kvm.c +++ b/hw/intc/loongarch_ipi_kvm.c @@ -25,6 +25,10 @@ static void kvm_ipi_access_regs(void *opaque, bool write) uint64_t attr; int cpu, fd = lis->dev_fd; + if (fd == 0) { + return; + } + for (cpu = 0; cpu < ipi->num_cpu; cpu++) { core = &ipi->cpu[cpu]; attr = (cpu << 16) | CORE_STATUS_OFF; diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 1adef980d4..c4b242dbf4 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -264,6 +264,10 @@ static void loongarch_pic_reset_hold(Object *obj, ResetType type) if (lpc->parent_phases.hold) { lpc->parent_phases.hold(obj, type); } + + if (kvm_irqchip_in_kernel()) { + kvm_pic_put(obj, 0); + } } static void loongarch_pic_realize(DeviceState *dev, Error **errp) diff --git a/hw/intc/loongarch_pic_kvm.c b/hw/intc/loongarch_pic_kvm.c index 3eef81a9bb..dd504ec6a6 100644 --- a/hw/intc/loongarch_pic_kvm.c +++ b/hw/intc/loongarch_pic_kvm.c @@ -26,6 +26,10 @@ static void kvm_pch_pic_access(void *opaque, bool write) int fd = lps->dev_fd; int addr, offset; + if (fd == 0) { + return; + } + kvm_pch_pic_access_reg(fd, PCH_PIC_INT_MASK, &s->int_mask, write); kvm_pch_pic_access_reg(fd, PCH_PIC_HTMSI_EN, &s->htmsi_en, write); kvm_pch_pic_access_reg(fd, PCH_PIC_INT_EDGE, &s->intedge, write); From 74586a2482575776fff5f5f75e0657524c60719d Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:34:31 +0800 Subject: [PATCH 11/14] target/loongarch: Report error with split kernel_irqchip option Option kernel_irqchip=split is not supported on LoongArch virt machine, report error and exit if detect split kernel_irqchip option. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063431.2557468-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/kvm/kvm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index c66bdd5302..c5d488aa42 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -1253,7 +1253,12 @@ int kvm_arch_init(MachineState *ms, KVMState *s) int kvm_arch_irqchip_create(KVMState *s) { - return 0; + if (kvm_kernel_irqchip_split()) { + error_report("kernel_irqchip=split is not supported on LoongArch"); + exit(1); + } + + return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL); } void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) From 17fb88a0fa0a13b0e2976a2fe04756337d95fe1f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:35:23 +0800 Subject: [PATCH 12/14] hw/loongarch/virt: Disable emulation with IOCSR misc register Register IOCSR MISC_FUNC_REG is to enable features about EXTIOI irqchip. If EXTIOI is emulated in kernel, MISC_FUNC_REG register should be emulated in kernel also. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063523.2557513-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/virt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 34dfbd13e5..e5468b6af9 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -522,6 +522,10 @@ static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr, switch (addr) { case MISC_FUNC_REG: + if (kvm_irqchip_in_kernel()) { + return MEMTX_OK; + } + if (!virt_is_veiointc_enabled(lvms)) { return MEMTX_OK; } @@ -572,6 +576,10 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr, ret = 0x303030354133ULL; /* "3A5000" */ break; case MISC_FUNC_REG: + if (kvm_irqchip_in_kernel()) { + return MEMTX_OK; + } + if (!virt_is_veiointc_enabled(lvms)) { ret |= BIT_ULL(IOCSRM_EXTIOI_EN); break; From 27f5d500c2259650076e3abd72f092b566fd81ac Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 6 Jun 2025 14:36:07 +0800 Subject: [PATCH 13/14] hw/loongarch/virt: Add kernel irqchip support If kvm_irqchip_in_kernel() return true, interrupt controller ExtIOI, IPI, PCH_PCI and PCH_MSI should be emlated in kernel. And it is not necessary to create memory region for these devices in user space. Reviewed-by: Song Gao Signed-off-by: Bibo Mao Message-ID: <20250606063607.2557540-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/virt.c | 57 ++++++++++++++++++++++---------------- target/loongarch/cpu.h | 1 + target/loongarch/kvm/kvm.c | 16 +++++++++++ 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index e5468b6af9..b15ada2078 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -414,12 +414,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) lvms->ipi = ipi; 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)); - /* Create EXTIOI device */ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); lvms->extioi = extioi; @@ -427,12 +421,6 @@ static void virt_irq_init(LoongArchVirtMachineState *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)); - } virt_cpu_irq_init(lvms); pch_pic = qdev_new(TYPE_LOONGARCH_PIC); @@ -440,13 +428,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) 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)); - - /* 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; @@ -456,12 +437,40 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) 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)); - } + if (kvm_irqchip_in_kernel()) { + kvm_loongarch_init_irq_routing(); + } else { + /* 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)); + + /* EXTIOI iocsr memory region */ + 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)); + } + + /* PCH_PIC memory region */ + memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(pch_pic), 0)); + + /* Connect pch_pic irqs to extioi */ + for (i = 0; i < VIRT_PCH_PIC_IRQ_NUM; i++) { + qdev_connect_gpio_out(DEVICE(pch_pic), i, + qdev_get_gpio_in(extioi, i)); + } + + for (i = VIRT_PCH_PIC_IRQ_NUM; i < EXTIOI_IRQS; i++) { + /* Connect pch_msi irqs to extioi */ + qdev_connect_gpio_out(DEVICE(pch_msi), i - VIRT_PCH_PIC_IRQ_NUM, + qdev_get_gpio_in(extioi, i)); + } + } virt_devices_init(pch_pic, lvms); } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 262bf87f7b..9538e8d61d 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -503,5 +503,6 @@ static inline void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu) { } #endif +void kvm_loongarch_init_irq_routing(void); #endif /* LOONGARCH_CPU_H */ diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index c5d488aa42..e5ea2dba9d 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -1240,6 +1240,22 @@ void kvm_arch_init_irq_routing(KVMState *s) { } +void kvm_loongarch_init_irq_routing(void) +{ + int i; + + kvm_async_interrupts_allowed = true; + kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled(); + if (kvm_has_gsi_routing()) { + for (i = 0; i < KVM_IRQCHIP_NUM_PINS; ++i) { + kvm_irqchip_add_irq_route(kvm_state, i, 0, i); + } + + kvm_gsi_routing_allowed = true; + kvm_irqchip_commit_routes(kvm_state); + } +} + int kvm_arch_get_default_type(MachineState *ms) { return 0; From c2a2e1ad2a749caa864281b1d4dc3f16c3f344f6 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 4 Jun 2025 16:40:05 +0800 Subject: [PATCH 14/14] target/loongarch: fix vldi/xvldi raise wrong error on qemu we got an aborted error ** ERROR:../target/loongarch/tcg/insn_trans/trans_vec.c.inc:3574:vldi_get_value: code should not be reached Bail out! ERROR:../target/loongarch/tcg/insn_trans/trans_vec.c.inc:3574:vldi_get_value: code should not be reached Aborted (core dumped) but on 3A600/3A5000 we got a "Illegal instruction" error. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2971 Fixes: 29bb5d727ff ("target/loongarch: Implement vldi") Cc: qemu-stable@nongnu.org Reviewed-by: Bibo Mao Reviewed-by: Richard Henderson Signed-off-by: Song Gao --- target/loongarch/tcg/insn_trans/trans_vec.c.inc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/loongarch/tcg/insn_trans/trans_vec.c.inc b/target/loongarch/tcg/insn_trans/trans_vec.c.inc index d6f0560349..78730029cb 100644 --- a/target/loongarch/tcg/insn_trans/trans_vec.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_vec.c.inc @@ -3465,7 +3465,7 @@ TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b) static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm) { int mode; - uint64_t data, t; + uint64_t data = 0, t; /* * imm bit [11:8] is mode, mode value is 0-12. @@ -3570,17 +3570,26 @@ static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm) } break; default: - generate_exception(ctx, EXCCODE_INE); g_assert_not_reached(); } return data; } +static bool check_valid_vldi_mode(arg_vldi *a) +{ + return extract32(a->imm, 8, 4) <= 12; +} + static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz) { int sel, vece; uint64_t value; + if (!check_valid_vldi_mode(a)) { + generate_exception(ctx, EXCCODE_INE); + return true; + } + if (!check_vec(ctx, oprsz)) { return true; }