diff options
Diffstat (limited to 'hw/intc')
| -rw-r--r-- | hw/intc/riscv_aplic.c | 74 |
1 files changed, 60 insertions, 14 deletions
diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index e160816d26..2e2f2a44f6 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -32,6 +32,7 @@ #include "target/riscv/cpu.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "sysemu/tcg.h" #include "kvm/kvm_riscv.h" #include "migration/vmstate.h" @@ -154,11 +155,38 @@ * KVM AIA only supports APLIC MSI, fallback to QEMU emulation if we want to use * APLIC Wired. */ -static bool is_kvm_aia(bool msimode) +bool riscv_is_kvm_aia_aplic_imsic(bool msimode) { return kvm_irqchip_in_kernel() && msimode; } +bool riscv_use_emulated_aplic(bool msimode) +{ +#ifdef CONFIG_KVM + if (tcg_enabled()) { + return true; + } + + if (!riscv_is_kvm_aia_aplic_imsic(msimode)) { + return true; + } + + return kvm_kernel_irqchip_split(); +#else + return true; +#endif +} + +void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr) +{ +#ifdef CONFIG_KVM + if (riscv_use_emulated_aplic(aplic->msimode)) { + aplic->kvm_msicfgaddr = extract64(addr, 0, 32); + aplic->kvm_msicfgaddrH = extract64(addr, 32, 32); + } +#endif +} + static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { @@ -248,9 +276,12 @@ static void riscv_aplic_set_pending(RISCVAPLICState *aplic, if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) || (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) { - if (!aplic->msimode || (aplic->msimode && !pending)) { + if (!aplic->msimode) { return; } + if (aplic->msimode && !pending) { + goto noskip_write_pending; + } if ((aplic->state[irq] & APLIC_ISTATE_INPUT) && (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) { return; @@ -261,6 +292,7 @@ static void riscv_aplic_set_pending(RISCVAPLICState *aplic, } } +noskip_write_pending: riscv_aplic_set_pending_raw(aplic, irq, pending); } @@ -359,13 +391,16 @@ static void riscv_aplic_msi_send(RISCVAPLICState *aplic, uint32_t lhxs, lhxw, hhxs, hhxw, group_idx, msicfgaddr, msicfgaddrH; aplic_m = aplic; - while (aplic_m && !aplic_m->mmode) { - aplic_m = aplic_m->parent; - } - if (!aplic_m) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n", - __func__); - return; + + if (!aplic->kvm_splitmode) { + while (aplic_m && !aplic_m->mmode) { + aplic_m = aplic_m->parent; + } + if (!aplic_m) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n", + __func__); + return; + } } if (aplic->mmode) { @@ -397,6 +432,11 @@ static void riscv_aplic_msi_send(RISCVAPLICState *aplic, addr |= (uint64_t)(guest_idx & APLIC_xMSICFGADDR_PPN_HART(lhxs)); addr <<= APLIC_xMSICFGADDR_PPN_SHIFT; + if (aplic->kvm_splitmode) { + addr |= aplic->kvm_msicfgaddr; + addr |= ((uint64_t)aplic->kvm_msicfgaddrH << 32); + } + address_space_stl_le(&address_space_memory, addr, eiid, MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { @@ -853,7 +893,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) uint32_t i; RISCVAPLICState *aplic = RISCV_APLIC(dev); - if (!is_kvm_aia(aplic->msimode)) { + if (riscv_use_emulated_aplic(aplic->msimode)) { aplic->bitfield_words = (aplic->num_irqs + 31) >> 5; aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs); aplic->state = g_new0(uint32_t, aplic->num_irqs); @@ -870,6 +910,10 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) memory_region_init_io(&aplic->mmio, OBJECT(dev), &riscv_aplic_ops, aplic, TYPE_RISCV_APLIC, aplic->aperture_size); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &aplic->mmio); + + if (kvm_enabled()) { + aplic->kvm_splitmode = true; + } } /* @@ -877,7 +921,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) * have IRQ lines delegated by their parent APLIC. */ if (!aplic->parent) { - if (kvm_enabled() && is_kvm_aia(aplic->msimode)) { + if (kvm_enabled() && !riscv_use_emulated_aplic(aplic->msimode)) { qdev_init_gpio_in(dev, riscv_kvm_aplic_request, aplic->num_irqs); } else { qdev_init_gpio_in(dev, riscv_aplic_request, aplic->num_irqs); @@ -916,8 +960,8 @@ static const Property riscv_aplic_properties[] = { static const VMStateDescription vmstate_riscv_aplic = { .name = "riscv_aplic", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (const VMStateField[]) { VMSTATE_UINT32(domaincfg, RISCVAPLICState), VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState), @@ -925,6 +969,8 @@ static const VMStateDescription vmstate_riscv_aplic = { VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState), VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState), VMSTATE_UINT32(genmsi, RISCVAPLICState), + VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState), + VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState), VMSTATE_VARRAY_UINT32(sourcecfg, RISCVAPLICState, num_irqs, 0, vmstate_info_uint32, uint32_t), @@ -1020,7 +1066,7 @@ DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size, sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - if (!is_kvm_aia(msimode)) { + if (riscv_use_emulated_aplic(msimode)) { sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); } |