KVM initializes CONFIG_IDS to the number of guest MSI IDs supported by
the host. The virt machine currently overwrites it with the fixed
VIRT_IRQCHIP_NUM_MSIS value of 255, which can be inconsistent with the
host-supported guest MSI ID count.
Create the KVM AIA device before realizing the per-socket IMSICs and
read the host-provided CONFIG_IDS value. Use it to configure the QEMU
IMSIC devices and the guest-visible DT and ACPI descriptions. Complete
the remaining KVM AIA setup after all vCPUs have been created, as the
IMSIC address configuration depends on them.
Keep VIRT_IRQCHIP_NUM_MSIS as the default for non-KVM machines.
Fixes: 9634ef7eda5f ("target/riscv: Create an KVM AIA irqchip")
Signed-off-by: Qingwei Hu <[email protected]>
---
hw/riscv/virt-acpi-build.c | 4 +--
hw/riscv/virt.c | 28 ++++++++++++-----
include/hw/riscv/virt.h | 1 +
target/riscv/kvm/kvm-cpu.c | 59 +++++++++++++++++++++++-------------
target/riscv/kvm/kvm_riscv.h | 9 +++---
5 files changed, 66 insertions(+), 35 deletions(-)
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 8e516ec114..0ebfa10a02 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -576,9 +576,9 @@ static void build_madt(GArray *table_data,
build_append_int_noprefix(table_data, 0, 1); /* Reserved */
build_append_int_noprefix(table_data, 0, 4); /* Flags */
/* Number of supervisor mode Interrupt Identities */
- build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
+ build_append_int_noprefix(table_data, s->num_msis, 2);
/* Number of guest mode Interrupt Identities */
- build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
+ build_append_int_noprefix(table_data, s->num_msis, 2);
/* Guest Index Bits */
build_append_int_noprefix(table_data, guest_index_bits, 1);
/* Hart Index Bits */
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index d4b501802f..ba0e74ce83 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -277,7 +277,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
.imsic_m_base = !kvm_enabled() ? s->memmap[VIRT_IMSIC_M].base : 0,
.imsic_s_base = s->memmap[VIRT_IMSIC_S].base,
.imsic_group_max_size = VIRT_IMSIC_GROUP_MAX_SIZE,
- .irqchip_num_msis = VIRT_IRQCHIP_NUM_MSIS,
+ .irqchip_num_msis = s->num_msis,
.aia_guests = s->aia_guests
};
@@ -718,6 +718,7 @@ static void virt_machine_init(MachineState *machine)
DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip;
int i, base_hartid, hart_count;
int socket_count = riscv_socket_count(machine);
+ int aia_fd = -1;
s->memmap = virt_memmap;
@@ -733,6 +734,16 @@ static void virt_machine_init(MachineState *machine)
exit(1);
}
+ /*
+ * Create the KVM AIA device and query the host MSI ID count before
+ * realizing the per-socket IMSICs. Complete AIA initialization after
+ * all vCPUs have been created.
+ */
+ if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) {
+ aia_fd = kvm_riscv_aia_create(VIRT_IRQCHIP_NUM_SOURCES,
+ &s->num_msis);
+ }
+
/* Initialize sockets */
mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL;
for (i = 0; i < socket_count; i++) {
@@ -826,7 +837,7 @@ static void virt_machine_init(MachineState *machine)
&s->memmap[VIRT_IMSIC_M],
&s->memmap[VIRT_IMSIC_S],
i, base_hartid, hart_count,
- VIRT_IRQCHIP_NUM_MSIS,
+ s->num_msis,
VIRT_IRQCHIP_NUM_PRIO_BITS);
}
@@ -845,12 +856,12 @@ static void virt_machine_init(MachineState *machine)
}
}
- if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) {
- kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT,
- VIRT_IRQCHIP_NUM_SOURCES, VIRT_IRQCHIP_NUM_MSIS,
- s->memmap[VIRT_APLIC_S].base,
- s->memmap[VIRT_IMSIC_S].base,
- s->aia_guests);
+ if (aia_fd >= 0) {
+ kvm_riscv_aia_init(machine, aia_fd, IMSIC_MMIO_GROUP_MIN_SHIFT,
+ VIRT_IRQCHIP_NUM_SOURCES,
+ s->memmap[VIRT_APLIC_S].base,
+ s->memmap[VIRT_IMSIC_S].base,
+ s->aia_guests);
}
if (riscv_is_32bit(&s->soc[0])) {
@@ -972,6 +983,7 @@ static void virt_machine_instance_init(Object *obj)
s->acpi = ON_OFF_AUTO_AUTO;
s->iommu_sys = ON_OFF_AUTO_AUTO;
s->num_sources = VIRT_IRQCHIP_NUM_SOURCES;
+ s->num_msis = VIRT_IRQCHIP_NUM_MSIS;
}
static char *virt_get_aia_guests(Object *obj, Error **errp)
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index e516898f9a..f64a2a3448 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -66,6 +66,7 @@ struct RISCVVirtState {
OnOffAuto iommu_sys;
uint16_t pci_iommu_bdf;
uint16_t num_sources;
+ uint32_t num_msis;
};
enum {
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 68e1501b21..02af4e7723 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1859,19 +1859,11 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
"auto");
}
-void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
- uint64_t aia_irq_num, uint64_t aia_msi_num,
- uint64_t aplic_base, uint64_t imsic_base,
- uint64_t guest_num)
+int kvm_riscv_aia_create(uint64_t aia_irq_num, uint32_t *aia_msi_num)
{
- int ret, i;
- int aia_fd = -1;
+ int ret;
+ int aia_fd;
uint64_t default_aia_mode;
- uint64_t socket_count = riscv_socket_count(machine);
- uint64_t max_hart_per_socket = 0;
- uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr;
- uint64_t socket_bits, hart_bits, guest_bits;
- uint64_t max_group_id;
aia_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_RISCV_AIA, false);
@@ -1903,6 +1895,41 @@ void kvm_riscv_aia_create(MachineState *machine,
uint64_t group_shift,
}
}
+ /*
+ * Get the maximum MSI ID supported by the host from the CONFIG_IDS
+ * attribute and use it for the guest-visible interrupt controller
+ * configuration.
+ */
+ ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
+ KVM_DEV_RISCV_AIA_CONFIG_IDS,
+ aia_msi_num, false, NULL);
+ if (ret < 0) {
+ error_report("KVM AIA: failed to get number of MSI IDs");
+ exit(1);
+ }
+
+ if (!kvm_kernel_irqchip_split() && *aia_msi_num < aia_irq_num) {
+ error_report("KVM AIA: host supports only %" PRIu32 " MSI IDs, "
+ "but the virt machine requires at least %" PRIu64,
+ *aia_msi_num, aia_irq_num);
+ exit(1);
+ }
+
+ return aia_fd;
+}
+
+void kvm_riscv_aia_init(MachineState *machine, int aia_fd,
+ uint64_t group_shift, uint64_t aia_irq_num,
+ uint64_t aplic_base, uint64_t imsic_base,
+ uint64_t guest_num)
+{
+ int ret, i;
+ uint64_t socket_count = riscv_socket_count(machine);
+ uint64_t max_hart_per_socket = 0;
+ uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr;
+ uint64_t socket_bits, hart_bits, guest_bits;
+ uint64_t max_group_id;
+
/*
* Skip APLIC creation in KVM if we're running split mode.
* This is done by leaving KVM_DEV_RISCV_AIA_CONFIG_SRCS
@@ -1927,15 +1954,6 @@ void kvm_riscv_aia_create(MachineState *machine,
uint64_t group_shift,
}
}
- ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
- KVM_DEV_RISCV_AIA_CONFIG_IDS,
- &aia_msi_num, true, NULL);
- if (ret < 0) {
- error_report("KVM AIA: failed to set number of msi");
- exit(1);
- }
-
-
if (socket_count > 1) {
max_group_id = socket_count - 1;
socket_bits = find_last_bit(&max_group_id, BITS_PER_LONG) + 1;
@@ -1987,7 +2005,6 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t
group_shift,
}
}
-
if (max_hart_per_socket > 1) {
max_hart_per_socket--;
hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1;
diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h
index 61eaa12443..1499fb4487 100644
--- a/target/riscv/kvm/kvm_riscv.h
+++ b/target/riscv/kvm/kvm_riscv.h
@@ -23,10 +23,11 @@
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
-void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
- uint64_t aia_irq_num, uint64_t aia_msi_num,
- uint64_t aplic_base, uint64_t imsic_base,
- uint64_t guest_num);
+int kvm_riscv_aia_create(uint64_t aia_irq_num, uint32_t *aia_msi_num);
+void kvm_riscv_aia_init(MachineState *machine, int aia_fd,
+ uint64_t group_shift, uint64_t aia_irq_num,
+ uint64_t aplic_base, uint64_t imsic_base,
+ uint64_t guest_num);
void riscv_kvm_aplic_request(void *opaque, int irq, int level);
bool kvm_riscv_has_mp_state(void);
void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp);
--
2.39.5