hw/riscv/aia.h | 58 +++++++++++++++++++++++++
include/hw/riscv/virt.h | 29 -------------
hw/riscv/aia.c | 88 ++++++++++++++++++++++++++++++++++++++
hw/riscv/virt-acpi-build.c | 2 +
hw/riscv/virt.c | 85 ++++--------------------------------
hw/riscv/meson.build | 2 +-
6 files changed, 158 insertions(+), 106 deletions(-)
create mode 100644 hw/riscv/aia.h
create mode 100644 hw/riscv/aia.c
diff --git a/hw/riscv/aia.h b/hw/riscv/aia.h
new file mode 100644
index 000000000000..50c48ea4d79c
--- /dev/null
+++ b/hw/riscv/aia.h
@@ -0,0 +1,58 @@
+/*
+ * QEMU RISC-V Advanced Interrupt Architecture (AIA)
+ *
+ * Copyright (C) 2019 Western Digital Corporation or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_RISCV_AIA_H
+#define HW_RISCV_AIA_H
+
+#include "exec/hwaddr.h"
+
+/*
+ * The virt machine physical address space used by some of the devices
+ * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets,
+ * number of CPUs, and number of IMSIC guest files.
+ *
+ * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS,
+ * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization
+ * of virt machine physical address space.
+ */
+
+#define VIRT_SOCKETS_MAX_BITS 2
+#define VIRT_CPUS_MAX_BITS 9
+#define VIRT_CPUS_MAX (1 << VIRT_CPUS_MAX_BITS)
+#define VIRT_SOCKETS_MAX (1 << VIRT_SOCKETS_MAX_BITS)
+
+#define VIRT_IRQCHIP_NUM_MSIS 255
+#define VIRT_IRQCHIP_NUM_SOURCES 96
+#define VIRT_IRQCHIP_NUM_PRIO_BITS 3
+#define VIRT_IRQCHIP_MAX_GUESTS_BITS 3
+#define VIRT_IRQCHIP_MAX_GUESTS ((1U << VIRT_IRQCHIP_MAX_GUESTS_BITS) - 1U)
+
+
+#define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT)
+#if VIRT_IMSIC_GROUP_MAX_SIZE < \
+ IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS)
+#error "Can't accommodate single IMSIC group in address space"
+#endif
+
+#define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \
+ VIRT_IMSIC_GROUP_MAX_SIZE)
+#if 0x4000000 < VIRT_IMSIC_MAX_SIZE
+#error "Can't accommodate all IMSIC groups in address space"
+#endif
+
+uint32_t imsic_num_bits(uint32_t count);
+
+DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+ const MemMapEntry *aplic_m,
+ const MemMapEntry *aplic_s,
+ const MemMapEntry *imsic_m,
+ const MemMapEntry *imsic_s,
+ int socket, int base_hartid, int hart_count);
+
+
+#endif
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 18a2a323a344..25ec5c665780 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -102,12 +102,6 @@ enum {
#define VIRT_PLATFORM_BUS_NUM_IRQS 32
-#define VIRT_IRQCHIP_NUM_MSIS 255
-#define VIRT_IRQCHIP_NUM_SOURCES 96
-#define VIRT_IRQCHIP_NUM_PRIO_BITS 3
-#define VIRT_IRQCHIP_MAX_GUESTS_BITS 3
-#define VIRT_IRQCHIP_MAX_GUESTS ((1U << VIRT_IRQCHIP_MAX_GUESTS_BITS) - 1U)
-
#define VIRT_PLIC_PRIORITY_BASE 0x00
#define VIRT_PLIC_PENDING_BASE 0x1000
#define VIRT_PLIC_ENABLE_BASE 0x2000
@@ -135,28 +129,5 @@ enum {
bool virt_is_acpi_enabled(RISCVVirtState *s);
bool virt_is_iommu_sys_enabled(RISCVVirtState *s);
void virt_acpi_setup(RISCVVirtState *vms);
-uint32_t imsic_num_bits(uint32_t count);
-
-/*
- * The virt machine physical address space used by some of the devices
- * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets,
- * number of CPUs, and number of IMSIC guest files.
- *
- * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS,
- * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization
- * of virt machine physical address space.
- */
-
-#define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT)
-#if VIRT_IMSIC_GROUP_MAX_SIZE < \
- IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS)
-#error "Can't accommodate single IMSIC group in address space"
-#endif
-
-#define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \
- VIRT_IMSIC_GROUP_MAX_SIZE)
-#if 0x4000000 < VIRT_IMSIC_MAX_SIZE
-#error "Can't accommodate all IMSIC groups in address space"
-#endif
#endif
diff --git a/hw/riscv/aia.c b/hw/riscv/aia.c
new file mode 100644
index 000000000000..0a89d7b49b7b
--- /dev/null
+++ b/hw/riscv/aia.c
@@ -0,0 +1,88 @@
+/*
+ * QEMU RISC-V Advanced Interrupt Architecture (AIA)
+ *
+ * Copyright (C) 2019 Western Digital Corporation or its affiliates.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/kvm.h"
+#include "hw/intc/riscv_aplic.h"
+#include "hw/intc/riscv_imsic.h"
+
+#include "aia.h"
+
+uint32_t imsic_num_bits(uint32_t count)
+{
+ uint32_t ret = 0;
+
+ while (BIT(ret) < count) {
+ ret++;
+ }
+
+ return ret;
+}
+
+DeviceState *riscv_create_aia(bool msimode, int aia_guests,
+ const MemMapEntry *aplic_m,
+ const MemMapEntry *aplic_s,
+ const MemMapEntry *imsic_m,
+ const MemMapEntry *imsic_s,
+ int socket, int base_hartid, int hart_count)
+{
+ int i;
+ hwaddr addr = 0;
+ uint32_t guest_bits;
+ DeviceState *aplic_s_dev = NULL;
+ DeviceState *aplic_m_dev = NULL;
+
+ if (msimode) {
+ if (!kvm_enabled()) {
+ /* Per-socket M-level IMSICs */
+ addr = imsic_m->base + socket * VIRT_IMSIC_GROUP_MAX_SIZE;
+ for (i = 0; i < hart_count; i++) {
+ riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
+ base_hartid + i, true, 1,
+ VIRT_IRQCHIP_NUM_MSIS);
+ }
+ }
+
+ /* Per-socket S-level IMSICs */
+ guest_bits = imsic_num_bits(aia_guests + 1);
+ addr = imsic_s->base + socket * VIRT_IMSIC_GROUP_MAX_SIZE;
+ for (i = 0; i < hart_count; i++) {
+ riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
+ base_hartid + i, false, 1 + aia_guests,
+ VIRT_IRQCHIP_NUM_MSIS);
+ }
+ }
+
+ if (!kvm_enabled()) {
+ /* Per-socket M-level APLIC */
+ aplic_m_dev = riscv_aplic_create(aplic_m->base +
+ socket * aplic_m->size,
+ aplic_m->size,
+ (msimode) ? 0 : base_hartid,
+ (msimode) ? 0 : hart_count,
+ VIRT_IRQCHIP_NUM_SOURCES,
+ VIRT_IRQCHIP_NUM_PRIO_BITS,
+ msimode, true, NULL);
+ }
+
+ /* Per-socket S-level APLIC */
+ aplic_s_dev = riscv_aplic_create(aplic_s->base +
+ socket * aplic_s->size,
+ aplic_s->size,
+ (msimode) ? 0 : base_hartid,
+ (msimode) ? 0 : hart_count,
+ VIRT_IRQCHIP_NUM_SOURCES,
+ VIRT_IRQCHIP_NUM_PRIO_BITS,
+ msimode, false, aplic_m_dev);
+
+ if (kvm_enabled() && msimode) {
+ riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s_dev), addr);
+ }
+
+ return kvm_enabled() ? aplic_s_dev : aplic_m_dev;
+}
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index f1406cb68339..b091a9df9e0f 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -40,6 +40,8 @@
#include "qemu/error-report.h"
#include "system/reset.h"
+#include "aia.h"
+
#define ACPI_BUILD_TABLE_SIZE 0x20000
#define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index))
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index bd8608ea5bfd..01115a0fb946 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -59,6 +59,8 @@
#include "hw/virtio/virtio-iommu.h"
#include "hw/uefi/var-service-api.h"
+#include "aia.h"
+
/* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */
static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type)
{
@@ -509,17 +511,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
}
}
-uint32_t imsic_num_bits(uint32_t count)
-{
- uint32_t ret = 0;
-
- while (BIT(ret) < count) {
- ret++;
- }
-
- return ret;
-}
-
static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr,
uint32_t *intc_phandles, uint32_t
msi_phandle,
bool m_mode, uint32_t imsic_guest_bits)
@@ -1302,68 +1293,6 @@ static DeviceState *virt_create_plic(const MemMapEntry
*memmap, int socket,
memmap[VIRT_PLIC].size);
}
-static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests,
- const MemMapEntry *memmap, int socket,
- int base_hartid, int hart_count)
-{
- int i;
- hwaddr addr = 0;
- uint32_t guest_bits;
- DeviceState *aplic_s = NULL;
- DeviceState *aplic_m = NULL;
- bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC;
-
- if (msimode) {
- if (!kvm_enabled()) {
- /* Per-socket M-level IMSICs */
- addr = memmap[VIRT_IMSIC_M].base +
- socket * VIRT_IMSIC_GROUP_MAX_SIZE;
- for (i = 0; i < hart_count; i++) {
- riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0),
- base_hartid + i, true, 1,
- VIRT_IRQCHIP_NUM_MSIS);
- }
- }
-
- /* Per-socket S-level IMSICs */
- guest_bits = imsic_num_bits(aia_guests + 1);
- addr = memmap[VIRT_IMSIC_S].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE;
- for (i = 0; i < hart_count; i++) {
- riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits),
- base_hartid + i, false, 1 + aia_guests,
- VIRT_IRQCHIP_NUM_MSIS);
- }
- }
-
- if (!kvm_enabled()) {
- /* Per-socket M-level APLIC */
- aplic_m = riscv_aplic_create(memmap[VIRT_APLIC_M].base +
- socket * memmap[VIRT_APLIC_M].size,
- memmap[VIRT_APLIC_M].size,
- (msimode) ? 0 : base_hartid,
- (msimode) ? 0 : hart_count,
- VIRT_IRQCHIP_NUM_SOURCES,
- VIRT_IRQCHIP_NUM_PRIO_BITS,
- msimode, true, NULL);
- }
-
- /* Per-socket S-level APLIC */
- aplic_s = riscv_aplic_create(memmap[VIRT_APLIC_S].base +
- socket * memmap[VIRT_APLIC_S].size,
- memmap[VIRT_APLIC_S].size,
- (msimode) ? 0 : base_hartid,
- (msimode) ? 0 : hart_count,
- VIRT_IRQCHIP_NUM_SOURCES,
- VIRT_IRQCHIP_NUM_PRIO_BITS,
- msimode, false, aplic_m);
-
- if (kvm_enabled() && msimode) {
- riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s), addr);
- }
-
- return kvm_enabled() ? aplic_s : aplic_m;
-}
-
static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
{
DeviceState *dev;
@@ -1625,9 +1554,13 @@ static void virt_machine_init(MachineState *machine)
s->irqchip[i] = virt_create_plic(s->memmap, i,
base_hartid, hart_count);
} else {
- s->irqchip[i] = virt_create_aia(s->aia_type, s->aia_guests,
- s->memmap, i, base_hartid,
- hart_count);
+ s->irqchip[i] = riscv_create_aia(s->aia_type ==
VIRT_AIA_TYPE_APLIC_IMSIC,
+ s->aia_guests,
+ &s->memmap[VIRT_APLIC_M],
+ &s->memmap[VIRT_APLIC_S],
+ &s->memmap[VIRT_IMSIC_M],
+ &s->memmap[VIRT_IMSIC_S],
+ i, base_hartid, hart_count);
}
/* Try to use different IRQCHIP instance based device type */
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 533472e22aef..e53c180d0d10 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -1,5 +1,5 @@
riscv_ss = ss.source_set()
-riscv_ss.add(files('boot.c'))
+riscv_ss.add(files('boot.c', 'aia.c'))
riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
riscv_ss.add(files('riscv_hart.c'))
riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))