[PATCH 05/13] hw/riscv/fdt_common, virt.c: add create_fdt_imsic()
Daniel Henrique Barboza <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
The FDT related to interrupt controllers should definitely be put into helpers, even if only 'virt' benefits from it, due to the amount of code that is relieved from the board alone. We'll start with 'imsic'. For this endeavor we're going to use a helper struct that will carry all the extra FDT arguments in a human format. The alternative would be to add 8 more function arguments, on top of 4 phandle arguments that we're passing around in all these controllers, and that's not only a poor reading experience but it's quite error prone too. We do not want to crowd the fdt-helper with non-FDT logic, hence we're handling the !kvm_enabled() cond in virt.c using the imsic_m_base argument. This is a pattern that we'll fall back on in the next patches too. No FDT changes made. Signed-off-by: Daniel Henrique Barboza <[email protected]> --- hw/riscv/fdt-common.c | 94 ++++++++++++++++++++++++++++++ hw/riscv/virt.c | 104 ++++------------------------------ include/hw/riscv/fdt-common.h | 22 +++++++ 3 files changed, 128 insertions(+), 92 deletions(-) diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c index 67a0a3d8f2..6fa2543a2a 100644 --- a/hw/riscv/fdt-common.c +++ b/hw/riscv/fdt-common.c @@ -15,8 +15,10 @@ #include "target/riscv/cpu_bits.h" #include "hw/riscv/riscv-iommu-bits.h" #include "hw/riscv/iommu.h" +#include "hw/intc/riscv_imsic.h" #include "hw/pci/pci.h" #include "hw/pci/pcie_host.h" +#include "hw/riscv/aia.h" void *create_board_device_tree(const char *model, const char *compatible, int *fdt_size) @@ -495,3 +497,95 @@ void create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys, create_pcie_irq_map(fdt, name, irq_pcie_phandle, aia_type, pcie_irq); } + +static void create_fdt_one_imsic(void *fdt, IMSICFdtProps *props, + hwaddr base_addr, + uint32_t *intc_phandles, uint32_t msi_phandle, + bool m_mode, uint32_t imsic_guest_bits) +{ + RISCVHartArrayState *soc = (RISCVHartArrayState *)props->soc; + g_autofree char *imsic_name = NULL; + uint32_t imsic_max_hart_per_socket, imsic_addr, imsic_size; + g_autofree uint32_t *imsic_cells = NULL; + g_autofree uint32_t *imsic_regs = NULL; + static const char * const imsic_compat[2] = { + "qemu,imsics", "riscv,imsics" + }; + int cpu, socket; + + imsic_cells = g_new0(uint32_t, props->smp_cpus * 2); + imsic_regs = g_new0(uint32_t, props->socket_count * 4); + + for (cpu = 0; cpu < props->smp_cpus; cpu++) { + imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); + imsic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT); + } + + imsic_max_hart_per_socket = 0; + for (socket = 0; socket < props->socket_count; socket++) { + imsic_addr = base_addr + socket * props->imsic_group_max_size; + imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) * + soc[socket].num_harts; + imsic_regs[socket * 4 + 0] = 0; + imsic_regs[socket * 4 + 1] = cpu_to_be32(imsic_addr); + imsic_regs[socket * 4 + 2] = 0; + imsic_regs[socket * 4 + 3] = cpu_to_be32(imsic_size); + if (imsic_max_hart_per_socket < soc[socket].num_harts) { + imsic_max_hart_per_socket = soc[socket].num_harts; + } + } + + imsic_name = g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIx, + base_addr); + qemu_fdt_add_subnode(fdt, imsic_name); + + qemu_fdt_setprop_string_array(fdt, imsic_name, "compatible", + (char **)&imsic_compat, + ARRAY_SIZE(imsic_compat)); + + qemu_fdt_setprop_cell(fdt, imsic_name, "#interrupt-cells", + FDT_IMSIC_INT_CELLS); + qemu_fdt_setprop(fdt, imsic_name, "interrupt-controller", NULL, 0); + qemu_fdt_setprop(fdt, imsic_name, "msi-controller", NULL, 0); + qemu_fdt_setprop(fdt, imsic_name, "interrupts-extended", + imsic_cells, props->smp_cpus * sizeof(uint32_t) * 2); + qemu_fdt_setprop(fdt, imsic_name, "reg", imsic_regs, + props->socket_count * sizeof(uint32_t) * 4); + qemu_fdt_setprop_cell(fdt, imsic_name, "riscv,num-ids", + props->irqchip_num_msis); + + if (imsic_guest_bits) { + qemu_fdt_setprop_cell(fdt, imsic_name, "riscv,guest-index-bits", + imsic_guest_bits); + } + + if (props->socket_count > 1) { + qemu_fdt_setprop_cell(fdt, imsic_name, "riscv,hart-index-bits", + imsic_num_bits(imsic_max_hart_per_socket)); + qemu_fdt_setprop_cell(fdt, imsic_name, "riscv,group-index-bits", + imsic_num_bits(props->socket_count)); + qemu_fdt_setprop_cell(fdt, imsic_name, "riscv,group-index-shift", + IMSIC_MMIO_GROUP_MIN_SHIFT); + } + qemu_fdt_setprop_cell(fdt, imsic_name, "phandle", msi_phandle); +} + +void create_fdt_imsic(void *fdt, IMSICFdtProps *props, + uint32_t *phandle, uint32_t *intc_phandles, + uint32_t *msi_m_phandle, uint32_t *msi_s_phandle) +{ + *msi_m_phandle = (*phandle)++; + *msi_s_phandle = (*phandle)++; + + if (props->imsic_m_base) { + /* M-level IMSIC node */ + create_fdt_one_imsic(fdt, props, props->imsic_m_base, + intc_phandles, *msi_m_phandle, true, 0); + } + + /* S-level IMSIC node */ + create_fdt_one_imsic(fdt, props, props->imsic_s_base, + intc_phandles, *msi_s_phandle, false, + imsic_num_bits(props->aia_guests + 1)); + +} diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index fc381a07f3..0ab91728d9 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -320,97 +320,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s, } } -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) -{ - int cpu, socket; - g_autofree char *imsic_name = NULL; - MachineState *ms = MACHINE(s); - int socket_count = riscv_socket_count(ms); - uint32_t imsic_max_hart_per_socket, imsic_addr, imsic_size; - g_autofree uint32_t *imsic_cells = NULL; - g_autofree uint32_t *imsic_regs = NULL; - static const char * const imsic_compat[2] = { - "qemu,imsics", "riscv,imsics" - }; - - imsic_cells = g_new0(uint32_t, ms->smp.cpus * 2); - imsic_regs = g_new0(uint32_t, socket_count * 4); - - for (cpu = 0; cpu < ms->smp.cpus; cpu++) { - imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); - imsic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT); - } - - imsic_max_hart_per_socket = 0; - for (socket = 0; socket < socket_count; socket++) { - imsic_addr = base_addr + socket * VIRT_IMSIC_GROUP_MAX_SIZE; - imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) * - s->soc[socket].num_harts; - imsic_regs[socket * 4 + 0] = 0; - imsic_regs[socket * 4 + 1] = cpu_to_be32(imsic_addr); - imsic_regs[socket * 4 + 2] = 0; - imsic_regs[socket * 4 + 3] = cpu_to_be32(imsic_size); - if (imsic_max_hart_per_socket < s->soc[socket].num_harts) { - imsic_max_hart_per_socket = s->soc[socket].num_harts; - } - } - - imsic_name = g_strdup_printf("/soc/interrupt-controller@%lx", - (unsigned long)base_addr); - qemu_fdt_add_subnode(ms->fdt, imsic_name); - qemu_fdt_setprop_string_array(ms->fdt, imsic_name, "compatible", - (char **)&imsic_compat, - ARRAY_SIZE(imsic_compat)); - - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells", - FDT_IMSIC_INT_CELLS); - qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", NULL, 0); - qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended", - imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2); - qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs, - socket_count * sizeof(uint32_t) * 4); - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids", - VIRT_IRQCHIP_NUM_MSIS); - - if (imsic_guest_bits) { - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,guest-index-bits", - imsic_guest_bits); - } - - if (socket_count > 1) { - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits", - imsic_num_bits(imsic_max_hart_per_socket)); - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits", - imsic_num_bits(socket_count)); - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift", - IMSIC_MMIO_GROUP_MIN_SHIFT); - } - qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle); -} - -static void create_fdt_imsic(RISCVVirtState *s, - uint32_t *phandle, uint32_t *intc_phandles, - uint32_t *msi_m_phandle, uint32_t *msi_s_phandle) -{ - *msi_m_phandle = (*phandle)++; - *msi_s_phandle = (*phandle)++; - - if (!kvm_enabled()) { - /* M-level IMSIC node */ - create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_M].base, intc_phandles, - *msi_m_phandle, true, 0); - } - - /* S-level IMSIC node */ - create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_S].base, intc_phandles, - *msi_s_phandle, false, - imsic_num_bits(s->aia_guests + 1)); - -} - /* Caller must free string after use */ static char *fdt_get_aplic_nodename(unsigned long aplic_addr) { @@ -583,8 +492,19 @@ static void create_fdt_sockets(RISCVVirtState *s, } if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { - create_fdt_imsic(s, phandle, intc_phandles, + IMSICFdtProps props = { + .soc = &s->soc, .socket_count = riscv_socket_count(ms), + .smp_cpus = ms->smp.cpus, + .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, + .aia_guests = s->aia_guests + }; + + create_fdt_imsic(ms->fdt, &props, phandle, intc_phandles, &msi_m_phandle, &msi_s_phandle); + *msi_pcie_phandle = msi_s_phandle; } diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h index bee8b85597..ab77bbda12 100644 --- a/include/hw/riscv/fdt-common.h +++ b/include/hw/riscv/fdt-common.h @@ -10,6 +10,8 @@ #define RISCV_VIRT_FDT_H #include "target/riscv/cpu.h" +#include "hw/core/boards.h" +#include "hw/riscv/riscv_hart.h" #define FDT_PCI_ADDR_CELLS 3 #define FDT_PCI_INT_CELLS 1 @@ -32,6 +34,23 @@ typedef enum RISCVAIAType { AIA_TYPE_APLIC_IMSIC, } RISCVAIAType; +typedef struct IMSICFdtProps { + /* + * Machines will statically allocate RISCVHartArrayState[] pointer, + * e.g. "RISCVHartArrayState soc[VIRT_SOCKETS_MAX]". We'll have + * to use a void* pointer to handle a soc with variable sizes. + */ + void *soc; + hwaddr imsic_m_base; + hwaddr imsic_s_base; + int socket_count; + int smp_cpus; + int imsic_group_max_size; + int irqchip_num_msis; + int aia_guests; +} IMSICFdtProps; + + void *create_board_device_tree(const char *model, const char *compatible, int *fdt_size); void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size, @@ -72,4 +91,7 @@ void create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys, const MemMapEntry *pcie_mmio, const MemMapEntry *high_pcie, uint32_t irq_pcie_phandle, uint32_t msi_pcie_phandle, uint32_t iommu_sys_phandle, uint32_t pcie_irq); +void create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props, + uint32_t *phandle, uint32_t *intc_phandles, + uint32_t *msi_m_phandle, uint32_t *msi_s_phandle); #endif -- 2.43.0