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 <gaosong@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Message-ID: <20250606063607.2557540-1-maobibo@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
This commit is contained in:
Bibo Mao 2025-06-06 14:36:07 +08:00 committed by Song Gao
parent 17fb88a0fa
commit 27f5d500c2
3 changed files with 50 additions and 24 deletions

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;