* [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep)
@ 2026-08-28 20:39 Daniel Henrique Barboza
2026-08-28 20:39 ` [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
` (15 more replies)
0 siblings, 16 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Michael Tokarev, Laurent Vivier,
open list:Trivial patches
Hi,
In this new version a new patch was added. It is a fix for the aclint
FDT, suggested by Chao in the v4 review. We're fixing the FDT before
moving the aclint FDT to the helper in the patch that follows.
No other changes made. Patches based on alistair/riscv-to-apply.next.
Changes from v4:
- patch 8 (new): fix aclint soc/mtimer node
- patch 9:
- move the aclint FDT to the helper without any changes, as stated in
the commit msg.
- v4 link: https://lore.kernel.org/qemu-devel/20260827222608.329788-1-daniel.barboza@oss.qualcomm.com/
Daniel Henrique Barboza (15):
hw/riscv/fdt-common: prepend helpers with "riscv_"
hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
hw/riscv/virt.c: fix aclint soc/mtimer nodename
hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
hw/riscv/device-common, virt.c: add flash helpers
hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
hw/riscv/device-common.c | 168 ++++++
hw/riscv/fdt-common.c | 613 +++++++++++++++++++++-
hw/riscv/meson.build | 1 +
hw/riscv/riscv-iommu-sys.c | 25 +
hw/riscv/riscv-iommu.h | 3 +
hw/riscv/sifive_u.c | 34 +-
hw/riscv/spike.c | 30 +-
hw/riscv/tt_atlantis.c | 22 +-
hw/riscv/virt.c | 861 +++++--------------------------
include/hw/riscv/device-common.h | 32 ++
include/hw/riscv/fdt-common.h | 146 +++++-
include/hw/riscv/virt.h | 15 -
12 files changed, 1112 insertions(+), 838 deletions(-)
create mode 100644 hw/riscv/device-common.c
create mode 100644 include/hw/riscv/device-common.h
--
2.43.0
^ permalink raw reply [flat|nested] 55+ messages in thread
* [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_"
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-09-01 4:42 ` Alistair Francis
2026-09-02 16:24 ` Philippe Mathieu-Daudé
2026-08-28 20:39 ` [PATCH v5 02/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
` (14 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt, Joel Stanley, Nicholas Piggin, Anirudh Srinivasan,
Michael Ellerman, Portia Stephens
Given that the helpers are public API we should prefix them with
"riscv_" to avoid conflicts when linking with different targets in the
future, i.e. we should not use generic names like
"create_fdt_socket_memory".
Despite the amount of lines this is a mechanical change and no real
FDT changes are intended.
Suggested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 45 ++++++++++++++++----------------
hw/riscv/sifive_u.c | 34 +++++++++++++------------
hw/riscv/spike.c | 30 ++++++++++++----------
hw/riscv/tt_atlantis.c | 22 ++++++++--------
hw/riscv/virt.c | 42 +++++++++++++++---------------
include/hw/riscv/fdt-common.h | 48 ++++++++++++++++++-----------------
6 files changed, 117 insertions(+), 104 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index aa143a618b..3a8da03cfb 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -14,8 +14,8 @@
#include "hw/riscv/fdt-common.h"
#include "target/riscv/cpu_bits.h"
-void *create_board_device_tree(const char *model, const char *compatible,
- int *fdt_size)
+void *riscv_create_board_device_tree(const char *model, const char *compatible,
+ int *fdt_size)
{
void *fdt = create_device_tree(fdt_size);
@@ -38,8 +38,8 @@ void *create_board_device_tree(const char *model, const char *compatible,
return fdt;
}
-void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
- int socket_id, bool numa_enabled)
+void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
+ int socket_id, bool numa_enabled)
{
g_autofree char *mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr);
@@ -52,9 +52,9 @@ void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
}
}
-void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
- int socket_id, uint32_t *intc_phandles,
- int num_harts, bool numa_enabled)
+void riscv_create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
+ int socket_id, uint32_t *intc_phandles,
+ int num_harts, bool numa_enabled)
{
g_autofree uint32_t *clint_cells = g_new0(uint32_t, num_harts * 4);
g_autofree char *clint_name = NULL;
@@ -84,7 +84,8 @@ void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
}
}
-void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency)
+void riscv_fdt_create_cpu_socket_subnode(void *fdt,
+ uint64_t timebase_frequency)
{
qemu_fdt_add_subnode(fdt, "/cpus");
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
@@ -169,11 +170,11 @@ create_fdt_socket_cpu_internal(void *fdt, char *clust_name, RISCVCPU *cpu_ptr,
qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
}
-void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
- int socket_id, int num_harts_socket,
- int socket_hartid_base, uint32_t *phandle,
- uint32_t *intc_phandles, bool numa_enabled,
- bool is_32_bit)
+void riscv_create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
+ int socket_id, int num_harts_socket,
+ int socket_hartid_base, uint32_t *phandle,
+ uint32_t *intc_phandles, bool numa_enabled,
+ bool is_32_bit)
{
g_autofree char *clust_name = NULL;
@@ -191,21 +192,21 @@ void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
}
void
-create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
- int cpu_id, int socket_id,
- int socket_hartid_base, uint32_t *phandle,
- uint32_t *intc_phandles)
+riscv_create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
+ int cpu_id, int socket_id,
+ int socket_hartid_base, uint32_t *phandle,
+ uint32_t *intc_phandles)
{
create_fdt_socket_cpu_internal(fdt, clust_name, NULL, cpu_id,
socket_id, socket_hartid_base,
phandle, intc_phandles, false, false);
}
-void create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
- uint32_t plic_phandle, uint32_t int_cells,
- uint32_t addr_cells, uint32_t *plic_cells,
- uint32_t cells_size, uint32_t ndev_sources,
- bool numa_enabled, int socket_id)
+void riscv_create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
+ uint32_t plic_phandle, uint32_t int_cells,
+ uint32_t addr_cells, uint32_t *plic_cells,
+ uint32_t cells_size, uint32_t ndev_sources,
+ bool numa_enabled, int socket_id)
{
g_autofree char *nodename = NULL;
static const char * const plic_compat[2] = {
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 57a57c96e1..852c48c056 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -108,8 +108,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms->smp.cpus);
g_autofree char *clust_name = NULL;
- fdt = ms->fdt = create_board_device_tree("SiFive HiFive Unleashed A00",
- "sifive,hifive-unleashed-a00", &s->fdt_size);
+ fdt = ms->fdt = riscv_create_board_device_tree(
+ "SiFive HiFive Unleashed A00",
+ "sifive,hifive-unleashed-a00",
+ &s->fdt_size);
hfclk_phandle = phandle++;
nodename = g_strdup_printf("/hfclk");
@@ -133,10 +135,10 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
g_free(nodename);
- create_fdt_socket_memory(fdt, memmap[SIFIVE_U_DEV_DRAM].base,
- ms->ram_size, 0, false);
+ riscv_create_fdt_socket_memory(fdt, memmap[SIFIVE_U_DEV_DRAM].base,
+ ms->ram_size, 0, false);
- fdt_create_cpu_socket_subnode(fdt, CLINT_TIMEBASE_FREQ);
+ riscv_fdt_create_cpu_socket_subnode(fdt, CLINT_TIMEBASE_FREQ);
clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", 0);
qemu_fdt_add_subnode(fdt, clust_name);
@@ -157,15 +159,15 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
riscv_isa_write_fdt(&s->soc.e_cpus.harts[0], fdt, nodename);
}
- create_fdt_socket_cpu_sifive(fdt, clust_name, cpu, 0, 0,
- &phandle, intc_phandles);
+ riscv_create_fdt_socket_cpu_sifive(fdt, clust_name, cpu, 0, 0,
+ &phandle, intc_phandles);
g_free(nodename);
}
- create_fdt_socket_clint(fdt, memmap[SIFIVE_U_DEV_CLINT].base,
- memmap[SIFIVE_U_DEV_CLINT].size, 0,
- intc_phandles, ms->smp.cpus, false);
+ riscv_create_fdt_socket_clint(fdt, memmap[SIFIVE_U_DEV_CLINT].base,
+ memmap[SIFIVE_U_DEV_CLINT].size, 0,
+ intc_phandles, ms->smp.cpus, false);
nodename = g_strdup_printf("/soc/otp@%lx",
(long)memmap[SIFIVE_U_DEV_OTP].base);
@@ -209,12 +211,12 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
}
}
- create_fdt_plic(fdt, memmap[SIFIVE_U_DEV_PLIC].base,
- memmap[SIFIVE_U_DEV_PLIC].size,
- plic_phandle, SIFIVE_U_PLIC_INT_CELLS,
- SIFIVE_U_PLIC_ADDR_CELLS, cells,
- cells_length * sizeof(uint32_t),
- SIFIVE_U_PLIC_NUM_SOURCES - 1, false, 0);
+ riscv_create_fdt_plic(fdt, memmap[SIFIVE_U_DEV_PLIC].base,
+ memmap[SIFIVE_U_DEV_PLIC].size,
+ plic_phandle, SIFIVE_U_PLIC_INT_CELLS,
+ SIFIVE_U_PLIC_ADDR_CELLS, cells,
+ cells_length * sizeof(uint32_t),
+ SIFIVE_U_PLIC_NUM_SOURCES - 1, false, 0);
g_free(cells);
gpio_phandle = phandle++;
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 630b65f569..8d7e93807c 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -61,8 +61,10 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
uint32_t phandle = 1;
bool numa_enabled = riscv_numa_enabled(ms);
- fdt = ms->fdt = create_board_device_tree("ucbbar,spike-bare,qemu",
- "ucbbar,spike-bare-dev", &fdt_size);
+ fdt = ms->fdt = riscv_create_board_device_tree(
+ "ucbbar,spike-bare,qemu",
+ "ucbbar,spike-bare-dev",
+ &fdt_size);
qemu_fdt_add_subnode(fdt, "/htif");
qemu_fdt_setprop_string(fdt, "/htif", "compatible", "ucb,htif0");
@@ -71,7 +73,8 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
0x0, memmap[SPIKE_HTIF].base, 0x0, memmap[SPIKE_HTIF].size);
}
- fdt_create_cpu_socket_subnode(fdt, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
+ riscv_fdt_create_cpu_socket_subnode(fdt,
+ RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
for (socket = (riscv_socket_count(ms) - 1); socket >= 0; socket--) {
g_autofree uint32_t *intc_phandles = g_new0(uint32_t,
@@ -80,20 +83,21 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
riscv_socket_mem_offset(ms, socket);
uint64_t memsize = riscv_socket_mem_size(ms, socket);
- create_fdt_socket_cpus(fdt, (&s->soc[socket])->harts, socket,
- s->soc[socket].num_harts,
- s->soc[socket].hartid_base,
- &phandle, intc_phandles, numa_enabled,
- is_32_bit);
+ riscv_create_fdt_socket_cpus(fdt, (&s->soc[socket])->harts, socket,
+ s->soc[socket].num_harts,
+ s->soc[socket].hartid_base,
+ &phandle, intc_phandles, numa_enabled,
+ is_32_bit);
- create_fdt_socket_memory(fdt, memaddr, memsize, socket,
- riscv_numa_enabled(ms));
+ riscv_create_fdt_socket_memory(fdt, memaddr, memsize, socket,
+ riscv_numa_enabled(ms));
clint_addr = memmap[SPIKE_CLINT].base +
(memmap[SPIKE_CLINT].size * socket);
- create_fdt_socket_clint(fdt, clint_addr, memmap[SPIKE_CLINT].size,
- socket, intc_phandles,
- s->soc[socket].num_harts, numa_enabled);
+ riscv_create_fdt_socket_clint(fdt, clint_addr,
+ memmap[SPIKE_CLINT].size, socket,
+ intc_phandles, s->soc[socket].num_harts,
+ numa_enabled);
}
riscv_socket_fdt_write_distance_matrix(ms);
diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
index babce2b680..812051a11f 100644
--- a/hw/riscv/tt_atlantis.c
+++ b/hw/riscv/tt_atlantis.c
@@ -91,16 +91,17 @@ static void create_fdt_memory(TTAtlantisState *s)
size_hi = MACHINE(s)->ram_size - size_lo;
}
- create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_LO].base, size_lo,
- 0, false);
+ riscv_create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_LO].base,
+ size_lo, 0, false);
if (size_hi) {
/*
* The first part of the HI address is aliased at the LO address
* so do not include that as usable memory. Is there any way
* (or good reason) to describe that aliasing 2GB with DT?
*/
- create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_HI].base + size_lo,
- size_hi, 0, false);
+ riscv_create_fdt_socket_memory(fdt,
+ s->memmap[TT_ATL_DDR_HI].base + size_lo,
+ size_hi, 0, false);
}
}
@@ -225,11 +226,11 @@ static void create_fdt_cpu(TTAtlantisState *s, const MemMapEntry *memmap,
void *fdt = MACHINE(s)->fdt;
g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms->smp.cpus);
- fdt_create_cpu_socket_subnode(fdt, TT_ACLINT_TIMEBASE_FREQ);
+ riscv_fdt_create_cpu_socket_subnode(fdt, TT_ACLINT_TIMEBASE_FREQ);
- create_fdt_socket_cpus(fdt, s->soc.harts, 0, s->soc.num_harts,
- s->soc.hartid_base, &fdt_phandle, intc_phandles,
- false, false);
+ riscv_create_fdt_socket_cpus(fdt, s->soc.harts, 0, s->soc.num_harts,
+ s->soc.hartid_base, &fdt_phandle,
+ intc_phandles, false, false);
create_fdt_memory(s);
@@ -367,8 +368,9 @@ static void create_fdt(TTAtlantisState *s)
{
MachineState *ms = MACHINE(s);
- ms->fdt = create_board_device_tree("Tenstorrent Atlantis RISC-V Machine",
- "tenstorrent,atlantis", &s->fdt_size);
+ ms->fdt = riscv_create_board_device_tree(
+ "Tenstorrent Atlantis RISC-V Machine",
+ "tenstorrent,atlantis", &s->fdt_size);
qemu_fdt_add_subnode(ms->fdt, "/chosen");
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 329ccdb5a7..b796220fc2 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -360,12 +360,12 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
plic_phandles[socket] = (*phandle)++;
- create_fdt_plic(ms->fdt, plic_addr, s->memmap[VIRT_PLIC].size,
- plic_phandles[socket], FDT_PLIC_INT_CELLS,
- FDT_PLIC_ADDR_CELLS, plic_cells,
- cells_length * sizeof(uint32_t),
- VIRT_IRQCHIP_NUM_SOURCES - 1,
- numa_enabled, socket);
+ riscv_create_fdt_plic(ms->fdt, plic_addr, s->memmap[VIRT_PLIC].size,
+ plic_phandles[socket], FDT_PLIC_INT_CELLS,
+ FDT_PLIC_ADDR_CELLS, plic_cells,
+ cells_length * sizeof(uint32_t),
+ VIRT_IRQCHIP_NUM_SOURCES - 1,
+ numa_enabled, socket);
if (!socket) {
platform_bus_add_all_fdt_nodes(ms->fdt, plic_name,
@@ -601,7 +601,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
bool numa_enabled = riscv_numa_enabled(ms);
bool is_32_bit = riscv_is_32bit(&s->soc[0]);
- fdt_create_cpu_socket_subnode(ms->fdt,
+ riscv_fdt_create_cpu_socket_subnode(ms->fdt,
kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
@@ -615,14 +615,14 @@ static void create_fdt_sockets(RISCVVirtState *s,
phandle_pos -= s->soc[socket].num_harts;
- create_fdt_socket_cpus(ms->fdt, (&s->soc[socket])->harts, socket,
- s->soc[socket].num_harts,
- s->soc[socket].hartid_base,
- phandle, &intc_phandles[phandle_pos],
- numa_enabled, is_32_bit);
+ riscv_create_fdt_socket_cpus(ms->fdt, (&s->soc[socket])->harts, socket,
+ s->soc[socket].num_harts,
+ s->soc[socket].hartid_base,
+ phandle, &intc_phandles[phandle_pos],
+ numa_enabled, is_32_bit);
- create_fdt_socket_memory(ms->fdt, memaddr, memsize,
- socket, riscv_numa_enabled(ms));
+ riscv_create_fdt_socket_memory(ms->fdt, memaddr, memsize,
+ socket, riscv_numa_enabled(ms));
if (virt_aclint_allowed() && s->have_aclint) {
create_fdt_socket_aclint(s, socket,
@@ -631,10 +631,11 @@ static void create_fdt_sockets(RISCVVirtState *s,
hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
s->memmap[VIRT_CLINT].size * socket;
- create_fdt_socket_clint(ms->fdt, clintaddr,
- s->memmap[VIRT_CLINT].size,
- socket, &intc_phandles[phandle_pos],
- s->soc[socket].num_harts, numa_enabled);
+ riscv_create_fdt_socket_clint(ms->fdt, clintaddr,
+ s->memmap[VIRT_CLINT].size,
+ socket, &intc_phandles[phandle_pos],
+ s->soc[socket].num_harts,
+ numa_enabled);
}
}
@@ -1021,8 +1022,9 @@ static void create_fdt(RISCVVirtState *s)
uint8_t rng_seed[32];
g_autofree char *name = NULL;
- ms->fdt = create_board_device_tree("riscv-virtio,qemu", "riscv-virtio",
- &s->fdt_size);
+ ms->fdt = riscv_create_board_device_tree("riscv-virtio,qemu",
+ "riscv-virtio",
+ &s->fdt_size);
/*
* The "/soc/pci@..." node is needed for PCIE hotplugs
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 1729a6abc6..371971d79d 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -11,29 +11,31 @@
#include "target/riscv/cpu.h"
-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,
- int socket_id, bool numa_enabled);
-void create_fdt_clint(void *fdt, hwaddr addr, uint64_t size,
- uint32_t *intc_phandles, int num_harts);
-void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
- int socket_id, uint32_t *intc_phandles,
- int num_harts, bool numa_enabled);
-void fdt_create_cpu_socket_subnode(void *fdt, uint64_t timebase_frequency);
-void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
- int socket_id, int num_harts_socket,
- int socket_hartid_base, uint32_t *phandle,
- uint32_t *intc_phandles, bool numa_enabled,
- bool is_32_bit);
-void create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
- int cpu_id, int socket_id,
+void *riscv_create_board_device_tree(const char *model, const char *compatible,
+ int *fdt_size);
+void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
+ int socket_id, bool numa_enabled);
+void riscv_create_fdt_clint(void *fdt, hwaddr addr, uint64_t size,
+ uint32_t *intc_phandles, int num_harts);
+void riscv_create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
+ int socket_id, uint32_t *intc_phandles,
+ int num_harts, bool numa_enabled);
+void riscv_fdt_create_cpu_socket_subnode(void *fdt,
+ uint64_t timebase_frequency);
+void riscv_create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
+ int socket_id, int num_harts_socket,
int socket_hartid_base, uint32_t *phandle,
- uint32_t *intc_phandles);
-void create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
- uint32_t plic_phandle, uint32_t int_cells,
- uint32_t addr_cells, uint32_t *plic_cells,
- uint32_t cells_size, uint32_t ndev_sources,
- bool numa_enabled, int socket);
+ uint32_t *intc_phandles, bool numa_enabled,
+ bool is_32_bit);
+void riscv_create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
+ int cpu_id, int socket_id,
+ int socket_hartid_base,
+ uint32_t *phandle,
+ uint32_t *intc_phandles);
+void riscv_create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
+ uint32_t plic_phandle, uint32_t int_cells,
+ uint32_t addr_cells, uint32_t *plic_cells,
+ uint32_t cells_size, uint32_t ndev_sources,
+ bool numa_enabled, int socket);
void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 02/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
2026-08-28 20:39 ` [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-09-01 4:45 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 03/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
` (13 subsequent siblings)
15 siblings, 1 reply; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Add a common helper to create a cfi-flash compatible flash subnode.
This change only affects the existing 'virt' board for now but it will
be used by the future 'riscv-server-ref' board in the future.
No FDT changes intended.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
---
hw/riscv/fdt-common.c | 12 ++++++++++++
hw/riscv/virt.c | 18 ++----------------
include/hw/riscv/fdt-common.h | 1 +
3 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 3a8da03cfb..6fcc1ce21f 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -283,3 +283,15 @@ void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name)
qemu_fdt_setprop(fdt, pmu_name, "riscv,event-to-mhpmcounters",
fdt_event_ctr_map, sizeof(fdt_event_ctr_map));
}
+
+void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr flashsize)
+{
+ g_autofree char *name = g_strdup_printf("/flash@%" PRIx64, flashbase);
+
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, flashbase, 2, flashsize,
+ 2, flashbase + flashsize, 2, flashsize);
+ qemu_fdt_setprop_cell(fdt, name, "bank-width", 4);
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index b796220fc2..e48337dfd9 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -867,21 +867,6 @@ static void create_fdt_rtc(RISCVVirtState *s,
}
}
-static void create_fdt_flash(RISCVVirtState *s)
-{
- MachineState *ms = MACHINE(s);
- hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
- hwaddr flashbase = s->memmap[VIRT_FLASH].base;
- g_autofree char *name = g_strdup_printf("/flash@%" PRIx64, flashbase);
-
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible", "cfi-flash");
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, flashbase, 2, flashsize,
- 2, flashbase + flashsize, 2, flashsize);
- qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4);
-}
-
static void create_fdt_fw_cfg(RISCVVirtState *s)
{
MachineState *ms = MACHINE(s);
@@ -1043,7 +1028,8 @@ static void create_fdt(RISCVVirtState *s)
qemu_fdt_add_subnode(ms->fdt, "/aliases");
- create_fdt_flash(s);
+ riscv_create_fdt_flash(ms->fdt, s->memmap[VIRT_FLASH].base,
+ s->memmap[VIRT_FLASH].size / 2);
create_fdt_fw_cfg(s);
create_fdt_pmu(s);
}
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 371971d79d..b422da6aef 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -38,4 +38,5 @@ void riscv_create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
uint32_t cells_size, uint32_t ndev_sources,
bool numa_enabled, int socket);
void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name);
+void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr flashsize);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 03/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
2026-08-28 20:39 ` [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
2026-08-28 20:39 ` [PATCH v5 02/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-09-01 4:45 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 04/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
` (12 subsequent siblings)
15 siblings, 1 reply; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
The soon to be added riscv-server-ref board will declare a syscon FDT
similar to what the 'virt' board already does.
It won't have a 'sifive,test0' and 'sifive,test1' compat string though,
hence we'll add a flag to enable/disable these additional properties.
The FDT is slightly changed: the subnode is now named 'soc/syscon' instead
of 'soc/test' to be compatible with the latest device-tree docs.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
---
hw/riscv/fdt-common.c | 54 +++++++++++++++++++++++++++++++++++
hw/riscv/virt.c | 46 +++--------------------------
include/hw/riscv/fdt-common.h | 4 +++
3 files changed, 62 insertions(+), 42 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 6fcc1ce21f..eac5ca9322 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -295,3 +295,57 @@ void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr flashsize)
2, flashbase + flashsize, 2, flashsize);
qemu_fdt_setprop_cell(fdt, name, "bank-width", 4);
}
+
+/*
+ * @sifive_test_compat is used to create a FDT that declares
+ * compat with "sifive,test1" and "sifive,test0". This happens
+ * to be the case for the 'virt' machine that also creates a
+ * 'sifive_test' syscon device.
+ */
+void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,
+ hwaddr addr, hwaddr size,
+ uint32_t reboot, uint32_t poweroff,
+ bool sifive_test_compat)
+{
+ uint32_t syscon_phandle;
+ char *name;
+
+ name = g_strdup_printf("/soc/syscon@%"HWADDR_PRIx, addr);
+ qemu_fdt_add_subnode(fdt, name);
+
+ if (sifive_test_compat) {
+ static const char * const compat[3] = {
+ "sifive,test1", "sifive,test0", "syscon"
+ };
+
+ qemu_fdt_setprop_string_array(fdt, name, "compatible",
+ (char **)&compat, ARRAY_SIZE(compat));
+ } else {
+ qemu_fdt_setprop_string(fdt, name, "compatible", "syscon");
+ }
+
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, addr,
+ 2, size);
+
+ syscon_phandle = next_phandle ? (*next_phandle)++ : qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_setprop_cell(fdt, name, "phandle", syscon_phandle);
+
+ g_free(name);
+
+ name = g_strdup_printf("/reboot");
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
+ qemu_fdt_setprop_cell(fdt, name, "regmap", syscon_phandle);
+ qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
+ qemu_fdt_setprop_cell(fdt, name, "value", reboot);
+ g_free(name);
+
+ name = g_strdup_printf("/poweroff");
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
+ qemu_fdt_setprop_cell(fdt, name, "regmap", syscon_phandle);
+ qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
+ qemu_fdt_setprop_cell(fdt, name, "value", poweroff);
+ g_free(name);
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index e48337dfd9..ab6c53c78a 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -768,47 +768,6 @@ static void create_fdt_pcie(RISCVVirtState *s,
create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
}
-static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle)
-{
- char *name;
- uint32_t test_phandle;
- MachineState *ms = MACHINE(s);
-
- test_phandle = (*phandle)++;
- name = g_strdup_printf("/soc/test@%"HWADDR_PRIx,
- s->memmap[VIRT_TEST].base);
- qemu_fdt_add_subnode(ms->fdt, name);
- {
- static const char * const compat[3] = {
- "sifive,test1", "sifive,test0", "syscon"
- };
- qemu_fdt_setprop_string_array(ms->fdt, name, "compatible",
- (char **)&compat, ARRAY_SIZE(compat));
- }
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, s->memmap[VIRT_TEST].base,
- 2, s->memmap[VIRT_TEST].size);
- qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle);
- test_phandle = qemu_fdt_get_phandle(ms->fdt, name);
- g_free(name);
-
- name = g_strdup_printf("/reboot");
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot");
- qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle);
- qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0);
- qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_RESET);
- g_free(name);
-
- name = g_strdup_printf("/poweroff");
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff");
- qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle);
- qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0);
- qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_PASS);
- g_free(name);
-}
-
static void create_fdt_uart(RISCVVirtState *s,
uint32_t irq_mmio_phandle, int memId, int irqNo)
{
@@ -994,7 +953,10 @@ static void finalize_fdt(RISCVVirtState *s)
create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
iommu_sys_phandle);
- create_fdt_reset(s, &phandle);
+ riscv_create_fdt_syscon(MACHINE(s)->fdt, &phandle,
+ s->memmap[VIRT_TEST].base,
+ s->memmap[VIRT_TEST].size,
+ FINISHER_RESET, FINISHER_PASS, true);
create_fdt_uarts(s, irq_mmio_phandle);
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index b422da6aef..e377682b32 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -39,4 +39,8 @@ void riscv_create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
bool numa_enabled, int socket);
void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name);
void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr flashsize);
+void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,
+ hwaddr addr, hwaddr size,
+ uint32_t reboot, uint32_t poweroff,
+ bool sifive_test_compat);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 04/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (2 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 03/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-09-01 4:47 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
` (11 subsequent siblings)
15 siblings, 1 reply; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Both the 'virt' board and the future 'riscv-server-ref' boards uses an
iommu-sys device that is declared in the DT. Create a helper to
encapsulate the logic and avoid copy/pasting stuff between boards.
The helper will return the iommu phandle value instead of returning void
and writing the used phandle in an extra argument.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
---
hw/riscv/fdt-common.c | 35 ++++++++++++++++++++++++
hw/riscv/virt.c | 50 ++++++-----------------------------
include/hw/riscv/fdt-common.h | 5 ++++
3 files changed, 48 insertions(+), 42 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index eac5ca9322..88589330fb 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -13,6 +13,8 @@
#include "hw/core/boards.h"
#include "hw/riscv/fdt-common.h"
#include "target/riscv/cpu_bits.h"
+#include "hw/riscv/riscv-iommu-bits.h"
+#include "hw/riscv/iommu.h"
void *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size)
@@ -349,3 +351,36 @@ void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,
qemu_fdt_setprop_cell(fdt, name, "value", poweroff);
g_free(name);
}
+
+uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
+ uint32_t *next_phandle,
+ uint32_t irq_chip,
+ uint32_t msi_phandle,
+ uint32_t iommu_sys_irq)
+{
+ const char comp[] = "riscv,iommu";
+ g_autofree char *iommu_node = NULL;
+ uint32_t iommu_phandle;
+
+ iommu_node = g_strdup_printf("/soc/iommu@%"HWADDR_PRIx, addr);
+ qemu_fdt_add_subnode(fdt, iommu_node);
+
+ qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp));
+ qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
+
+ iommu_phandle = next_phandle ? (*next_phandle)++ : qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle);
+
+ qemu_fdt_setprop_sized_cells(fdt, iommu_node, "reg", 2, addr, 2, size);
+ qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent", irq_chip);
+
+ qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts",
+ iommu_sys_irq + RISCV_IOMMU_INTR_CQ, FDT_IRQ_TYPE_EDGE_LOW,
+ iommu_sys_irq + RISCV_IOMMU_INTR_FQ, FDT_IRQ_TYPE_EDGE_LOW,
+ iommu_sys_irq + RISCV_IOMMU_INTR_PM, FDT_IRQ_TYPE_EDGE_LOW,
+ iommu_sys_irq + RISCV_IOMMU_INTR_PQ, FDT_IRQ_TYPE_EDGE_LOW);
+
+ qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent", msi_phandle);
+
+ return iommu_phandle;
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index ab6c53c78a..8a165f4d9e 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -869,46 +869,6 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf)
bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf);
}
-static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t irq_chip,
- uint32_t msi_phandle,
- uint32_t *iommu_sys_phandle)
-{
- const char comp[] = "riscv,iommu";
- void *fdt = MACHINE(s)->fdt;
- uint32_t iommu_phandle;
- g_autofree char *iommu_node = NULL;
- hwaddr addr = s->memmap[VIRT_IOMMU_SYS].base;
- hwaddr size = s->memmap[VIRT_IOMMU_SYS].size;
- uint32_t iommu_irq_map[RISCV_IOMMU_INTR_COUNT] = {
- IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_CQ,
- IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_FQ,
- IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PM,
- IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PQ,
- };
-
- iommu_node = g_strdup_printf("/soc/iommu@%x",
- (unsigned int) s->memmap[VIRT_IOMMU_SYS].base);
- iommu_phandle = qemu_fdt_alloc_phandle(fdt);
- qemu_fdt_add_subnode(fdt, iommu_node);
-
- qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp));
- qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
- qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle);
-
- qemu_fdt_setprop_sized_cells(fdt, iommu_node, "reg", 2, addr, 2, size);
- qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent", irq_chip);
-
- qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts",
- iommu_irq_map[0], FDT_IRQ_TYPE_EDGE_LOW,
- iommu_irq_map[1], FDT_IRQ_TYPE_EDGE_LOW,
- iommu_irq_map[2], FDT_IRQ_TYPE_EDGE_LOW,
- iommu_irq_map[3], FDT_IRQ_TYPE_EDGE_LOW);
-
- qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent", msi_phandle);
-
- *iommu_sys_phandle = iommu_phandle;
-}
-
static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf)
{
const char comp[] = "riscv,pci-iommu";
@@ -947,8 +907,14 @@ static void finalize_fdt(RISCVVirtState *s)
create_fdt_virtio(s, irq_virtio_phandle);
if (virt_is_iommu_sys_enabled(s)) {
- create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle,
- &iommu_sys_phandle);
+ iommu_sys_phandle =
+ riscv_create_fdt_riscv_iommu_sys(MACHINE(s)->fdt,
+ s->memmap[VIRT_IOMMU_SYS].base,
+ s->memmap[VIRT_IOMMU_SYS].size,
+ &phandle,
+ irq_mmio_phandle,
+ msi_pcie_phandle,
+ IOMMU_SYS_IRQ);
}
create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
iommu_sys_phandle);
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index e377682b32..65711468b8 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -43,4 +43,9 @@ void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,
hwaddr addr, hwaddr size,
uint32_t reboot, uint32_t poweroff,
bool sifive_test_compat);
+uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
+ uint32_t *next_phandle,
+ uint32_t irq_chip,
+ uint32_t msi_phandle,
+ uint32_t iommu_sys_irq);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (3 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 04/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:08 ` Chao Liu via qemu development
2026-09-01 4:49 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
` (10 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
The pcie FDT is quite tedious but can be parametrized into a helper.
This is going to benefit only the 'virt' board for now but it will be
used by the 'riscv-server-ref' board in the near future too.
Some other changes made:
- FDT related macros are moved to fdt-common.h. Only a couple are being
used by the helper ATM but more will be added in the next patches;
- an RISCVAIAType enum is created. There are several FDTs that depends
on the active AIA type being used, and we want a way to represent the
different AIA modes that doesn't re-use the 'virt' specific VIRT_AIA_*
macros. The enum vals are equivalent by design - we want "s->aia_type"
to be used by 'virt' when calling the fdt helpers, and other boards
will use "AIA_*" macros in their code.
No FDT changes made.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 111 ++++++++++++++++++++++++++++++++++
hw/riscv/virt.c | 111 +++-------------------------------
include/hw/riscv/fdt-common.h | 29 +++++++++
include/hw/riscv/virt.h | 15 -----
4 files changed, 149 insertions(+), 117 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 88589330fb..38813b6aa7 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -15,6 +15,8 @@
#include "target/riscv/cpu_bits.h"
#include "hw/riscv/riscv-iommu-bits.h"
#include "hw/riscv/iommu.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
void *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size)
@@ -384,3 +386,112 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
return iommu_phandle;
}
+
+static void create_pcie_irq_map(void *fdt, char *nodename,
+ uint32_t irqchip_phandle,
+ RISCVAIAType aia_type, uint32_t pcie_irq)
+{
+ int pin, dev;
+ uint32_t irq_map_stride = 0;
+ uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
+ FDT_MAX_INT_MAP_WIDTH] = {};
+ uint32_t *irq_map = full_irq_map;
+
+ /*
+ * This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+ for (dev = 0; dev < PCI_NUM_PINS; dev++) {
+ int devfn = dev * 0x8;
+
+ for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+ int irq_nr = pcie_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
+ int i = 0;
+
+ /* Fill PCI address cells */
+ irq_map[i] = cpu_to_be32(devfn << 8);
+ i += FDT_PCI_ADDR_CELLS;
+
+ /* Fill PCI Interrupt cells */
+ irq_map[i] = cpu_to_be32(pin + 1);
+ i += FDT_PCI_INT_CELLS;
+
+ /* Fill interrupt controller phandle and cells */
+ irq_map[i++] = cpu_to_be32(irqchip_phandle);
+ irq_map[i++] = cpu_to_be32(irq_nr);
+
+ if (aia_type != AIA_TYPE_NONE) {
+ irq_map[i++] = cpu_to_be32(0x4);
+ }
+
+ if (!irq_map_stride) {
+ irq_map_stride = i;
+ }
+ irq_map += irq_map_stride;
+ }
+ }
+
+ qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
+ PCI_NUM_PINS * PCI_NUM_PINS *
+ irq_map_stride * sizeof(uint32_t));
+
+ qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+/*
+ * NOTE: this function uses a "/soc/pci@..." FDT subnode that
+ * should be created beforehand.
+ */
+void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
+ const MemMapEntry *pcie_ecam,
+ const MemMapEntry *pcie_pio,
+ 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)
+{
+ g_autofree char *name = NULL;
+
+ name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, pcie_ecam->base);
+ qemu_fdt_setprop_cell(fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS);
+ qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", FDT_PCI_INT_CELLS);
+ qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0x2);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "pci-host-ecam-generic");
+ qemu_fdt_setprop_string(fdt, name, "device_type", "pci");
+ qemu_fdt_setprop_cell(fdt, name, "linux,pci-domain", 0);
+
+ qemu_fdt_setprop_cells(fdt, name, "bus-range", 0,
+ pcie_ecam->size / PCIE_MMCFG_SIZE_MIN - 1);
+ qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
+
+ if (aia_type == AIA_TYPE_APLIC_IMSIC) {
+ qemu_fdt_setprop_cell(fdt, name, "msi-parent", msi_pcie_phandle);
+ }
+
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2,
+ pcie_ecam->base, 2, pcie_ecam->size);
+
+ qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
+ 1, FDT_PCI_RANGE_IOPORT, 2, 0,
+ 2, pcie_pio->base, 2, pcie_pio->size,
+ 1, FDT_PCI_RANGE_MMIO,
+ 2, pcie_mmio->base,
+ 2, pcie_mmio->base, 2, pcie_mmio->size,
+ 1, FDT_PCI_RANGE_MMIO_64BIT,
+ 2, high_pcie->base,
+ 2, high_pcie->base, 2, high_pcie->size);
+
+ if (has_iommu_sys) {
+ qemu_fdt_setprop_cells(fdt, name, "iommu-map",
+ 0, iommu_sys_phandle, 0, 0x10000);
+ }
+
+ create_pcie_irq_map(fdt, name, irq_pcie_phandle, aia_type, pcie_irq);
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 8a165f4d9e..a28e6d200a 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -180,61 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
sysmem);
}
-static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
- uint32_t irqchip_phandle)
-{
- int pin, dev;
- uint32_t irq_map_stride = 0;
- uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
- FDT_MAX_INT_MAP_WIDTH] = {};
- uint32_t *irq_map = full_irq_map;
-
- /*
- * This code creates a standard swizzle of interrupts such that
- * each device's first interrupt is based on it's PCI_SLOT number.
- * (See pci_swizzle_map_irq_fn())
- *
- * We only need one entry per interrupt in the table (not one per
- * possible slot) seeing the interrupt-map-mask will allow the table
- * to wrap to any number of devices.
- */
- for (dev = 0; dev < PCI_NUM_PINS; dev++) {
- int devfn = dev * 0x8;
-
- for (pin = 0; pin < PCI_NUM_PINS; pin++) {
- int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
- int i = 0;
-
- /* Fill PCI address cells */
- irq_map[i] = cpu_to_be32(devfn << 8);
- i += FDT_PCI_ADDR_CELLS;
-
- /* Fill PCI Interrupt cells */
- irq_map[i] = cpu_to_be32(pin + 1);
- i += FDT_PCI_INT_CELLS;
-
- /* Fill interrupt controller phandle and cells */
- irq_map[i++] = cpu_to_be32(irqchip_phandle);
- irq_map[i++] = cpu_to_be32(irq_nr);
- if (s->aia_type != VIRT_AIA_TYPE_NONE) {
- irq_map[i++] = cpu_to_be32(0x4);
- }
-
- if (!irq_map_stride) {
- irq_map_stride = i;
- }
- irq_map += irq_map_stride;
- }
- }
-
- qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
- PCI_NUM_PINS * PCI_NUM_PINS *
- irq_map_stride * sizeof(uint32_t));
-
- qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
- 0x1800, 0, 0, 0x7);
-}
-
static void create_fdt_socket_aclint(RISCVVirtState *s,
int socket,
uint32_t *intc_phandles)
@@ -723,51 +668,6 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
}
}
-static void create_fdt_pcie(RISCVVirtState *s,
- uint32_t irq_pcie_phandle,
- uint32_t msi_pcie_phandle,
- uint32_t iommu_sys_phandle)
-{
- g_autofree char *name = NULL;
- MachineState *ms = MACHINE(s);
-
- name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
- s->memmap[VIRT_PCIE_ECAM].base);
- qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells",
- FDT_PCI_ADDR_CELLS);
- qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells",
- FDT_PCI_INT_CELLS);
- qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible",
- "pci-host-ecam-generic");
- qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci");
- qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0);
- qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0,
- s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
- qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0);
- if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
- qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle);
- }
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2,
- s->memmap[VIRT_PCIE_ECAM].base, 2, s->memmap[VIRT_PCIE_ECAM].size);
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges",
- 1, FDT_PCI_RANGE_IOPORT, 2, 0,
- 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size,
- 1, FDT_PCI_RANGE_MMIO,
- 2, s->memmap[VIRT_PCIE_MMIO].base,
- 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s->memmap[VIRT_PCIE_MMIO].size,
- 1, FDT_PCI_RANGE_MMIO_64BIT,
- 2, virt_high_pcie_memmap.base,
- 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
-
- if (virt_is_iommu_sys_enabled(s)) {
- qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
- 0, iommu_sys_phandle, 0, 0x10000);
- }
-
- create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
-}
-
static void create_fdt_uart(RISCVVirtState *s,
uint32_t irq_mmio_phandle, int memId, int irqNo)
{
@@ -916,8 +816,15 @@ static void finalize_fdt(RISCVVirtState *s)
msi_pcie_phandle,
IOMMU_SYS_IRQ);
}
- create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
- iommu_sys_phandle);
+
+ riscv_create_fdt_pcie(MACHINE(s)->fdt, s->aia_type,
+ virt_is_iommu_sys_enabled(s),
+ &s->memmap[VIRT_PCIE_ECAM],
+ &s->memmap[VIRT_PCIE_PIO],
+ &s->memmap[VIRT_PCIE_MMIO],
+ &virt_high_pcie_memmap,
+ irq_pcie_phandle, msi_pcie_phandle,
+ iommu_sys_phandle, PCIE_IRQ);
riscv_create_fdt_syscon(MACHINE(s)->fdt, &phandle,
s->memmap[VIRT_TEST].base,
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 65711468b8..3750230865 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -11,6 +11,27 @@
#include "target/riscv/cpu.h"
+#define FDT_PCI_ADDR_CELLS 3
+#define FDT_PCI_INT_CELLS 1
+#define FDT_PLIC_ADDR_CELLS 0
+#define FDT_PLIC_INT_CELLS 1
+#define FDT_APLIC_INT_CELLS 2
+#define FDT_APLIC_ADDR_CELLS 0
+#define FDT_IMSIC_INT_CELLS 0
+#define FDT_MAX_INT_CELLS 2
+#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+ 1 + FDT_MAX_INT_CELLS)
+#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+ 1 + FDT_PLIC_INT_CELLS)
+#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
+ 1 + FDT_APLIC_INT_CELLS)
+
+typedef enum RISCVAIAType {
+ AIA_TYPE_NONE = 0,
+ AIA_TYPE_APLIC,
+ AIA_TYPE_APLIC_IMSIC,
+} RISCVAIAType;
+
void *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size);
void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
@@ -48,4 +69,12 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
uint32_t irq_chip,
uint32_t msi_phandle,
uint32_t iommu_sys_irq);
+void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
+ const MemMapEntry *pcie_ecam,
+ const MemMapEntry *pcie_pio,
+ 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);
#endif
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 7c862b0da2..e516898f9a 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -121,21 +121,6 @@ enum {
#define VIRT_PLIC_SIZE(__num_context) \
(VIRT_PLIC_CONTEXT_BASE + (__num_context) * VIRT_PLIC_CONTEXT_STRIDE)
-#define FDT_PCI_ADDR_CELLS 3
-#define FDT_PCI_INT_CELLS 1
-#define FDT_PLIC_ADDR_CELLS 0
-#define FDT_PLIC_INT_CELLS 1
-#define FDT_APLIC_INT_CELLS 2
-#define FDT_APLIC_ADDR_CELLS 0
-#define FDT_IMSIC_INT_CELLS 0
-#define FDT_MAX_INT_CELLS 2
-#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
- 1 + FDT_MAX_INT_CELLS)
-#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
- 1 + FDT_PLIC_INT_CELLS)
-#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
- 1 + FDT_APLIC_INT_CELLS)
-
bool virt_is_acpi_enabled(RISCVVirtState *s);
bool virt_is_iommu_sys_enabled(RISCVVirtState *s);
void virt_acpi_setup(RISCVVirtState *vms);
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (4 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:08 ` Chao Liu via qemu development
2026-09-01 4:51 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
` (9 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
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 <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 98 ++++++++++++++++++++++++++++++
hw/riscv/virt.c | 108 +++++-----------------------------
include/hw/riscv/fdt-common.h | 21 +++++++
3 files changed, 133 insertions(+), 94 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 38813b6aa7..ae24ad0011 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 *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size)
@@ -495,3 +497,99 @@ void riscv_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;
+ g_autofree uint32_t *imsic_cells = NULL;
+ g_autofree uint32_t *imsic_regs = NULL;
+ uint32_t imsic_max_hart_per_socket = 0;
+ static const char * const imsic_compat[2] = {
+ "qemu,imsics", "riscv,imsics"
+ };
+
+ imsic_cells = g_new0(uint32_t, props->smp_cpus * 2);
+ imsic_regs = g_new0(uint32_t, props->socket_count * 4);
+
+ for (int 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);
+ }
+
+ for (int socket = 0; socket < props->socket_count; socket++) {
+ hwaddr imsic_addr = base_addr + socket * props->imsic_group_max_size;
+ uint32_t imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) *
+ soc[socket].num_harts;
+
+ imsic_regs[socket * 4 + 0] = cpu_to_be32(imsic_addr >> 32);
+ 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 riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
+ uint32_t *next_phandle, uint32_t *intc_phandles,
+ uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
+{
+ if (next_phandle) {
+ *msi_m_phandle = (*next_phandle)++;
+ *msi_s_phandle = (*next_phandle)++;
+ } else {
+ *msi_m_phandle = qemu_fdt_alloc_phandle(fdt);
+ *msi_s_phandle = qemu_fdt_alloc_phandle(fdt);
+ }
+
+ 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 a28e6d200a..468ec90696 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -320,98 +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_size;
- hwaddr imsic_addr;
- 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] = cpu_to_be32(imsic_addr >> 32);
- 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)
{
@@ -585,8 +493,20 @@ static void create_fdt_sockets(RISCVVirtState *s,
}
if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
- create_fdt_imsic(s, phandle, intc_phandles,
- &msi_m_phandle, &msi_s_phandle);
+ 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
+ };
+
+ riscv_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 3750230865..182c03d8ce 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,22 @@ 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 *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size);
void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
@@ -77,4 +95,7 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
uint32_t irq_pcie_phandle,
uint32_t msi_pcie_phandle,
uint32_t iommu_sys_phandle, uint32_t pcie_irq);
+void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
+ uint32_t *next_phandle, uint32_t *intc_phandles,
+ uint32_t *msi_m_phandle, uint32_t *msi_s_phandle);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (5 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:09 ` Chao Liu via qemu development
2026-09-01 5:14 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename Daniel Henrique Barboza
` (8 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Similar to what we did with 'imsic' in the previous patch, including
creating a helper struct to encapsulate the extra arguments required to
create the FDT.
TODO: I believe the tt-atlantis board can use this same helper too. We
just need to verify how to map the phandles used by it and what the
helper is using (which was inherited by the 'virt' board).
No FDT changes intended.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 109 ++++++++++++++++++++++++++
hw/riscv/virt.c | 139 ++++++----------------------------
include/hw/riscv/fdt-common.h | 19 +++++
3 files changed, 151 insertions(+), 116 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index ae24ad0011..d815c5adff 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -11,6 +11,7 @@
#include "qemu/error-report.h"
#include "system/device_tree.h"
#include "hw/core/boards.h"
+#include "hw/core/sysbus-fdt.h"
#include "hw/riscv/fdt-common.h"
#include "target/riscv/cpu_bits.h"
#include "hw/riscv/riscv-iommu-bits.h"
@@ -593,3 +594,111 @@ void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
imsic_num_bits(props->aia_guests + 1));
}
+
+/* Caller must free string after use */
+static char *fdt_get_aplic_nodename(hwaddr aplic_addr)
+{
+ return g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIx,
+ aplic_addr);
+}
+
+static void create_fdt_one_aplic(void *fdt, APLICFdtProps *props,
+ hwaddr aplic_addr, uint32_t aplic_size,
+ uint32_t msi_phandle,
+ uint32_t *intc_phandles,
+ uint32_t aplic_phandle,
+ uint32_t aplic_child_phandle,
+ bool m_mode)
+{
+ g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
+ g_autofree uint32_t *aplic_cells = g_new0(uint32_t, props->num_harts * 2);
+ static const char * const aplic_compat[2] = {
+ "qemu,aplic", "riscv,aplic"
+ };
+
+ for (int cpu = 0; cpu < props->num_harts; cpu++) {
+ aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+ aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
+ }
+
+ qemu_fdt_add_subnode(fdt, aplic_name);
+ qemu_fdt_setprop_string_array(fdt, aplic_name, "compatible",
+ (char **)&aplic_compat,
+ ARRAY_SIZE(aplic_compat));
+ qemu_fdt_setprop_cell(fdt, aplic_name, "#address-cells",
+ FDT_APLIC_ADDR_CELLS);
+ qemu_fdt_setprop_cell(fdt, aplic_name,
+ "#interrupt-cells", FDT_APLIC_INT_CELLS);
+ qemu_fdt_setprop(fdt, aplic_name, "interrupt-controller", NULL, 0);
+
+ if (props->aia_type == AIA_TYPE_APLIC) {
+ qemu_fdt_setprop(fdt, aplic_name, "interrupts-extended",
+ aplic_cells, props->num_harts * sizeof(uint32_t) * 2);
+ } else {
+ qemu_fdt_setprop_cell(fdt, aplic_name, "msi-parent", msi_phandle);
+ }
+
+ qemu_fdt_setprop_sized_cells(fdt, aplic_name, "reg",
+ 2, aplic_addr, 2, aplic_size);
+ qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,num-sources",
+ props->irqchip_num_sources);
+
+ if (aplic_child_phandle) {
+ qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,children",
+ aplic_child_phandle);
+ qemu_fdt_setprop_cells(fdt, aplic_name, "riscv,delegation",
+ aplic_child_phandle, 0x1,
+ props->irqchip_num_sources);
+ }
+
+ if (props->numa_enabled) {
+ qemu_fdt_setprop_cell(fdt, aplic_name, "numa-node-id", props->socket);
+ }
+
+ qemu_fdt_setprop_cell(fdt, aplic_name, "phandle", aplic_phandle);
+}
+
+void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
+ uint32_t msi_m_phandle,
+ uint32_t msi_s_phandle,
+ uint32_t *next_phandle,
+ uint32_t *intc_phandles,
+ uint32_t *aplic_phandles)
+{
+ uint32_t aplic_m_phandle, aplic_s_phandle;
+ hwaddr aplic_addr;
+
+ if (next_phandle) {
+ aplic_m_phandle = (*next_phandle)++;
+ aplic_s_phandle = (*next_phandle)++;
+ } else {
+ aplic_m_phandle = qemu_fdt_alloc_phandle(fdt);
+ aplic_s_phandle = qemu_fdt_alloc_phandle(fdt);
+ }
+
+ if (props->aplic_m) {
+ /* M-level APLIC node */
+ aplic_addr = props->aplic_m->base + (props->aplic_m->size * props->socket);
+ create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_m->size,
+ msi_m_phandle, intc_phandles,
+ aplic_m_phandle, aplic_s_phandle,
+ true);
+ }
+
+ /* S-level APLIC node */
+ aplic_addr = props->aplic_s->base + (props->aplic_s->size * props->socket);
+ create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_s->size,
+ msi_s_phandle, intc_phandles,
+ aplic_s_phandle, 0,
+ false);
+
+ if (!props->socket && props->platform_bus_irq) {
+ g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
+ platform_bus_add_all_fdt_nodes(fdt, aplic_name,
+ props->platform_bus->base,
+ props->platform_bus->size,
+ props->platform_bus_irq);
+ }
+
+ aplic_phandles[props->socket] = aplic_s_phandle;
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 468ec90696..a6ec9def16 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -320,113 +320,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
}
}
-/* Caller must free string after use */
-static char *fdt_get_aplic_nodename(unsigned long aplic_addr)
-{
- return g_strdup_printf("/soc/interrupt-controller@%lx", aplic_addr);
-}
-
-static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
- unsigned long aplic_addr, uint32_t aplic_size,
- uint32_t msi_phandle,
- uint32_t *intc_phandles,
- uint32_t aplic_phandle,
- uint32_t aplic_child_phandle,
- bool m_mode, int num_harts)
-{
- int cpu;
- g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
- g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts * 2);
- MachineState *ms = MACHINE(s);
- static const char * const aplic_compat[2] = {
- "qemu,aplic", "riscv,aplic"
- };
-
- for (cpu = 0; cpu < num_harts; cpu++) {
- aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
- aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
- }
-
- qemu_fdt_add_subnode(ms->fdt, aplic_name);
- qemu_fdt_setprop_string_array(ms->fdt, aplic_name, "compatible",
- (char **)&aplic_compat,
- ARRAY_SIZE(aplic_compat));
- qemu_fdt_setprop_cell(ms->fdt, aplic_name, "#address-cells",
- FDT_APLIC_ADDR_CELLS);
- qemu_fdt_setprop_cell(ms->fdt, aplic_name,
- "#interrupt-cells", FDT_APLIC_INT_CELLS);
- qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
-
- if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
- qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
- aplic_cells, num_harts * sizeof(uint32_t) * 2);
- } else {
- qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_phandle);
- }
-
- qemu_fdt_setprop_sized_cells(ms->fdt, aplic_name, "reg",
- 2, aplic_addr, 2, aplic_size);
- qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
- VIRT_IRQCHIP_NUM_SOURCES);
-
- if (aplic_child_phandle) {
- qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
- aplic_child_phandle);
- qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegation",
- aplic_child_phandle, 0x1,
- VIRT_IRQCHIP_NUM_SOURCES);
- }
-
- riscv_socket_fdt_write_id(ms, aplic_name, socket);
- qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_phandle);
-}
-
-static void create_fdt_socket_aplic(RISCVVirtState *s,
- int socket,
- uint32_t msi_m_phandle,
- uint32_t msi_s_phandle,
- uint32_t *phandle,
- uint32_t *intc_phandles,
- uint32_t *aplic_phandles,
- int num_harts)
-{
- unsigned long aplic_addr;
- MachineState *ms = MACHINE(s);
- uint32_t aplic_m_phandle, aplic_s_phandle;
-
- aplic_m_phandle = (*phandle)++;
- aplic_s_phandle = (*phandle)++;
-
- if (!kvm_enabled()) {
- /* M-level APLIC node */
- aplic_addr = s->memmap[VIRT_APLIC_M].base +
- (s->memmap[VIRT_APLIC_M].size * socket);
- create_fdt_one_aplic(s, socket, aplic_addr,
- s->memmap[VIRT_APLIC_M].size,
- msi_m_phandle, intc_phandles,
- aplic_m_phandle, aplic_s_phandle,
- true, num_harts);
- }
-
- /* S-level APLIC node */
- aplic_addr = s->memmap[VIRT_APLIC_S].base +
- (s->memmap[VIRT_APLIC_S].size * socket);
- create_fdt_one_aplic(s, socket, aplic_addr, s->memmap[VIRT_APLIC_S].size,
- msi_s_phandle, intc_phandles,
- aplic_s_phandle, 0,
- false, num_harts);
-
- if (!socket) {
- g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
- platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
- s->memmap[VIRT_PLATFORM_BUS].base,
- s->memmap[VIRT_PLATFORM_BUS].size,
- VIRT_PLATFORM_BUS_IRQ);
- }
-
- aplic_phandles[socket] = aplic_s_phandle;
-}
-
static void create_fdt_pmu(RISCVVirtState *s)
{
g_autofree char *pmu_name = g_strdup_printf("/pmu");
@@ -453,6 +346,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
int socket_count = riscv_socket_count(ms);
bool numa_enabled = riscv_numa_enabled(ms);
bool is_32_bit = riscv_is_32bit(&s->soc[0]);
+ APLICFdtProps aplic_props;
riscv_fdt_create_cpu_socket_subnode(ms->fdt,
kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
@@ -510,15 +404,26 @@ static void create_fdt_sockets(RISCVVirtState *s,
*msi_pcie_phandle = msi_s_phandle;
}
+ if (s->aia_type != VIRT_AIA_TYPE_NONE) {
+ aplic_props.aplic_m = !kvm_enabled() ? &s->memmap[VIRT_APLIC_M] : NULL;
+ aplic_props.aplic_s = &s->memmap[VIRT_APLIC_S];
+ aplic_props.platform_bus = &s->memmap[VIRT_PLATFORM_BUS];
+ aplic_props.platform_bus_irq = VIRT_PLATFORM_BUS_IRQ;
+ aplic_props.socket = 0;
+ aplic_props.num_harts = ms->smp.cpus;
+ aplic_props.numa_enabled = numa_enabled;
+ aplic_props.irqchip_num_sources = VIRT_IRQCHIP_NUM_SOURCES;
+ aplic_props.aia_type = s->aia_type;
+ }
+
/*
* With KVM AIA aplic-imsic, using an irqchip without split
* mode, we'll use only one APLIC instance.
*/
if (!virt_use_emulated_aplic(s->aia_type)) {
- create_fdt_socket_aplic(s, 0,
- msi_m_phandle, msi_s_phandle, phandle,
- &intc_phandles[0], xplic_phandles,
- ms->smp.cpus);
+ riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
+ msi_m_phandle, msi_s_phandle, phandle,
+ &intc_phandles[0], xplic_phandles);
*irq_mmio_phandle = xplic_phandles[0];
*irq_virtio_phandle = xplic_phandles[0];
@@ -533,11 +438,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
&intc_phandles[phandle_pos],
xplic_phandles);
} else {
- create_fdt_socket_aplic(s, socket,
- msi_m_phandle, msi_s_phandle, phandle,
- &intc_phandles[phandle_pos],
- xplic_phandles,
- s->soc[socket].num_harts);
+ aplic_props.socket = socket;
+ aplic_props.num_harts = s->soc[socket].num_harts;
+ riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
+ msi_m_phandle, msi_s_phandle,
+ phandle,
+ &intc_phandles[phandle_pos],
+ xplic_phandles);
}
}
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 182c03d8ce..8207cfee7b 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -12,6 +12,7 @@
#include "target/riscv/cpu.h"
#include "hw/core/boards.h"
#include "hw/riscv/riscv_hart.h"
+#include "exec/hwaddr.h"
#define FDT_PCI_ADDR_CELLS 3
#define FDT_PCI_INT_CELLS 1
@@ -50,6 +51,18 @@ typedef struct IMSICFdtProps {
int aia_guests;
} IMSICFdtProps;
+typedef struct APLICFdtProps {
+ const MemMapEntry *aplic_m;
+ const MemMapEntry *aplic_s;
+ const MemMapEntry *platform_bus;
+ int platform_bus_irq;
+ int socket;
+ int num_harts;
+ bool numa_enabled;
+ int irqchip_num_sources;
+ int aia_type;
+} APLICFdtProps;
+
void *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size);
void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
@@ -98,4 +111,10 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
uint32_t *next_phandle, uint32_t *intc_phandles,
uint32_t *msi_m_phandle, uint32_t *msi_s_phandle);
+void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
+ uint32_t msi_m_phandle,
+ uint32_t msi_s_phandle,
+ uint32_t *next_phandle,
+ uint32_t *intc_phandles,
+ uint32_t *aplic_phandles);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (6 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:10 ` Chao Liu
2026-09-01 5:15 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
` (7 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, qemu-stable, Palmer Dabbelt
Running 'dtc' to generate a readable fdt for the virt machine produce
warnings:
$ dtc -I dtb -O dts virt.dtb > virt.dts
<stdout>: Warning (simple_bus_reg): /soc/mtimer@2000000: simple-bus unit address format error, expected "2007ff8"
<stdout>: Warning (simple_bus_reg): /soc/mtimer@2008000: simple-bus unit address format error, expected "200fff8"
This happens because the 'reg' field does not match the address in the
nodename. The right fix, pointed out by Chao in [1], is to make the
nodename match the reg value:
"In the current QEMU implement, `addr` is the MTIMECMP base address,
while the MTIME register is located at addr + RISCV_ACLINT_DEFAULT_MTIME."
In other words, the 'reg' value is correct but the nodename isn't.
We'll make the fix now, allowing the next patch to move the fixed version
of aclint FDT to fdt-common.
[1] https://lore.kernel.org/qemu-devel/apHH1upnh8udUUT-@ChaodeMacBook-Pro.local/
Cc: qemu-stable@nongnu.org
Suggested-by: Chao Liu <chao.liu@processmission.com>
Fixes: 954886ea6d ("hw/riscv: virt: Add optional ACLINT support to virt machine")
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
---
hw/riscv/virt.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index a6ec9def16..83a4b7710d 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -234,7 +234,8 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
(s->memmap[VIRT_CLINT].size * socket);
size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
}
- name = g_strdup_printf("/soc/mtimer@%lx", addr);
+ name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
+ addr + RISCV_ACLINT_DEFAULT_MTIME);
qemu_fdt_add_subnode(ms->fdt, name);
qemu_fdt_setprop_string(ms->fdt, name, "compatible",
"riscv,aclint-mtimer");
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (7 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:10 ` Chao Liu via qemu development
2026-09-01 5:17 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
` (6 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Yet another FDT that we want to move to a helper to avoid copy/pasting
code to other boards that will use a mtimer. In particular the future
'riscv-server-ref' board.
No FDT changes made.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 97 ++++++++++++++++++++++++++++++++
hw/riscv/virt.c | 102 ++++------------------------------
include/hw/riscv/fdt-common.h | 11 ++++
3 files changed, 120 insertions(+), 90 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index d815c5adff..d2ce93ad28 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -16,6 +16,7 @@
#include "target/riscv/cpu_bits.h"
#include "hw/riscv/riscv-iommu-bits.h"
#include "hw/riscv/iommu.h"
+#include "hw/intc/riscv_aclint.h"
#include "hw/intc/riscv_imsic.h"
#include "hw/pci/pci.h"
#include "hw/pci/pcie_host.h"
@@ -702,3 +703,99 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
aplic_phandles[props->socket] = aplic_s_phandle;
}
+
+void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
+ uint32_t *intc_phandles)
+{
+ uint32_t aclint_cells_size = props->num_harts * sizeof(uint32_t) * 2;
+ g_autofree uint32_t *aclint_mswi_cells = NULL;
+ g_autofree uint32_t *aclint_sswi_cells = NULL;
+ g_autofree uint32_t *aclint_mtimer_cells = NULL;
+ hwaddr addr, size;
+ char *name;
+ int cpu;
+
+ aclint_mswi_cells = g_new0(uint32_t, props->num_harts * 2);
+ aclint_mtimer_cells = g_new0(uint32_t, props->num_harts * 2);
+ aclint_sswi_cells = g_new0(uint32_t, props->num_harts * 2);
+
+ for (cpu = 0; cpu < props->num_harts; cpu++) {
+ aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+ aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
+ aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+ aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
+ aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
+ aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
+ }
+
+ if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
+ addr = props->clint->base + (props->clint->size * props->socket);
+ name = g_strdup_printf("/soc/mswi@%"HWADDR_PRIx, addr);
+
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "riscv,aclint-mswi");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
+ qemu_fdt_setprop(fdt, name, "interrupts-extended",
+ aclint_mswi_cells, aclint_cells_size);
+ qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
+
+ if (props->numa_enabled) {
+ qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
+ }
+
+ g_free(name);
+ }
+
+ if (props->aia_type == AIA_TYPE_APLIC_IMSIC) {
+ addr = props->clint->base +
+ (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * props->socket);
+ size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
+ } else {
+ addr = props->clint->base + RISCV_ACLINT_SWI_SIZE +
+ (props->clint->size * props->socket);
+ size = props->clint->size - RISCV_ACLINT_SWI_SIZE;
+ }
+
+ name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
+ addr + RISCV_ACLINT_DEFAULT_MTIME);
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible",
+ "riscv,aclint-mtimer");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
+ 2, size - RISCV_ACLINT_DEFAULT_MTIME,
+ 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
+ 2, RISCV_ACLINT_DEFAULT_MTIME);
+ qemu_fdt_setprop(fdt, name, "interrupts-extended",
+ aclint_mtimer_cells, aclint_cells_size);
+
+ if (props->numa_enabled) {
+ qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
+ }
+
+ g_free(name);
+
+ if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
+ addr = props->aclint_sswi->base
+ + (props->aclint_sswi->size * props->socket);
+
+ name = g_strdup_printf("/soc/sswi@%"HWADDR_PRIx, addr);
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible",
+ "riscv,aclint-sswi");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, addr, 2, props->aclint_sswi->size);
+ qemu_fdt_setprop(fdt, name, "interrupts-extended",
+ aclint_sswi_cells, aclint_cells_size);
+ qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
+ qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
+
+ if (props->numa_enabled) {
+ qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
+ }
+
+ g_free(name);
+ }
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 83a4b7710d..717a01da8d 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -180,94 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
sysmem);
}
-static void create_fdt_socket_aclint(RISCVVirtState *s,
- int socket,
- uint32_t *intc_phandles)
-{
- int cpu;
- char *name;
- unsigned long addr, size;
- uint32_t aclint_cells_size;
- g_autofree uint32_t *aclint_mswi_cells = NULL;
- g_autofree uint32_t *aclint_sswi_cells = NULL;
- g_autofree uint32_t *aclint_mtimer_cells = NULL;
- MachineState *ms = MACHINE(s);
-
- aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
- aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
- aclint_sswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
-
- for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
- aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
- aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
- aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
- aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
- aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
- aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
- }
- aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2;
-
- if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
- addr = s->memmap[VIRT_CLINT].base +
- (s->memmap[VIRT_CLINT].size * socket);
- name = g_strdup_printf("/soc/mswi@%lx", addr);
-
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible",
- "riscv,aclint-mswi");
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
- qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
- aclint_mswi_cells, aclint_cells_size);
- qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
- riscv_socket_fdt_write_id(ms, name, socket);
- g_free(name);
- }
-
- if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
- addr = s->memmap[VIRT_CLINT].base +
- (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket);
- size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
- } else {
- addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
- (s->memmap[VIRT_CLINT].size * socket);
- size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
- }
- name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
- addr + RISCV_ACLINT_DEFAULT_MTIME);
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible",
- "riscv,aclint-mtimer");
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
- 2, size - RISCV_ACLINT_DEFAULT_MTIME,
- 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
- 2, RISCV_ACLINT_DEFAULT_MTIME);
- qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
- aclint_mtimer_cells, aclint_cells_size);
- riscv_socket_fdt_write_id(ms, name, socket);
- g_free(name);
-
- if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
- addr = s->memmap[VIRT_ACLINT_SSWI].base +
- (s->memmap[VIRT_ACLINT_SSWI].size * socket);
-
- name = g_strdup_printf("/soc/sswi@%lx", addr);
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible",
- "riscv,aclint-sswi");
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, addr, 2, s->memmap[VIRT_ACLINT_SSWI].size);
- qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
- aclint_sswi_cells, aclint_cells_size);
- qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
- riscv_socket_fdt_write_id(ms, name, socket);
- g_free(name);
- }
-}
-
static void create_fdt_socket_plic(RISCVVirtState *s,
int socket,
uint32_t *phandle, uint32_t *intc_phandles,
@@ -348,6 +260,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
bool numa_enabled = riscv_numa_enabled(ms);
bool is_32_bit = riscv_is_32bit(&s->soc[0]);
APLICFdtProps aplic_props;
+ ACLINTFdtProps aclint_props;
riscv_fdt_create_cpu_socket_subnode(ms->fdt,
kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
@@ -355,6 +268,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
intc_phandles = g_new0(uint32_t, ms->smp.cpus);
+ if (virt_aclint_allowed() && s->have_aclint) {
+ aclint_props.clint = &s->memmap[VIRT_CLINT];
+ aclint_props.aclint_sswi = &s->memmap[VIRT_ACLINT_SSWI];
+ aclint_props.aia_type = s->aia_type;
+ aclint_props.numa_enabled = numa_enabled;
+ }
+
phandle_pos = ms->smp.cpus;
for (socket = (socket_count - 1); socket >= 0; socket--) {
hwaddr memaddr = s->memmap[VIRT_DRAM].base +
@@ -373,8 +293,10 @@ static void create_fdt_sockets(RISCVVirtState *s,
socket, riscv_numa_enabled(ms));
if (virt_aclint_allowed() && s->have_aclint) {
- create_fdt_socket_aclint(s, socket,
- &intc_phandles[phandle_pos]);
+ aclint_props.socket = socket;
+ aclint_props.num_harts = s->soc[socket].num_harts;
+ riscv_create_fdt_socket_aclint(ms->fdt, &aclint_props,
+ &intc_phandles[phandle_pos]);
} else if (tcg_enabled()) {
hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
s->memmap[VIRT_CLINT].size * socket;
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index 8207cfee7b..a45b063f66 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -63,6 +63,15 @@ typedef struct APLICFdtProps {
int aia_type;
} APLICFdtProps;
+typedef struct ACLINTFdtProps {
+ const MemMapEntry *clint;
+ const MemMapEntry *aclint_sswi;
+ int socket;
+ int num_harts;
+ int aia_type;
+ bool numa_enabled;
+} ACLINTFdtProps;
+
void *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size);
void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
@@ -117,4 +126,6 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
uint32_t *next_phandle,
uint32_t *intc_phandles,
uint32_t *aplic_phandles);
+void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
+ uint32_t *intc_phandles);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (8 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:11 ` Chao Liu via
2026-09-01 5:23 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
` (5 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Add a common uart FDT helper to be used by 'virt' and the future
'riscv-server-ref' board.
The 'tt-atlantis' board is left out of this patch because it's going
through UART related changes and its FDT might change soon, thus it's
better to wait for the final DT to be determined and then we can
evaluate whether it can share a common helper.
The "/chosen" and "/alias" changes are UART0 only so we're keeping them
out of the common helper. The board can set both manually as
appropriate.
No FDT changes intended.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 29 +++++++++++++++++++++++++++++
hw/riscv/virt.c | 35 +++++++++--------------------------
include/hw/riscv/fdt-common.h | 5 +++++
3 files changed, 43 insertions(+), 26 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index d2ce93ad28..0107aadaad 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -22,6 +22,8 @@
#include "hw/pci/pcie_host.h"
#include "hw/riscv/aia.h"
+#define UART_STD_CLOCK_FREQ 3686400 /* 3.6864 MHz */
+
void *riscv_create_board_device_tree(const char *model, const char *compatible,
int *fdt_size)
{
@@ -799,3 +801,30 @@ void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
g_free(name);
}
}
+
+char *riscv_fdt_get_uart_nodename(hwaddr addr)
+{
+ return g_strdup_printf("/soc/serial@%"HWADDR_PRIx, addr);
+}
+
+void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
+ int uart_irq, int aia_type,
+ uint32_t irq_phandle)
+{
+ g_autofree char *name = riscv_fdt_get_uart_nodename(uart_mem->base);
+
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, uart_mem->base,
+ 2, uart_mem->size);
+
+ qemu_fdt_setprop_cell(fdt, name, "clock-frequency", UART_STD_CLOCK_FREQ);
+ qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle);
+
+ if (aia_type == AIA_TYPE_NONE) {
+ qemu_fdt_setprop_cell(fdt, name, "interrupts", uart_irq);
+ } else {
+ qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq, 0x4);
+ }
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 717a01da8d..3e40513dc1 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -418,39 +418,22 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
}
}
-static void create_fdt_uart(RISCVVirtState *s,
- uint32_t irq_mmio_phandle, int memId, int irqNo)
+static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
{
g_autofree char *name = NULL;
MachineState *ms = MACHINE(s);
- name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx,
- s->memmap[memId].base);
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a");
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, s->memmap[memId].base,
- 2, s->memmap[memId].size);
- qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400);
- qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle);
- if (s->aia_type == VIRT_AIA_TYPE_NONE) {
- qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", irqNo);
- } else {
- qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqNo, 0x4);
+ if (s->uart1_present) {
+ riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART1],
+ UART1_IRQ, s->aia_type, irq_mmio_phandle);
}
- if (VIRT_UART0 == memId) {
- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
- qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
- }
-}
+ riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART0], UART0_IRQ,
+ s->aia_type, irq_mmio_phandle);
-static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
-{
- if (s->uart1_present) {
- create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ);
- }
- create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ);
+ name = riscv_fdt_get_uart_nodename(s->memmap[VIRT_UART0].base);
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
+ qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
}
static void create_fdt_rtc(RISCVVirtState *s,
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index a45b063f66..c8b25348bd 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -128,4 +128,9 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
uint32_t *aplic_phandles);
void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
uint32_t *intc_phandles);
+/* Caller must free the returned string. */
+char *riscv_fdt_get_uart_nodename(hwaddr addr);
+void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
+ int uart_irq, int aia_type,
+ uint32_t irq_phandle);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (9 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via
2026-09-01 5:23 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
` (4 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
The soon to be added 'riscv-server-ref' board will add a rtc FDT subnode
that is similar to what the 'virt' board users. Put it into a helper to
avoid copy/pasting code.
No FDT changes intended.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/fdt-common.c | 21 +++++++++++++++++++++
hw/riscv/virt.c | 26 ++------------------------
include/hw/riscv/fdt-common.h | 3 +++
3 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index 0107aadaad..ce2dcb43b4 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -828,3 +828,24 @@ void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq, 0x4);
}
}
+
+void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
+ int rtc_irq, int aia_type,
+ uint32_t irq_phandle)
+{
+ g_autofree char *name = NULL;
+
+ name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
+ rtc_mem->base);
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 2, rtc_mem->base,
+ 2, rtc_mem->size);
+ qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle);
+ if (aia_type == AIA_TYPE_NONE) {
+ qemu_fdt_setprop_cell(fdt, name, "interrupts", rtc_irq);
+ } else {
+ qemu_fdt_setprop_cells(fdt, name, "interrupts", rtc_irq, 0x4);
+ }
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 3e40513dc1..ccea5784f0 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -436,29 +436,6 @@ static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
}
-static void create_fdt_rtc(RISCVVirtState *s,
- uint32_t irq_mmio_phandle)
-{
- g_autofree char *name = NULL;
- MachineState *ms = MACHINE(s);
-
- name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
- s->memmap[VIRT_RTC].base);
- qemu_fdt_add_subnode(ms->fdt, name);
- qemu_fdt_setprop_string(ms->fdt, name, "compatible",
- "google,goldfish-rtc");
- qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
- 2, s->memmap[VIRT_RTC].base,
- 2, s->memmap[VIRT_RTC].size);
- qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
- irq_mmio_phandle);
- if (s->aia_type == VIRT_AIA_TYPE_NONE) {
- qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", RTC_IRQ);
- } else {
- qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ, 0x4);
- }
-}
-
static void create_fdt_fw_cfg(RISCVVirtState *s)
{
MachineState *ms = MACHINE(s);
@@ -566,7 +543,8 @@ static void finalize_fdt(RISCVVirtState *s)
create_fdt_uarts(s, irq_mmio_phandle);
- create_fdt_rtc(s, irq_mmio_phandle);
+ riscv_create_fdt_rtc(MACHINE(s)->fdt, &s->memmap[VIRT_RTC], RTC_IRQ,
+ s->aia_type, irq_mmio_phandle);
}
static void create_fdt(RISCVVirtState *s)
diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
index c8b25348bd..eb9db8278d 100644
--- a/include/hw/riscv/fdt-common.h
+++ b/include/hw/riscv/fdt-common.h
@@ -133,4 +133,7 @@ char *riscv_fdt_get_uart_nodename(hwaddr addr);
void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
int uart_irq, int aia_type,
uint32_t irq_phandle);
+void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
+ int rtc_irq, int aia_type,
+ uint32_t irq_phandle);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (10 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via qemu development
2026-09-01 5:24 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
` (3 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
There will be code repetition instances added by the 'riscv-server-ref'
board w.r.t device creation and initialization. Instead of waiting for
that code to land we're adding helpers beforehand. The idea is to make
the new board code shorter and more palatable for reviewers.
A new 'device-common' file is created for such helpers. We'll start
with the platform bus, a nice piece of software that only the 'virt'
board uses so far, and the 'riscv-server-ref' will use to support TPM
devices.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/device-common.c | 48 ++++++++++++++++++++++++++++++++
hw/riscv/meson.build | 1 +
hw/riscv/virt.c | 30 +++-----------------
include/hw/riscv/device-common.h | 19 +++++++++++++
4 files changed, 72 insertions(+), 26 deletions(-)
create mode 100644 hw/riscv/device-common.c
create mode 100644 include/hw/riscv/device-common.h
diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
new file mode 100644
index 0000000000..d3c68a9e71
--- /dev/null
+++ b/hw/riscv/device-common.c
@@ -0,0 +1,48 @@
+/*
+ * RISC-V board helpers for FDT generation.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/riscv/device-common.h"
+
+#include "hw/core/platform-bus.h"
+#include "hw/core/qdev.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/sysbus.h"
+#include "qapi/error.h"
+#include "system/address-spaces.h"
+#include "system/memory.h"
+
+
+DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
+ const MemMapEntry *platform_bus_mem,
+ int platform_bus_base_irq,
+ int platform_bus_num_irqs)
+{
+ MemoryRegion *sysmem = get_system_memory();
+ DeviceState *dev;
+ SysBusDevice *sysbus;
+
+ dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
+ dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
+ qdev_prop_set_uint32(dev, "num_irqs", platform_bus_num_irqs);
+ qdev_prop_set_uint32(dev, "mmio_size", platform_bus_mem->size);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ sysbus = SYS_BUS_DEVICE(dev);
+ for (int i = 0; i < platform_bus_num_irqs; i++) {
+ int irq = platform_bus_base_irq + i;
+ sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
+ }
+
+ memory_region_add_subregion(sysmem,
+ platform_bus_mem->base,
+ sysbus_mmio_get_region(sysbus, 0));
+
+ return dev;
+}
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 0d82ceacc4..7aa3c1578d 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -1,6 +1,7 @@
riscv_ss = ss.source_set()
riscv_ss.add(files('aia.c'))
riscv_ss.add(files('boot.c'))
+riscv_ss.add(files('device-common.c'))
riscv_ss.add(files('fdt-common.c'))
riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
riscv_ss.add(files('riscv_hart.c'))
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index ccea5784f0..a2671ae341 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -35,6 +35,7 @@
#include "hw/riscv/riscv-iommu-bits.h"
#include "hw/riscv/virt.h"
#include "hw/riscv/boot.h"
+#include "hw/riscv/device-common.h"
#include "hw/riscv/fdt-common.h"
#include "hw/riscv/machines-qom.h"
#include "hw/riscv/numa.h"
@@ -683,31 +684,6 @@ static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket,
memmap[VIRT_PLIC].size);
}
-static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
-{
- DeviceState *dev;
- SysBusDevice *sysbus;
- int i;
- MemoryRegion *sysmem = get_system_memory();
-
- dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
- dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
- qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS);
- qdev_prop_set_uint32(dev, "mmio_size", s->memmap[VIRT_PLATFORM_BUS].size);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- s->platform_bus_dev = dev;
-
- sysbus = SYS_BUS_DEVICE(dev);
- for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) {
- int irq = VIRT_PLATFORM_BUS_IRQ + i;
- sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
- }
-
- memory_region_add_subregion(sysmem,
- s->memmap[VIRT_PLATFORM_BUS].base,
- sysbus_mmio_get_region(sysbus, 0));
-}
-
static void virt_build_smbios(RISCVVirtState *s)
{
MachineClass *mc = MACHINE_GET_CLASS(s);
@@ -1030,7 +1006,9 @@ static void virt_machine_init(MachineState *machine)
gpex_pcie_init(system_memory, pcie_irqchip, s);
- create_platform_bus(s, mmio_irqchip);
+ s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
+ &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
+ VIRT_PLATFORM_BUS_NUM_IRQS);
serial_mm_init(system_memory, s->memmap[VIRT_UART0].base,
0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
new file mode 100644
index 0000000000..12af031bbf
--- /dev/null
+++ b/include/hw/riscv/device-common.h
@@ -0,0 +1,19 @@
+/*
+ * RISC-V board helpers for FDT generation.
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef RISCV_DEVICE_COMMON_H
+#define RISCV_DEVICE_COMMON_H
+
+#include "exec/hwaddr.h"
+#include "hw/core/qdev.h"
+
+DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
+ const MemMapEntry *platform_bus_mem,
+ int platform_bus_base_irq,
+ int platform_bus_num_irqs);
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (11 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via
2026-09-01 5:28 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
` (2 subsequent siblings)
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Move the flash device creating and flash map initialization to
device-common.c.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/device-common.c | 44 ++++++++++++++++++++++++
hw/riscv/virt.c | 57 +++++---------------------------
include/hw/riscv/device-common.h | 6 ++++
3 files changed, 58 insertions(+), 49 deletions(-)
diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
index d3c68a9e71..a054cd7114 100644
--- a/hw/riscv/device-common.c
+++ b/hw/riscv/device-common.c
@@ -10,11 +10,13 @@
#include "hw/riscv/device-common.h"
+#include "hw/block/flash.h"
#include "hw/core/platform-bus.h"
#include "hw/core/qdev.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/sysbus.h"
#include "qapi/error.h"
+#include "qom/object.h"
#include "system/address-spaces.h"
#include "system/memory.h"
@@ -46,3 +48,45 @@ DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
return dev;
}
+
+PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
+ const char *alias_prop_name,
+ int flash_sector_size)
+{
+ /*
+ * Create a single flash device. We use the same parameters as
+ * the flash devices on the ARM virt board.
+ */
+ DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
+
+ qdev_prop_set_uint64(dev, "sector-length", flash_sector_size);
+ qdev_prop_set_uint8(dev, "width", 4);
+ qdev_prop_set_uint8(dev, "device-width", 2);
+ qdev_prop_set_bit(dev, "big-endian", false);
+ qdev_prop_set_uint16(dev, "id0", 0x89);
+ qdev_prop_set_uint16(dev, "id1", 0x18);
+ qdev_prop_set_uint16(dev, "id2", 0x00);
+ qdev_prop_set_uint16(dev, "id3", 0x00);
+ qdev_prop_set_string(dev, "name", name);
+
+ object_property_add_child(parent, name, OBJECT(dev));
+ object_property_add_alias(parent, alias_prop_name,
+ OBJECT(dev), "drive");
+
+ return PFLASH_CFI01(dev);
+}
+
+void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
+ MemoryRegion *sysmem, int flash_sector_size)
+{
+ DeviceState *dev = DEVICE(flash);
+
+ assert(QEMU_IS_ALIGNED(size, flash_sector_size));
+ assert(size / flash_sector_size <= UINT32_MAX);
+
+ qdev_prop_set_uint32(dev, "num-blocks", size / flash_sector_size);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ memory_region_add_subregion(sysmem, base,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index a2671ae341..9ff5beae77 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -120,53 +120,12 @@ static MemMapEntry virt_high_pcie_memmap;
#define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
-static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s,
- const char *name,
- const char *alias_prop_name)
-{
- /*
- * Create a single flash device. We use the same parameters as
- * the flash devices on the ARM virt board.
- */
- DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
-
- qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
- qdev_prop_set_uint8(dev, "width", 4);
- qdev_prop_set_uint8(dev, "device-width", 2);
- qdev_prop_set_bit(dev, "big-endian", false);
- qdev_prop_set_uint16(dev, "id0", 0x89);
- qdev_prop_set_uint16(dev, "id1", 0x18);
- qdev_prop_set_uint16(dev, "id2", 0x00);
- qdev_prop_set_uint16(dev, "id3", 0x00);
- qdev_prop_set_string(dev, "name", name);
-
- object_property_add_child(OBJECT(s), name, OBJECT(dev));
- object_property_add_alias(OBJECT(s), alias_prop_name,
- OBJECT(dev), "drive");
-
- return PFLASH_CFI01(dev);
-}
-
static void virt_flash_create(RISCVVirtState *s)
{
- s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0");
- s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1");
-}
-
-static void virt_flash_map1(PFlashCFI01 *flash,
- hwaddr base, hwaddr size,
- MemoryRegion *sysmem)
-{
- DeviceState *dev = DEVICE(flash);
-
- assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE));
- assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
- qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-
- memory_region_add_subregion(sysmem, base,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
- 0));
+ s->flash[0] = riscv_flash_create(OBJECT(s), "virt.flash0", "pflash0",
+ VIRT_FLASH_SECTOR_SIZE);
+ s->flash[1] = riscv_flash_create(OBJECT(s), "virt.flash1", "pflash1",
+ VIRT_FLASH_SECTOR_SIZE);
}
static void virt_flash_map(RISCVVirtState *s,
@@ -175,10 +134,10 @@ static void virt_flash_map(RISCVVirtState *s,
hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
hwaddr flashbase = s->memmap[VIRT_FLASH].base;
- virt_flash_map1(s->flash[0], flashbase, flashsize,
- sysmem);
- virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize,
- sysmem);
+ riscv_init_flash_map(s->flash[0], flashbase, flashsize,
+ sysmem, VIRT_FLASH_SECTOR_SIZE);
+ riscv_init_flash_map(s->flash[1], flashbase + flashsize, flashsize,
+ sysmem, VIRT_FLASH_SECTOR_SIZE);
}
static void create_fdt_socket_plic(RISCVVirtState *s,
diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
index 12af031bbf..9f8bc67a1d 100644
--- a/include/hw/riscv/device-common.h
+++ b/include/hw/riscv/device-common.h
@@ -10,10 +10,16 @@
#define RISCV_DEVICE_COMMON_H
#include "exec/hwaddr.h"
+#include "hw/block/flash.h"
#include "hw/core/qdev.h"
DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
const MemMapEntry *platform_bus_mem,
int platform_bus_base_irq,
int platform_bus_num_irqs);
+PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
+ const char *alias_prop_name,
+ int flash_sector_size);
+void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
+ MemoryRegion *sysmem, int flash_sector_size);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (12 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:13 ` Chao Liu via qemu development
2026-09-01 5:28 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
2026-09-01 5:32 ` [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Alistair Francis
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
The GPEX_HOST initialization in 'virt' can be moved to device-common.c
and be re-used later for other boards, namely the future
'riscv-server-ref' emulation.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/device-common.c | 76 +++++++++++++++++++++++++++++++
hw/riscv/virt.c | 77 ++------------------------------
include/hw/riscv/device-common.h | 7 +++
3 files changed, 87 insertions(+), 73 deletions(-)
diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
index a054cd7114..d1a6814f87 100644
--- a/hw/riscv/device-common.c
+++ b/hw/riscv/device-common.c
@@ -15,6 +15,8 @@
#include "hw/core/qdev.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/sysbus.h"
+#include "hw/pci/pci.h"
+#include "hw/pci-host/gpex.h"
#include "qapi/error.h"
#include "qom/object.h"
#include "system/address-spaces.h"
@@ -90,3 +92,77 @@ void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
memory_region_add_subregion(sysmem, base,
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
}
+
+DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
+ DeviceState *irqchip,
+ const MemMapEntry *pcie_ecam_mem,
+ const MemMapEntry *pcie_mmio_mem,
+ const MemMapEntry *high_pcie_mmio_mem,
+ const MemMapEntry *pcie_pio_mem,
+ int pcie_irq)
+{
+ DeviceState *dev;
+ MemoryRegion *ecam_alias, *ecam_reg;
+ MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
+ hwaddr ecam_base = pcie_ecam_mem->base;
+ hwaddr ecam_size = pcie_ecam_mem->size;
+ hwaddr mmio_base = pcie_mmio_mem->base;
+ hwaddr mmio_size = pcie_mmio_mem->size;
+ hwaddr high_mmio_base = high_pcie_mmio_mem->base;
+ hwaddr high_mmio_size = high_pcie_mmio_mem->size;
+ hwaddr pio_base = pcie_pio_mem->base;
+ hwaddr pio_size = pcie_pio_mem->size;
+
+ dev = qdev_new(TYPE_GPEX_HOST);
+
+ /* Set GPEX object properties for the virt machine */
+ object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
+ ecam_base, NULL);
+ object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
+ ecam_size, NULL);
+ object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
+ mmio_base, NULL);
+ object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
+ mmio_size, NULL);
+ object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
+ high_mmio_base, NULL);
+ object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
+ high_mmio_size, NULL);
+ object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
+ pio_base, NULL);
+ object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
+ pio_size, NULL);
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ ecam_alias = g_new0(MemoryRegion, 1);
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+ ecam_reg, 0, ecam_size);
+ memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
+
+ mmio_alias = g_new0(MemoryRegion, 1);
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg, mmio_base, mmio_size);
+ memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
+
+ /* Map high MMIO space */
+ high_mmio_alias = g_new0(MemoryRegion, 1);
+ memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
+ mmio_reg, high_mmio_base, high_mmio_size);
+ memory_region_add_subregion(get_system_memory(), high_mmio_base,
+ high_mmio_alias);
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
+
+ for (int i = 0; i < PCI_NUM_PINS; i++) {
+ qemu_irq irq = qdev_get_gpio_in(irqchip, pcie_irq + i);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+ gpex_set_irq_num(GPEX_HOST(dev), i, pcie_irq + i);
+ }
+
+ GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
+ return dev;
+}
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 9ff5beae77..d75dec2dd2 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -540,78 +540,6 @@ static void create_fdt(RISCVVirtState *s)
create_fdt_pmu(s);
}
-static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
- DeviceState *irqchip,
- RISCVVirtState *s)
-{
- DeviceState *dev;
- MemoryRegion *ecam_alias, *ecam_reg;
- MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
- hwaddr ecam_base = s->memmap[VIRT_PCIE_ECAM].base;
- hwaddr ecam_size = s->memmap[VIRT_PCIE_ECAM].size;
- hwaddr mmio_base = s->memmap[VIRT_PCIE_MMIO].base;
- hwaddr mmio_size = s->memmap[VIRT_PCIE_MMIO].size;
- hwaddr high_mmio_base = virt_high_pcie_memmap.base;
- hwaddr high_mmio_size = virt_high_pcie_memmap.size;
- hwaddr pio_base = s->memmap[VIRT_PCIE_PIO].base;
- hwaddr pio_size = s->memmap[VIRT_PCIE_PIO].size;
- qemu_irq irq;
- int i;
-
- dev = qdev_new(TYPE_GPEX_HOST);
-
- /* Set GPEX object properties for the virt machine */
- object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
- ecam_base, NULL);
- object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
- ecam_size, NULL);
- object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
- mmio_base, NULL);
- object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
- mmio_size, NULL);
- object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
- high_mmio_base, NULL);
- object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
- high_mmio_size, NULL);
- object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
- pio_base, NULL);
- object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
- pio_size, NULL);
-
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-
- ecam_alias = g_new0(MemoryRegion, 1);
- ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
- memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
- ecam_reg, 0, ecam_size);
- memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
-
- mmio_alias = g_new0(MemoryRegion, 1);
- mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
- memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
- mmio_reg, mmio_base, mmio_size);
- memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
-
- /* Map high MMIO space */
- high_mmio_alias = g_new0(MemoryRegion, 1);
- memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
- mmio_reg, high_mmio_base, high_mmio_size);
- memory_region_add_subregion(get_system_memory(), high_mmio_base,
- high_mmio_alias);
-
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
-
- for (i = 0; i < PCI_NUM_PINS; i++) {
- irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
- gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
- }
-
- GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
- return dev;
-}
-
static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base)
{
FWCfgState *fw_cfg;
@@ -963,7 +891,10 @@ static void virt_machine_init(MachineState *machine)
qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i));
}
- gpex_pcie_init(system_memory, pcie_irqchip, s);
+ riscv_gpex_pcie_init(system_memory, pcie_irqchip,
+ &s->memmap[VIRT_PCIE_ECAM], &s->memmap[VIRT_PCIE_MMIO],
+ &virt_high_pcie_memmap, &s->memmap[VIRT_PCIE_PIO],
+ PCIE_IRQ);
s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
&s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
index 9f8bc67a1d..572912ec36 100644
--- a/include/hw/riscv/device-common.h
+++ b/include/hw/riscv/device-common.h
@@ -22,4 +22,11 @@ PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
int flash_sector_size);
void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
MemoryRegion *sysmem, int flash_sector_size);
+DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
+ DeviceState *irqchip,
+ const MemMapEntry *pcie_ecam_mem,
+ const MemMapEntry *pcie_mmio_mem,
+ const MemMapEntry *high_pcie_mmio_mem,
+ const MemMapEntry *pcie_pio_mem,
+ int pcie_irq);
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (13 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
@ 2026-08-28 20:39 ` Daniel Henrique Barboza
2026-08-29 3:13 ` Chao Liu via
2026-09-01 5:28 ` Alistair Francis
2026-09-01 5:32 ` [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Alistair Francis
15 siblings, 2 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 20:39 UTC (permalink / raw)
To: qemu-devel
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Daniel Henrique Barboza, Philippe Mathieu-Daudé,
Palmer Dabbelt
Move the creation of riscv-iommu-sys to its own file instead of open
coding it in the 'virt' board. Other boards in the future might want to
use this device and we want to avoid code duplication.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/riscv/riscv-iommu-sys.c | 25 +++++++++++++++++++++++++
hw/riscv/riscv-iommu.h | 3 +++
hw/riscv/virt.c | 23 +++--------------------
3 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c
index 3314adeed2..258c171efd 100644
--- a/hw/riscv/riscv-iommu-sys.c
+++ b/hw/riscv/riscv-iommu-sys.c
@@ -217,6 +217,31 @@ static void riscv_iommu_sys_init(Object *obj)
riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_BOTH);
}
+DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
+ hwaddr addr, int base_irq,
+ bool is_32_bit)
+{
+ DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
+
+ object_property_set_uint(OBJECT(iommu_sys), "addr", addr, &error_fatal);
+ object_property_set_uint(OBJECT(iommu_sys), "base-irq",
+ base_irq, &error_fatal);
+ object_property_set_link(OBJECT(iommu_sys), "irqchip",
+ OBJECT(mmio_irqchip),
+ &error_fatal);
+ /*
+ * For riscv64 use a physical address size of 56 bits (44 bit PPN),
+ * and for riscv32 use 34 bits (22 bit PPN).
+ */
+ object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
+ is_32_bit ? 34 : 56,
+ &error_fatal);
+
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
+
+ return iommu_sys;
+}
+
static const Property riscv_iommu_sys_properties[] = {
DEFINE_PROP_UINT64("addr", RISCVIOMMUStateSys, addr, 0),
DEFINE_PROP_UINT32("base-irq", RISCVIOMMUStateSys, base_irq, 0),
diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
index da70e8bfa8..7c470ba084 100644
--- a/hw/riscv/riscv-iommu.h
+++ b/hw/riscv/riscv-iommu.h
@@ -104,6 +104,9 @@ void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
void riscv_iommu_reset(RISCVIOMMUState *s);
void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
void riscv_iommu_fault(RISCVIOMMUState *s, struct riscv_iommu_fq_record *ev);
+DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
+ hwaddr addr, int base_irq,
+ bool is_32_bit);
typedef struct RISCVIOMMUContext RISCVIOMMUContext;
/* Device translation context state. */
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index d75dec2dd2..de7b99c6a5 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -32,6 +32,7 @@
#include "hw/core/sysbus-fdt.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/iommu.h"
+#include "hw/riscv/riscv-iommu.h"
#include "hw/riscv/riscv-iommu-bits.h"
#include "hw/riscv/virt.h"
#include "hw/riscv/boot.h"
@@ -933,26 +934,8 @@ static void virt_machine_init(MachineState *machine)
}
if (virt_is_iommu_sys_enabled(s)) {
- DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
-
- object_property_set_uint(OBJECT(iommu_sys), "addr",
- s->memmap[VIRT_IOMMU_SYS].base,
- &error_fatal);
- object_property_set_uint(OBJECT(iommu_sys), "base-irq",
- IOMMU_SYS_IRQ,
- &error_fatal);
- object_property_set_link(OBJECT(iommu_sys), "irqchip",
- OBJECT(mmio_irqchip),
- &error_fatal);
- /*
- * For riscv64 use a physical address size of 56 bits (44 bit PPN),
- * and for riscv32 use 34 bits (22 bit PPN).
- */
- object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
- riscv_is_32bit(&s->soc[0]) ? 34 : 56,
- &error_fatal);
-
- sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
+ riscv_create_iommu_sys(mmio_irqchip, s->memmap[VIRT_IOMMU_SYS].base,
+ IOMMU_SYS_IRQ, riscv_is_32bit(&s->soc[0]));
}
s->machine_done.notify = virt_machine_done;
--
2.43.0
^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
2026-08-28 20:39 ` [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
@ 2026-08-29 3:08 ` Chao Liu via qemu development
2026-09-01 4:49 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:08 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:07PM +0800, Daniel Henrique Barboza wrote:
> The pcie FDT is quite tedious but can be parametrized into a helper.
> This is going to benefit only the 'virt' board for now but it will be
> used by the 'riscv-server-ref' board in the near future too.
>
> Some other changes made:
>
> - FDT related macros are moved to fdt-common.h. Only a couple are being
> used by the helper ATM but more will be added in the next patches;
> - an RISCVAIAType enum is created. There are several FDTs that depends
> on the active AIA type being used, and we want a way to represent the
> different AIA modes that doesn't re-use the 'virt' specific VIRT_AIA_*
> macros. The enum vals are equivalent by design - we want "s->aia_type"
> to be used by 'virt' when calling the fdt helpers, and other boards
> will use "AIA_*" macros in their code.
>
> No FDT changes made.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 111 ++++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 111 +++-------------------------------
> include/hw/riscv/fdt-common.h | 29 +++++++++
> include/hw/riscv/virt.h | 15 -----
> 4 files changed, 149 insertions(+), 117 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 88589330fb..38813b6aa7 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -15,6 +15,8 @@
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pcie_host.h"
>
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size)
> @@ -384,3 +386,112 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
>
> return iommu_phandle;
> }
> +
> +static void create_pcie_irq_map(void *fdt, char *nodename,
> + uint32_t irqchip_phandle,
> + RISCVAIAType aia_type, uint32_t pcie_irq)
> +{
> + int pin, dev;
> + uint32_t irq_map_stride = 0;
> + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
> + FDT_MAX_INT_MAP_WIDTH] = {};
> + uint32_t *irq_map = full_irq_map;
> +
> + /*
> + * This code creates a standard swizzle of interrupts such that
> + * each device's first interrupt is based on it's PCI_SLOT number.
> + * (See pci_swizzle_map_irq_fn())
> + *
> + * We only need one entry per interrupt in the table (not one per
> + * possible slot) seeing the interrupt-map-mask will allow the table
> + * to wrap to any number of devices.
> + */
> + for (dev = 0; dev < PCI_NUM_PINS; dev++) {
> + int devfn = dev * 0x8;
> +
> + for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> + int irq_nr = pcie_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
> + int i = 0;
> +
> + /* Fill PCI address cells */
> + irq_map[i] = cpu_to_be32(devfn << 8);
> + i += FDT_PCI_ADDR_CELLS;
> +
> + /* Fill PCI Interrupt cells */
> + irq_map[i] = cpu_to_be32(pin + 1);
> + i += FDT_PCI_INT_CELLS;
> +
> + /* Fill interrupt controller phandle and cells */
> + irq_map[i++] = cpu_to_be32(irqchip_phandle);
> + irq_map[i++] = cpu_to_be32(irq_nr);
> +
> + if (aia_type != AIA_TYPE_NONE) {
> + irq_map[i++] = cpu_to_be32(0x4);
> + }
> +
> + if (!irq_map_stride) {
> + irq_map_stride = i;
> + }
> + irq_map += irq_map_stride;
> + }
> + }
> +
> + qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
> + PCI_NUM_PINS * PCI_NUM_PINS *
> + irq_map_stride * sizeof(uint32_t));
> +
> + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
> + 0x1800, 0, 0, 0x7);
> +}
> +
> +/*
> + * NOTE: this function uses a "/soc/pci@..." FDT subnode that
> + * should be created beforehand.
> + */
> +void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> + const MemMapEntry *pcie_ecam,
> + const MemMapEntry *pcie_pio,
> + 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)
> +{
> + g_autofree char *name = NULL;
> +
> + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, pcie_ecam->base);
> + qemu_fdt_setprop_cell(fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", FDT_PCI_INT_CELLS);
> + qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0x2);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "pci-host-ecam-generic");
> + qemu_fdt_setprop_string(fdt, name, "device_type", "pci");
> + qemu_fdt_setprop_cell(fdt, name, "linux,pci-domain", 0);
> +
> + qemu_fdt_setprop_cells(fdt, name, "bus-range", 0,
> + pcie_ecam->size / PCIE_MMCFG_SIZE_MIN - 1);
> + qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> +
> + if (aia_type == AIA_TYPE_APLIC_IMSIC) {
> + qemu_fdt_setprop_cell(fdt, name, "msi-parent", msi_pcie_phandle);
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2,
> + pcie_ecam->base, 2, pcie_ecam->size);
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> + 1, FDT_PCI_RANGE_IOPORT, 2, 0,
> + 2, pcie_pio->base, 2, pcie_pio->size,
> + 1, FDT_PCI_RANGE_MMIO,
> + 2, pcie_mmio->base,
> + 2, pcie_mmio->base, 2, pcie_mmio->size,
> + 1, FDT_PCI_RANGE_MMIO_64BIT,
> + 2, high_pcie->base,
> + 2, high_pcie->base, 2, high_pcie->size);
> +
> + if (has_iommu_sys) {
> + qemu_fdt_setprop_cells(fdt, name, "iommu-map",
> + 0, iommu_sys_phandle, 0, 0x10000);
> + }
> +
> + create_pcie_irq_map(fdt, name, irq_pcie_phandle, aia_type, pcie_irq);
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 8a165f4d9e..a28e6d200a 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -180,61 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
> sysmem);
> }
>
> -static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
> - uint32_t irqchip_phandle)
> -{
> - int pin, dev;
> - uint32_t irq_map_stride = 0;
> - uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
> - FDT_MAX_INT_MAP_WIDTH] = {};
> - uint32_t *irq_map = full_irq_map;
> -
> - /*
> - * This code creates a standard swizzle of interrupts such that
> - * each device's first interrupt is based on it's PCI_SLOT number.
> - * (See pci_swizzle_map_irq_fn())
> - *
> - * We only need one entry per interrupt in the table (not one per
> - * possible slot) seeing the interrupt-map-mask will allow the table
> - * to wrap to any number of devices.
> - */
> - for (dev = 0; dev < PCI_NUM_PINS; dev++) {
> - int devfn = dev * 0x8;
> -
> - for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
> - int i = 0;
> -
> - /* Fill PCI address cells */
> - irq_map[i] = cpu_to_be32(devfn << 8);
> - i += FDT_PCI_ADDR_CELLS;
> -
> - /* Fill PCI Interrupt cells */
> - irq_map[i] = cpu_to_be32(pin + 1);
> - i += FDT_PCI_INT_CELLS;
> -
> - /* Fill interrupt controller phandle and cells */
> - irq_map[i++] = cpu_to_be32(irqchip_phandle);
> - irq_map[i++] = cpu_to_be32(irq_nr);
> - if (s->aia_type != VIRT_AIA_TYPE_NONE) {
> - irq_map[i++] = cpu_to_be32(0x4);
> - }
> -
> - if (!irq_map_stride) {
> - irq_map_stride = i;
> - }
> - irq_map += irq_map_stride;
> - }
> - }
> -
> - qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
> - PCI_NUM_PINS * PCI_NUM_PINS *
> - irq_map_stride * sizeof(uint32_t));
> -
> - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
> - 0x1800, 0, 0, 0x7);
> -}
> -
> static void create_fdt_socket_aclint(RISCVVirtState *s,
> int socket,
> uint32_t *intc_phandles)
> @@ -723,51 +668,6 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
> }
> }
>
> -static void create_fdt_pcie(RISCVVirtState *s,
> - uint32_t irq_pcie_phandle,
> - uint32_t msi_pcie_phandle,
> - uint32_t iommu_sys_phandle)
> -{
> - g_autofree char *name = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
> - s->memmap[VIRT_PCIE_ECAM].base);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells",
> - FDT_PCI_ADDR_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells",
> - FDT_PCI_INT_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "pci-host-ecam-generic");
> - qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci");
> - qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0);
> - qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0,
> - s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> - qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0);
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle);
> - }
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2,
> - s->memmap[VIRT_PCIE_ECAM].base, 2, s->memmap[VIRT_PCIE_ECAM].size);
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges",
> - 1, FDT_PCI_RANGE_IOPORT, 2, 0,
> - 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size,
> - 1, FDT_PCI_RANGE_MMIO,
> - 2, s->memmap[VIRT_PCIE_MMIO].base,
> - 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s->memmap[VIRT_PCIE_MMIO].size,
> - 1, FDT_PCI_RANGE_MMIO_64BIT,
> - 2, virt_high_pcie_memmap.base,
> - 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
> -
> - if (virt_is_iommu_sys_enabled(s)) {
> - qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
> - 0, iommu_sys_phandle, 0, 0x10000);
> - }
> -
> - create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
> -}
> -
> static void create_fdt_uart(RISCVVirtState *s,
> uint32_t irq_mmio_phandle, int memId, int irqNo)
> {
> @@ -916,8 +816,15 @@ static void finalize_fdt(RISCVVirtState *s)
> msi_pcie_phandle,
> IOMMU_SYS_IRQ);
> }
> - create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
> - iommu_sys_phandle);
> +
> + riscv_create_fdt_pcie(MACHINE(s)->fdt, s->aia_type,
> + virt_is_iommu_sys_enabled(s),
> + &s->memmap[VIRT_PCIE_ECAM],
> + &s->memmap[VIRT_PCIE_PIO],
> + &s->memmap[VIRT_PCIE_MMIO],
> + &virt_high_pcie_memmap,
> + irq_pcie_phandle, msi_pcie_phandle,
> + iommu_sys_phandle, PCIE_IRQ);
>
> riscv_create_fdt_syscon(MACHINE(s)->fdt, &phandle,
> s->memmap[VIRT_TEST].base,
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index 65711468b8..3750230865 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -11,6 +11,27 @@
>
> #include "target/riscv/cpu.h"
>
> +#define FDT_PCI_ADDR_CELLS 3
> +#define FDT_PCI_INT_CELLS 1
> +#define FDT_PLIC_ADDR_CELLS 0
> +#define FDT_PLIC_INT_CELLS 1
> +#define FDT_APLIC_INT_CELLS 2
> +#define FDT_APLIC_ADDR_CELLS 0
> +#define FDT_IMSIC_INT_CELLS 0
> +#define FDT_MAX_INT_CELLS 2
> +#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> + 1 + FDT_MAX_INT_CELLS)
> +#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> + 1 + FDT_PLIC_INT_CELLS)
> +#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> + 1 + FDT_APLIC_INT_CELLS)
> +
> +typedef enum RISCVAIAType {
> + AIA_TYPE_NONE = 0,
> + AIA_TYPE_APLIC,
> + AIA_TYPE_APLIC_IMSIC,
> +} RISCVAIAType;
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -48,4 +69,12 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
> uint32_t irq_chip,
> uint32_t msi_phandle,
> uint32_t iommu_sys_irq);
> +void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> + const MemMapEntry *pcie_ecam,
> + const MemMapEntry *pcie_pio,
> + 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);
> #endif
> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> index 7c862b0da2..e516898f9a 100644
> --- a/include/hw/riscv/virt.h
> +++ b/include/hw/riscv/virt.h
> @@ -121,21 +121,6 @@ enum {
> #define VIRT_PLIC_SIZE(__num_context) \
> (VIRT_PLIC_CONTEXT_BASE + (__num_context) * VIRT_PLIC_CONTEXT_STRIDE)
>
> -#define FDT_PCI_ADDR_CELLS 3
> -#define FDT_PCI_INT_CELLS 1
> -#define FDT_PLIC_ADDR_CELLS 0
> -#define FDT_PLIC_INT_CELLS 1
> -#define FDT_APLIC_INT_CELLS 2
> -#define FDT_APLIC_ADDR_CELLS 0
> -#define FDT_IMSIC_INT_CELLS 0
> -#define FDT_MAX_INT_CELLS 2
> -#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> - 1 + FDT_MAX_INT_CELLS)
> -#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> - 1 + FDT_PLIC_INT_CELLS)
> -#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> - 1 + FDT_APLIC_INT_CELLS)
> -
> bool virt_is_acpi_enabled(RISCVVirtState *s);
> bool virt_is_iommu_sys_enabled(RISCVVirtState *s);
> void virt_acpi_setup(RISCVVirtState *vms);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
@ 2026-08-29 3:08 ` Chao Liu via qemu development
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:08 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:07PM +0800, Daniel Henrique Barboza wrote:
> The pcie FDT is quite tedious but can be parametrized into a helper.
> This is going to benefit only the 'virt' board for now but it will be
> used by the 'riscv-server-ref' board in the near future too.
>
> Some other changes made:
>
> - FDT related macros are moved to fdt-common.h. Only a couple are being
> used by the helper ATM but more will be added in the next patches;
> - an RISCVAIAType enum is created. There are several FDTs that depends
> on the active AIA type being used, and we want a way to represent the
> different AIA modes that doesn't re-use the 'virt' specific VIRT_AIA_*
> macros. The enum vals are equivalent by design - we want "s->aia_type"
> to be used by 'virt' when calling the fdt helpers, and other boards
> will use "AIA_*" macros in their code.
>
> No FDT changes made.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 111 ++++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 111 +++-------------------------------
> include/hw/riscv/fdt-common.h | 29 +++++++++
> include/hw/riscv/virt.h | 15 -----
> 4 files changed, 149 insertions(+), 117 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 88589330fb..38813b6aa7 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -15,6 +15,8 @@
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pcie_host.h"
>
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size)
> @@ -384,3 +386,112 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
>
> return iommu_phandle;
> }
> +
> +static void create_pcie_irq_map(void *fdt, char *nodename,
> + uint32_t irqchip_phandle,
> + RISCVAIAType aia_type, uint32_t pcie_irq)
> +{
> + int pin, dev;
> + uint32_t irq_map_stride = 0;
> + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
> + FDT_MAX_INT_MAP_WIDTH] = {};
> + uint32_t *irq_map = full_irq_map;
> +
> + /*
> + * This code creates a standard swizzle of interrupts such that
> + * each device's first interrupt is based on it's PCI_SLOT number.
> + * (See pci_swizzle_map_irq_fn())
> + *
> + * We only need one entry per interrupt in the table (not one per
> + * possible slot) seeing the interrupt-map-mask will allow the table
> + * to wrap to any number of devices.
> + */
> + for (dev = 0; dev < PCI_NUM_PINS; dev++) {
> + int devfn = dev * 0x8;
> +
> + for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> + int irq_nr = pcie_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
> + int i = 0;
> +
> + /* Fill PCI address cells */
> + irq_map[i] = cpu_to_be32(devfn << 8);
> + i += FDT_PCI_ADDR_CELLS;
> +
> + /* Fill PCI Interrupt cells */
> + irq_map[i] = cpu_to_be32(pin + 1);
> + i += FDT_PCI_INT_CELLS;
> +
> + /* Fill interrupt controller phandle and cells */
> + irq_map[i++] = cpu_to_be32(irqchip_phandle);
> + irq_map[i++] = cpu_to_be32(irq_nr);
> +
> + if (aia_type != AIA_TYPE_NONE) {
> + irq_map[i++] = cpu_to_be32(0x4);
> + }
> +
> + if (!irq_map_stride) {
> + irq_map_stride = i;
> + }
> + irq_map += irq_map_stride;
> + }
> + }
> +
> + qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
> + PCI_NUM_PINS * PCI_NUM_PINS *
> + irq_map_stride * sizeof(uint32_t));
> +
> + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
> + 0x1800, 0, 0, 0x7);
> +}
> +
> +/*
> + * NOTE: this function uses a "/soc/pci@..." FDT subnode that
> + * should be created beforehand.
> + */
> +void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> + const MemMapEntry *pcie_ecam,
> + const MemMapEntry *pcie_pio,
> + 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)
> +{
> + g_autofree char *name = NULL;
> +
> + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, pcie_ecam->base);
> + qemu_fdt_setprop_cell(fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", FDT_PCI_INT_CELLS);
> + qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0x2);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "pci-host-ecam-generic");
> + qemu_fdt_setprop_string(fdt, name, "device_type", "pci");
> + qemu_fdt_setprop_cell(fdt, name, "linux,pci-domain", 0);
> +
> + qemu_fdt_setprop_cells(fdt, name, "bus-range", 0,
> + pcie_ecam->size / PCIE_MMCFG_SIZE_MIN - 1);
> + qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> +
> + if (aia_type == AIA_TYPE_APLIC_IMSIC) {
> + qemu_fdt_setprop_cell(fdt, name, "msi-parent", msi_pcie_phandle);
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2,
> + pcie_ecam->base, 2, pcie_ecam->size);
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> + 1, FDT_PCI_RANGE_IOPORT, 2, 0,
> + 2, pcie_pio->base, 2, pcie_pio->size,
> + 1, FDT_PCI_RANGE_MMIO,
> + 2, pcie_mmio->base,
> + 2, pcie_mmio->base, 2, pcie_mmio->size,
> + 1, FDT_PCI_RANGE_MMIO_64BIT,
> + 2, high_pcie->base,
> + 2, high_pcie->base, 2, high_pcie->size);
> +
> + if (has_iommu_sys) {
> + qemu_fdt_setprop_cells(fdt, name, "iommu-map",
> + 0, iommu_sys_phandle, 0, 0x10000);
> + }
> +
> + create_pcie_irq_map(fdt, name, irq_pcie_phandle, aia_type, pcie_irq);
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 8a165f4d9e..a28e6d200a 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -180,61 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
> sysmem);
> }
>
> -static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
> - uint32_t irqchip_phandle)
> -{
> - int pin, dev;
> - uint32_t irq_map_stride = 0;
> - uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
> - FDT_MAX_INT_MAP_WIDTH] = {};
> - uint32_t *irq_map = full_irq_map;
> -
> - /*
> - * This code creates a standard swizzle of interrupts such that
> - * each device's first interrupt is based on it's PCI_SLOT number.
> - * (See pci_swizzle_map_irq_fn())
> - *
> - * We only need one entry per interrupt in the table (not one per
> - * possible slot) seeing the interrupt-map-mask will allow the table
> - * to wrap to any number of devices.
> - */
> - for (dev = 0; dev < PCI_NUM_PINS; dev++) {
> - int devfn = dev * 0x8;
> -
> - for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
> - int i = 0;
> -
> - /* Fill PCI address cells */
> - irq_map[i] = cpu_to_be32(devfn << 8);
> - i += FDT_PCI_ADDR_CELLS;
> -
> - /* Fill PCI Interrupt cells */
> - irq_map[i] = cpu_to_be32(pin + 1);
> - i += FDT_PCI_INT_CELLS;
> -
> - /* Fill interrupt controller phandle and cells */
> - irq_map[i++] = cpu_to_be32(irqchip_phandle);
> - irq_map[i++] = cpu_to_be32(irq_nr);
> - if (s->aia_type != VIRT_AIA_TYPE_NONE) {
> - irq_map[i++] = cpu_to_be32(0x4);
> - }
> -
> - if (!irq_map_stride) {
> - irq_map_stride = i;
> - }
> - irq_map += irq_map_stride;
> - }
> - }
> -
> - qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
> - PCI_NUM_PINS * PCI_NUM_PINS *
> - irq_map_stride * sizeof(uint32_t));
> -
> - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
> - 0x1800, 0, 0, 0x7);
> -}
> -
> static void create_fdt_socket_aclint(RISCVVirtState *s,
> int socket,
> uint32_t *intc_phandles)
> @@ -723,51 +668,6 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
> }
> }
>
> -static void create_fdt_pcie(RISCVVirtState *s,
> - uint32_t irq_pcie_phandle,
> - uint32_t msi_pcie_phandle,
> - uint32_t iommu_sys_phandle)
> -{
> - g_autofree char *name = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
> - s->memmap[VIRT_PCIE_ECAM].base);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells",
> - FDT_PCI_ADDR_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells",
> - FDT_PCI_INT_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "pci-host-ecam-generic");
> - qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci");
> - qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0);
> - qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0,
> - s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> - qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0);
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle);
> - }
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2,
> - s->memmap[VIRT_PCIE_ECAM].base, 2, s->memmap[VIRT_PCIE_ECAM].size);
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges",
> - 1, FDT_PCI_RANGE_IOPORT, 2, 0,
> - 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size,
> - 1, FDT_PCI_RANGE_MMIO,
> - 2, s->memmap[VIRT_PCIE_MMIO].base,
> - 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s->memmap[VIRT_PCIE_MMIO].size,
> - 1, FDT_PCI_RANGE_MMIO_64BIT,
> - 2, virt_high_pcie_memmap.base,
> - 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
> -
> - if (virt_is_iommu_sys_enabled(s)) {
> - qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
> - 0, iommu_sys_phandle, 0, 0x10000);
> - }
> -
> - create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
> -}
> -
> static void create_fdt_uart(RISCVVirtState *s,
> uint32_t irq_mmio_phandle, int memId, int irqNo)
> {
> @@ -916,8 +816,15 @@ static void finalize_fdt(RISCVVirtState *s)
> msi_pcie_phandle,
> IOMMU_SYS_IRQ);
> }
> - create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
> - iommu_sys_phandle);
> +
> + riscv_create_fdt_pcie(MACHINE(s)->fdt, s->aia_type,
> + virt_is_iommu_sys_enabled(s),
> + &s->memmap[VIRT_PCIE_ECAM],
> + &s->memmap[VIRT_PCIE_PIO],
> + &s->memmap[VIRT_PCIE_MMIO],
> + &virt_high_pcie_memmap,
> + irq_pcie_phandle, msi_pcie_phandle,
> + iommu_sys_phandle, PCIE_IRQ);
>
> riscv_create_fdt_syscon(MACHINE(s)->fdt, &phandle,
> s->memmap[VIRT_TEST].base,
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index 65711468b8..3750230865 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -11,6 +11,27 @@
>
> #include "target/riscv/cpu.h"
>
> +#define FDT_PCI_ADDR_CELLS 3
> +#define FDT_PCI_INT_CELLS 1
> +#define FDT_PLIC_ADDR_CELLS 0
> +#define FDT_PLIC_INT_CELLS 1
> +#define FDT_APLIC_INT_CELLS 2
> +#define FDT_APLIC_ADDR_CELLS 0
> +#define FDT_IMSIC_INT_CELLS 0
> +#define FDT_MAX_INT_CELLS 2
> +#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> + 1 + FDT_MAX_INT_CELLS)
> +#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> + 1 + FDT_PLIC_INT_CELLS)
> +#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> + 1 + FDT_APLIC_INT_CELLS)
> +
> +typedef enum RISCVAIAType {
> + AIA_TYPE_NONE = 0,
> + AIA_TYPE_APLIC,
> + AIA_TYPE_APLIC_IMSIC,
> +} RISCVAIAType;
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -48,4 +69,12 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr, hwaddr size,
> uint32_t irq_chip,
> uint32_t msi_phandle,
> uint32_t iommu_sys_irq);
> +void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> + const MemMapEntry *pcie_ecam,
> + const MemMapEntry *pcie_pio,
> + 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);
> #endif
> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> index 7c862b0da2..e516898f9a 100644
> --- a/include/hw/riscv/virt.h
> +++ b/include/hw/riscv/virt.h
> @@ -121,21 +121,6 @@ enum {
> #define VIRT_PLIC_SIZE(__num_context) \
> (VIRT_PLIC_CONTEXT_BASE + (__num_context) * VIRT_PLIC_CONTEXT_STRIDE)
>
> -#define FDT_PCI_ADDR_CELLS 3
> -#define FDT_PCI_INT_CELLS 1
> -#define FDT_PLIC_ADDR_CELLS 0
> -#define FDT_PLIC_INT_CELLS 1
> -#define FDT_APLIC_INT_CELLS 2
> -#define FDT_APLIC_ADDR_CELLS 0
> -#define FDT_IMSIC_INT_CELLS 0
> -#define FDT_MAX_INT_CELLS 2
> -#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> - 1 + FDT_MAX_INT_CELLS)
> -#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> - 1 + FDT_PLIC_INT_CELLS)
> -#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
> - 1 + FDT_APLIC_INT_CELLS)
> -
> bool virt_is_acpi_enabled(RISCVVirtState *s);
> bool virt_is_iommu_sys_enabled(RISCVVirtState *s);
> void virt_acpi_setup(RISCVVirtState *vms);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
2026-08-28 20:39 ` [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
@ 2026-08-29 3:08 ` Chao Liu via qemu development
2026-09-01 4:51 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:08 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:08PM +0800, Daniel Henrique Barboza wrote:
> 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 <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 98 ++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 108 +++++-----------------------------
> include/hw/riscv/fdt-common.h | 21 +++++++
> 3 files changed, 133 insertions(+), 94 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 38813b6aa7..ae24ad0011 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 *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size)
> @@ -495,3 +497,99 @@ void riscv_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;
> + g_autofree uint32_t *imsic_cells = NULL;
> + g_autofree uint32_t *imsic_regs = NULL;
> + uint32_t imsic_max_hart_per_socket = 0;
> + static const char * const imsic_compat[2] = {
> + "qemu,imsics", "riscv,imsics"
> + };
> +
> + imsic_cells = g_new0(uint32_t, props->smp_cpus * 2);
> + imsic_regs = g_new0(uint32_t, props->socket_count * 4);
> +
> + for (int 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);
> + }
> +
> + for (int socket = 0; socket < props->socket_count; socket++) {
> + hwaddr imsic_addr = base_addr + socket * props->imsic_group_max_size;
> + uint32_t imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) *
> + soc[socket].num_harts;
> +
> + imsic_regs[socket * 4 + 0] = cpu_to_be32(imsic_addr >> 32);
> + 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 riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
> + uint32_t *next_phandle, uint32_t *intc_phandles,
> + uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
> +{
> + if (next_phandle) {
> + *msi_m_phandle = (*next_phandle)++;
> + *msi_s_phandle = (*next_phandle)++;
> + } else {
> + *msi_m_phandle = qemu_fdt_alloc_phandle(fdt);
> + *msi_s_phandle = qemu_fdt_alloc_phandle(fdt);
> + }
> +
> + 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 a28e6d200a..468ec90696 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -320,98 +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_size;
> - hwaddr imsic_addr;
> - 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] = cpu_to_be32(imsic_addr >> 32);
> - 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)
> {
> @@ -585,8 +493,20 @@ static void create_fdt_sockets(RISCVVirtState *s,
> }
>
> if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - create_fdt_imsic(s, phandle, intc_phandles,
> - &msi_m_phandle, &msi_s_phandle);
> + 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
> + };
> +
> + riscv_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 3750230865..182c03d8ce 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,22 @@ 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 *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -77,4 +95,7 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> uint32_t irq_pcie_phandle,
> uint32_t msi_pcie_phandle,
> uint32_t iommu_sys_phandle, uint32_t pcie_irq);
> +void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
> + uint32_t *next_phandle, uint32_t *intc_phandles,
> + uint32_t *msi_m_phandle, uint32_t *msi_s_phandle);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
@ 2026-08-29 3:08 ` Chao Liu via qemu development
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:08 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:08PM +0800, Daniel Henrique Barboza wrote:
> 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 <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 98 ++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 108 +++++-----------------------------
> include/hw/riscv/fdt-common.h | 21 +++++++
> 3 files changed, 133 insertions(+), 94 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 38813b6aa7..ae24ad0011 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 *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size)
> @@ -495,3 +497,99 @@ void riscv_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;
> + g_autofree uint32_t *imsic_cells = NULL;
> + g_autofree uint32_t *imsic_regs = NULL;
> + uint32_t imsic_max_hart_per_socket = 0;
> + static const char * const imsic_compat[2] = {
> + "qemu,imsics", "riscv,imsics"
> + };
> +
> + imsic_cells = g_new0(uint32_t, props->smp_cpus * 2);
> + imsic_regs = g_new0(uint32_t, props->socket_count * 4);
> +
> + for (int 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);
> + }
> +
> + for (int socket = 0; socket < props->socket_count; socket++) {
> + hwaddr imsic_addr = base_addr + socket * props->imsic_group_max_size;
> + uint32_t imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) *
> + soc[socket].num_harts;
> +
> + imsic_regs[socket * 4 + 0] = cpu_to_be32(imsic_addr >> 32);
> + 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 riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
> + uint32_t *next_phandle, uint32_t *intc_phandles,
> + uint32_t *msi_m_phandle, uint32_t *msi_s_phandle)
> +{
> + if (next_phandle) {
> + *msi_m_phandle = (*next_phandle)++;
> + *msi_s_phandle = (*next_phandle)++;
> + } else {
> + *msi_m_phandle = qemu_fdt_alloc_phandle(fdt);
> + *msi_s_phandle = qemu_fdt_alloc_phandle(fdt);
> + }
> +
> + 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 a28e6d200a..468ec90696 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -320,98 +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_size;
> - hwaddr imsic_addr;
> - 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] = cpu_to_be32(imsic_addr >> 32);
> - 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)
> {
> @@ -585,8 +493,20 @@ static void create_fdt_sockets(RISCVVirtState *s,
> }
>
> if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - create_fdt_imsic(s, phandle, intc_phandles,
> - &msi_m_phandle, &msi_s_phandle);
> + 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
> + };
> +
> + riscv_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 3750230865..182c03d8ce 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,22 @@ 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 *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -77,4 +95,7 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> uint32_t irq_pcie_phandle,
> uint32_t msi_pcie_phandle,
> uint32_t iommu_sys_phandle, uint32_t pcie_irq);
> +void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
> + uint32_t *next_phandle, uint32_t *intc_phandles,
> + uint32_t *msi_m_phandle, uint32_t *msi_s_phandle);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
2026-08-28 20:39 ` [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
@ 2026-08-29 3:09 ` Chao Liu via qemu development
2026-09-01 5:14 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:09 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:09PM +0800, Daniel Henrique Barboza wrote:
> Similar to what we did with 'imsic' in the previous patch, including
> creating a helper struct to encapsulate the extra arguments required to
> create the FDT.
>
> TODO: I believe the tt-atlantis board can use this same helper too. We
> just need to verify how to map the phandles used by it and what the
> helper is using (which was inherited by the 'virt' board).
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 109 ++++++++++++++++++++++++++
> hw/riscv/virt.c | 139 ++++++----------------------------
> include/hw/riscv/fdt-common.h | 19 +++++
> 3 files changed, 151 insertions(+), 116 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index ae24ad0011..d815c5adff 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -11,6 +11,7 @@
> #include "qemu/error-report.h"
> #include "system/device_tree.h"
> #include "hw/core/boards.h"
> +#include "hw/core/sysbus-fdt.h"
> #include "hw/riscv/fdt-common.h"
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> @@ -593,3 +594,111 @@ void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
> imsic_num_bits(props->aia_guests + 1));
>
> }
> +
> +/* Caller must free string after use */
> +static char *fdt_get_aplic_nodename(hwaddr aplic_addr)
> +{
> + return g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIx,
> + aplic_addr);
> +}
> +
> +static void create_fdt_one_aplic(void *fdt, APLICFdtProps *props,
> + hwaddr aplic_addr, uint32_t aplic_size,
> + uint32_t msi_phandle,
> + uint32_t *intc_phandles,
> + uint32_t aplic_phandle,
> + uint32_t aplic_child_phandle,
> + bool m_mode)
> +{
> + g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> + g_autofree uint32_t *aplic_cells = g_new0(uint32_t, props->num_harts * 2);
> + static const char * const aplic_compat[2] = {
> + "qemu,aplic", "riscv,aplic"
> + };
> +
> + for (int cpu = 0; cpu < props->num_harts; cpu++) {
> + aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
> + }
> +
> + qemu_fdt_add_subnode(fdt, aplic_name);
> + qemu_fdt_setprop_string_array(fdt, aplic_name, "compatible",
> + (char **)&aplic_compat,
> + ARRAY_SIZE(aplic_compat));
> + qemu_fdt_setprop_cell(fdt, aplic_name, "#address-cells",
> + FDT_APLIC_ADDR_CELLS);
> + qemu_fdt_setprop_cell(fdt, aplic_name,
> + "#interrupt-cells", FDT_APLIC_INT_CELLS);
> + qemu_fdt_setprop(fdt, aplic_name, "interrupt-controller", NULL, 0);
> +
> + if (props->aia_type == AIA_TYPE_APLIC) {
> + qemu_fdt_setprop(fdt, aplic_name, "interrupts-extended",
> + aplic_cells, props->num_harts * sizeof(uint32_t) * 2);
> + } else {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "msi-parent", msi_phandle);
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, aplic_name, "reg",
> + 2, aplic_addr, 2, aplic_size);
> + qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,num-sources",
> + props->irqchip_num_sources);
> +
> + if (aplic_child_phandle) {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,children",
> + aplic_child_phandle);
> + qemu_fdt_setprop_cells(fdt, aplic_name, "riscv,delegation",
> + aplic_child_phandle, 0x1,
> + props->irqchip_num_sources);
> + }
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "numa-node-id", props->socket);
> + }
> +
> + qemu_fdt_setprop_cell(fdt, aplic_name, "phandle", aplic_phandle);
> +}
> +
> +void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> + uint32_t msi_m_phandle,
> + uint32_t msi_s_phandle,
> + uint32_t *next_phandle,
> + uint32_t *intc_phandles,
> + uint32_t *aplic_phandles)
> +{
> + uint32_t aplic_m_phandle, aplic_s_phandle;
> + hwaddr aplic_addr;
> +
> + if (next_phandle) {
> + aplic_m_phandle = (*next_phandle)++;
> + aplic_s_phandle = (*next_phandle)++;
> + } else {
> + aplic_m_phandle = qemu_fdt_alloc_phandle(fdt);
> + aplic_s_phandle = qemu_fdt_alloc_phandle(fdt);
> + }
> +
> + if (props->aplic_m) {
> + /* M-level APLIC node */
> + aplic_addr = props->aplic_m->base + (props->aplic_m->size * props->socket);
> + create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_m->size,
> + msi_m_phandle, intc_phandles,
> + aplic_m_phandle, aplic_s_phandle,
> + true);
> + }
> +
> + /* S-level APLIC node */
> + aplic_addr = props->aplic_s->base + (props->aplic_s->size * props->socket);
> + create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_s->size,
> + msi_s_phandle, intc_phandles,
> + aplic_s_phandle, 0,
> + false);
> +
> + if (!props->socket && props->platform_bus_irq) {
> + g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> + platform_bus_add_all_fdt_nodes(fdt, aplic_name,
> + props->platform_bus->base,
> + props->platform_bus->size,
> + props->platform_bus_irq);
> + }
> +
> + aplic_phandles[props->socket] = aplic_s_phandle;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 468ec90696..a6ec9def16 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -320,113 +320,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
> }
> }
>
> -/* Caller must free string after use */
> -static char *fdt_get_aplic_nodename(unsigned long aplic_addr)
> -{
> - return g_strdup_printf("/soc/interrupt-controller@%lx", aplic_addr);
> -}
> -
> -static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
> - unsigned long aplic_addr, uint32_t aplic_size,
> - uint32_t msi_phandle,
> - uint32_t *intc_phandles,
> - uint32_t aplic_phandle,
> - uint32_t aplic_child_phandle,
> - bool m_mode, int num_harts)
> -{
> - int cpu;
> - g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> - g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts * 2);
> - MachineState *ms = MACHINE(s);
> - static const char * const aplic_compat[2] = {
> - "qemu,aplic", "riscv,aplic"
> - };
> -
> - for (cpu = 0; cpu < num_harts; cpu++) {
> - aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
> - }
> -
> - qemu_fdt_add_subnode(ms->fdt, aplic_name);
> - qemu_fdt_setprop_string_array(ms->fdt, aplic_name, "compatible",
> - (char **)&aplic_compat,
> - ARRAY_SIZE(aplic_compat));
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "#address-cells",
> - FDT_APLIC_ADDR_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name,
> - "#interrupt-cells", FDT_APLIC_INT_CELLS);
> - qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
> -
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
> - qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
> - aplic_cells, num_harts * sizeof(uint32_t) * 2);
> - } else {
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_phandle);
> - }
> -
> - qemu_fdt_setprop_sized_cells(ms->fdt, aplic_name, "reg",
> - 2, aplic_addr, 2, aplic_size);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
> - VIRT_IRQCHIP_NUM_SOURCES);
> -
> - if (aplic_child_phandle) {
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
> - aplic_child_phandle);
> - qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegation",
> - aplic_child_phandle, 0x1,
> - VIRT_IRQCHIP_NUM_SOURCES);
> - }
> -
> - riscv_socket_fdt_write_id(ms, aplic_name, socket);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_phandle);
> -}
> -
> -static void create_fdt_socket_aplic(RISCVVirtState *s,
> - int socket,
> - uint32_t msi_m_phandle,
> - uint32_t msi_s_phandle,
> - uint32_t *phandle,
> - uint32_t *intc_phandles,
> - uint32_t *aplic_phandles,
> - int num_harts)
> -{
> - unsigned long aplic_addr;
> - MachineState *ms = MACHINE(s);
> - uint32_t aplic_m_phandle, aplic_s_phandle;
> -
> - aplic_m_phandle = (*phandle)++;
> - aplic_s_phandle = (*phandle)++;
> -
> - if (!kvm_enabled()) {
> - /* M-level APLIC node */
> - aplic_addr = s->memmap[VIRT_APLIC_M].base +
> - (s->memmap[VIRT_APLIC_M].size * socket);
> - create_fdt_one_aplic(s, socket, aplic_addr,
> - s->memmap[VIRT_APLIC_M].size,
> - msi_m_phandle, intc_phandles,
> - aplic_m_phandle, aplic_s_phandle,
> - true, num_harts);
> - }
> -
> - /* S-level APLIC node */
> - aplic_addr = s->memmap[VIRT_APLIC_S].base +
> - (s->memmap[VIRT_APLIC_S].size * socket);
> - create_fdt_one_aplic(s, socket, aplic_addr, s->memmap[VIRT_APLIC_S].size,
> - msi_s_phandle, intc_phandles,
> - aplic_s_phandle, 0,
> - false, num_harts);
> -
> - if (!socket) {
> - g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> - platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
> - s->memmap[VIRT_PLATFORM_BUS].base,
> - s->memmap[VIRT_PLATFORM_BUS].size,
> - VIRT_PLATFORM_BUS_IRQ);
> - }
> -
> - aplic_phandles[socket] = aplic_s_phandle;
> -}
> -
> static void create_fdt_pmu(RISCVVirtState *s)
> {
> g_autofree char *pmu_name = g_strdup_printf("/pmu");
> @@ -453,6 +346,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> int socket_count = riscv_socket_count(ms);
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
> + APLICFdtProps aplic_props;
>
> riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
> @@ -510,15 +404,26 @@ static void create_fdt_sockets(RISCVVirtState *s,
> *msi_pcie_phandle = msi_s_phandle;
> }
>
> + if (s->aia_type != VIRT_AIA_TYPE_NONE) {
> + aplic_props.aplic_m = !kvm_enabled() ? &s->memmap[VIRT_APLIC_M] : NULL;
> + aplic_props.aplic_s = &s->memmap[VIRT_APLIC_S];
> + aplic_props.platform_bus = &s->memmap[VIRT_PLATFORM_BUS];
> + aplic_props.platform_bus_irq = VIRT_PLATFORM_BUS_IRQ;
> + aplic_props.socket = 0;
> + aplic_props.num_harts = ms->smp.cpus;
> + aplic_props.numa_enabled = numa_enabled;
> + aplic_props.irqchip_num_sources = VIRT_IRQCHIP_NUM_SOURCES;
> + aplic_props.aia_type = s->aia_type;
> + }
> +
> /*
> * With KVM AIA aplic-imsic, using an irqchip without split
> * mode, we'll use only one APLIC instance.
> */
> if (!virt_use_emulated_aplic(s->aia_type)) {
> - create_fdt_socket_aplic(s, 0,
> - msi_m_phandle, msi_s_phandle, phandle,
> - &intc_phandles[0], xplic_phandles,
> - ms->smp.cpus);
> + riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
> + msi_m_phandle, msi_s_phandle, phandle,
> + &intc_phandles[0], xplic_phandles);
>
> *irq_mmio_phandle = xplic_phandles[0];
> *irq_virtio_phandle = xplic_phandles[0];
> @@ -533,11 +438,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
> &intc_phandles[phandle_pos],
> xplic_phandles);
> } else {
> - create_fdt_socket_aplic(s, socket,
> - msi_m_phandle, msi_s_phandle, phandle,
> - &intc_phandles[phandle_pos],
> - xplic_phandles,
> - s->soc[socket].num_harts);
> + aplic_props.socket = socket;
> + aplic_props.num_harts = s->soc[socket].num_harts;
> + riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
> + msi_m_phandle, msi_s_phandle,
> + phandle,
> + &intc_phandles[phandle_pos],
> + xplic_phandles);
> }
> }
>
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index 182c03d8ce..8207cfee7b 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -12,6 +12,7 @@
> #include "target/riscv/cpu.h"
> #include "hw/core/boards.h"
> #include "hw/riscv/riscv_hart.h"
> +#include "exec/hwaddr.h"
>
> #define FDT_PCI_ADDR_CELLS 3
> #define FDT_PCI_INT_CELLS 1
> @@ -50,6 +51,18 @@ typedef struct IMSICFdtProps {
> int aia_guests;
> } IMSICFdtProps;
>
> +typedef struct APLICFdtProps {
> + const MemMapEntry *aplic_m;
> + const MemMapEntry *aplic_s;
> + const MemMapEntry *platform_bus;
> + int platform_bus_irq;
> + int socket;
> + int num_harts;
> + bool numa_enabled;
> + int irqchip_num_sources;
> + int aia_type;
> +} APLICFdtProps;
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -98,4 +111,10 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
> uint32_t *next_phandle, uint32_t *intc_phandles,
> uint32_t *msi_m_phandle, uint32_t *msi_s_phandle);
> +void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> + uint32_t msi_m_phandle,
> + uint32_t msi_s_phandle,
> + uint32_t *next_phandle,
> + uint32_t *intc_phandles,
> + uint32_t *aplic_phandles);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
@ 2026-08-29 3:09 ` Chao Liu via qemu development
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:09 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:09PM +0800, Daniel Henrique Barboza wrote:
> Similar to what we did with 'imsic' in the previous patch, including
> creating a helper struct to encapsulate the extra arguments required to
> create the FDT.
>
> TODO: I believe the tt-atlantis board can use this same helper too. We
> just need to verify how to map the phandles used by it and what the
> helper is using (which was inherited by the 'virt' board).
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 109 ++++++++++++++++++++++++++
> hw/riscv/virt.c | 139 ++++++----------------------------
> include/hw/riscv/fdt-common.h | 19 +++++
> 3 files changed, 151 insertions(+), 116 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index ae24ad0011..d815c5adff 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -11,6 +11,7 @@
> #include "qemu/error-report.h"
> #include "system/device_tree.h"
> #include "hw/core/boards.h"
> +#include "hw/core/sysbus-fdt.h"
> #include "hw/riscv/fdt-common.h"
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> @@ -593,3 +594,111 @@ void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
> imsic_num_bits(props->aia_guests + 1));
>
> }
> +
> +/* Caller must free string after use */
> +static char *fdt_get_aplic_nodename(hwaddr aplic_addr)
> +{
> + return g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIx,
> + aplic_addr);
> +}
> +
> +static void create_fdt_one_aplic(void *fdt, APLICFdtProps *props,
> + hwaddr aplic_addr, uint32_t aplic_size,
> + uint32_t msi_phandle,
> + uint32_t *intc_phandles,
> + uint32_t aplic_phandle,
> + uint32_t aplic_child_phandle,
> + bool m_mode)
> +{
> + g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> + g_autofree uint32_t *aplic_cells = g_new0(uint32_t, props->num_harts * 2);
> + static const char * const aplic_compat[2] = {
> + "qemu,aplic", "riscv,aplic"
> + };
> +
> + for (int cpu = 0; cpu < props->num_harts; cpu++) {
> + aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
> + }
> +
> + qemu_fdt_add_subnode(fdt, aplic_name);
> + qemu_fdt_setprop_string_array(fdt, aplic_name, "compatible",
> + (char **)&aplic_compat,
> + ARRAY_SIZE(aplic_compat));
> + qemu_fdt_setprop_cell(fdt, aplic_name, "#address-cells",
> + FDT_APLIC_ADDR_CELLS);
> + qemu_fdt_setprop_cell(fdt, aplic_name,
> + "#interrupt-cells", FDT_APLIC_INT_CELLS);
> + qemu_fdt_setprop(fdt, aplic_name, "interrupt-controller", NULL, 0);
> +
> + if (props->aia_type == AIA_TYPE_APLIC) {
> + qemu_fdt_setprop(fdt, aplic_name, "interrupts-extended",
> + aplic_cells, props->num_harts * sizeof(uint32_t) * 2);
> + } else {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "msi-parent", msi_phandle);
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, aplic_name, "reg",
> + 2, aplic_addr, 2, aplic_size);
> + qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,num-sources",
> + props->irqchip_num_sources);
> +
> + if (aplic_child_phandle) {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,children",
> + aplic_child_phandle);
> + qemu_fdt_setprop_cells(fdt, aplic_name, "riscv,delegation",
> + aplic_child_phandle, 0x1,
> + props->irqchip_num_sources);
> + }
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "numa-node-id", props->socket);
> + }
> +
> + qemu_fdt_setprop_cell(fdt, aplic_name, "phandle", aplic_phandle);
> +}
> +
> +void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> + uint32_t msi_m_phandle,
> + uint32_t msi_s_phandle,
> + uint32_t *next_phandle,
> + uint32_t *intc_phandles,
> + uint32_t *aplic_phandles)
> +{
> + uint32_t aplic_m_phandle, aplic_s_phandle;
> + hwaddr aplic_addr;
> +
> + if (next_phandle) {
> + aplic_m_phandle = (*next_phandle)++;
> + aplic_s_phandle = (*next_phandle)++;
> + } else {
> + aplic_m_phandle = qemu_fdt_alloc_phandle(fdt);
> + aplic_s_phandle = qemu_fdt_alloc_phandle(fdt);
> + }
> +
> + if (props->aplic_m) {
> + /* M-level APLIC node */
> + aplic_addr = props->aplic_m->base + (props->aplic_m->size * props->socket);
> + create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_m->size,
> + msi_m_phandle, intc_phandles,
> + aplic_m_phandle, aplic_s_phandle,
> + true);
> + }
> +
> + /* S-level APLIC node */
> + aplic_addr = props->aplic_s->base + (props->aplic_s->size * props->socket);
> + create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_s->size,
> + msi_s_phandle, intc_phandles,
> + aplic_s_phandle, 0,
> + false);
> +
> + if (!props->socket && props->platform_bus_irq) {
> + g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> + platform_bus_add_all_fdt_nodes(fdt, aplic_name,
> + props->platform_bus->base,
> + props->platform_bus->size,
> + props->platform_bus_irq);
> + }
> +
> + aplic_phandles[props->socket] = aplic_s_phandle;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 468ec90696..a6ec9def16 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -320,113 +320,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
> }
> }
>
> -/* Caller must free string after use */
> -static char *fdt_get_aplic_nodename(unsigned long aplic_addr)
> -{
> - return g_strdup_printf("/soc/interrupt-controller@%lx", aplic_addr);
> -}
> -
> -static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
> - unsigned long aplic_addr, uint32_t aplic_size,
> - uint32_t msi_phandle,
> - uint32_t *intc_phandles,
> - uint32_t aplic_phandle,
> - uint32_t aplic_child_phandle,
> - bool m_mode, int num_harts)
> -{
> - int cpu;
> - g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> - g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts * 2);
> - MachineState *ms = MACHINE(s);
> - static const char * const aplic_compat[2] = {
> - "qemu,aplic", "riscv,aplic"
> - };
> -
> - for (cpu = 0; cpu < num_harts; cpu++) {
> - aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT : IRQ_S_EXT);
> - }
> -
> - qemu_fdt_add_subnode(ms->fdt, aplic_name);
> - qemu_fdt_setprop_string_array(ms->fdt, aplic_name, "compatible",
> - (char **)&aplic_compat,
> - ARRAY_SIZE(aplic_compat));
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "#address-cells",
> - FDT_APLIC_ADDR_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name,
> - "#interrupt-cells", FDT_APLIC_INT_CELLS);
> - qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0);
> -
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
> - qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
> - aplic_cells, num_harts * sizeof(uint32_t) * 2);
> - } else {
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", msi_phandle);
> - }
> -
> - qemu_fdt_setprop_sized_cells(ms->fdt, aplic_name, "reg",
> - 2, aplic_addr, 2, aplic_size);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
> - VIRT_IRQCHIP_NUM_SOURCES);
> -
> - if (aplic_child_phandle) {
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
> - aplic_child_phandle);
> - qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegation",
> - aplic_child_phandle, 0x1,
> - VIRT_IRQCHIP_NUM_SOURCES);
> - }
> -
> - riscv_socket_fdt_write_id(ms, aplic_name, socket);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_phandle);
> -}
> -
> -static void create_fdt_socket_aplic(RISCVVirtState *s,
> - int socket,
> - uint32_t msi_m_phandle,
> - uint32_t msi_s_phandle,
> - uint32_t *phandle,
> - uint32_t *intc_phandles,
> - uint32_t *aplic_phandles,
> - int num_harts)
> -{
> - unsigned long aplic_addr;
> - MachineState *ms = MACHINE(s);
> - uint32_t aplic_m_phandle, aplic_s_phandle;
> -
> - aplic_m_phandle = (*phandle)++;
> - aplic_s_phandle = (*phandle)++;
> -
> - if (!kvm_enabled()) {
> - /* M-level APLIC node */
> - aplic_addr = s->memmap[VIRT_APLIC_M].base +
> - (s->memmap[VIRT_APLIC_M].size * socket);
> - create_fdt_one_aplic(s, socket, aplic_addr,
> - s->memmap[VIRT_APLIC_M].size,
> - msi_m_phandle, intc_phandles,
> - aplic_m_phandle, aplic_s_phandle,
> - true, num_harts);
> - }
> -
> - /* S-level APLIC node */
> - aplic_addr = s->memmap[VIRT_APLIC_S].base +
> - (s->memmap[VIRT_APLIC_S].size * socket);
> - create_fdt_one_aplic(s, socket, aplic_addr, s->memmap[VIRT_APLIC_S].size,
> - msi_s_phandle, intc_phandles,
> - aplic_s_phandle, 0,
> - false, num_harts);
> -
> - if (!socket) {
> - g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr);
> - platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
> - s->memmap[VIRT_PLATFORM_BUS].base,
> - s->memmap[VIRT_PLATFORM_BUS].size,
> - VIRT_PLATFORM_BUS_IRQ);
> - }
> -
> - aplic_phandles[socket] = aplic_s_phandle;
> -}
> -
> static void create_fdt_pmu(RISCVVirtState *s)
> {
> g_autofree char *pmu_name = g_strdup_printf("/pmu");
> @@ -453,6 +346,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> int socket_count = riscv_socket_count(ms);
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
> + APLICFdtProps aplic_props;
>
> riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
> @@ -510,15 +404,26 @@ static void create_fdt_sockets(RISCVVirtState *s,
> *msi_pcie_phandle = msi_s_phandle;
> }
>
> + if (s->aia_type != VIRT_AIA_TYPE_NONE) {
> + aplic_props.aplic_m = !kvm_enabled() ? &s->memmap[VIRT_APLIC_M] : NULL;
> + aplic_props.aplic_s = &s->memmap[VIRT_APLIC_S];
> + aplic_props.platform_bus = &s->memmap[VIRT_PLATFORM_BUS];
> + aplic_props.platform_bus_irq = VIRT_PLATFORM_BUS_IRQ;
> + aplic_props.socket = 0;
> + aplic_props.num_harts = ms->smp.cpus;
> + aplic_props.numa_enabled = numa_enabled;
> + aplic_props.irqchip_num_sources = VIRT_IRQCHIP_NUM_SOURCES;
> + aplic_props.aia_type = s->aia_type;
> + }
> +
> /*
> * With KVM AIA aplic-imsic, using an irqchip without split
> * mode, we'll use only one APLIC instance.
> */
> if (!virt_use_emulated_aplic(s->aia_type)) {
> - create_fdt_socket_aplic(s, 0,
> - msi_m_phandle, msi_s_phandle, phandle,
> - &intc_phandles[0], xplic_phandles,
> - ms->smp.cpus);
> + riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
> + msi_m_phandle, msi_s_phandle, phandle,
> + &intc_phandles[0], xplic_phandles);
>
> *irq_mmio_phandle = xplic_phandles[0];
> *irq_virtio_phandle = xplic_phandles[0];
> @@ -533,11 +438,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
> &intc_phandles[phandle_pos],
> xplic_phandles);
> } else {
> - create_fdt_socket_aplic(s, socket,
> - msi_m_phandle, msi_s_phandle, phandle,
> - &intc_phandles[phandle_pos],
> - xplic_phandles,
> - s->soc[socket].num_harts);
> + aplic_props.socket = socket;
> + aplic_props.num_harts = s->soc[socket].num_harts;
> + riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
> + msi_m_phandle, msi_s_phandle,
> + phandle,
> + &intc_phandles[phandle_pos],
> + xplic_phandles);
> }
> }
>
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index 182c03d8ce..8207cfee7b 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -12,6 +12,7 @@
> #include "target/riscv/cpu.h"
> #include "hw/core/boards.h"
> #include "hw/riscv/riscv_hart.h"
> +#include "exec/hwaddr.h"
>
> #define FDT_PCI_ADDR_CELLS 3
> #define FDT_PCI_INT_CELLS 1
> @@ -50,6 +51,18 @@ typedef struct IMSICFdtProps {
> int aia_guests;
> } IMSICFdtProps;
>
> +typedef struct APLICFdtProps {
> + const MemMapEntry *aplic_m;
> + const MemMapEntry *aplic_s;
> + const MemMapEntry *platform_bus;
> + int platform_bus_irq;
> + int socket;
> + int num_harts;
> + bool numa_enabled;
> + int irqchip_num_sources;
> + int aia_type;
> +} APLICFdtProps;
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -98,4 +111,10 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type, bool has_iommu_sys,
> void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
> uint32_t *next_phandle, uint32_t *intc_phandles,
> uint32_t *msi_m_phandle, uint32_t *msi_s_phandle);
> +void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> + uint32_t msi_m_phandle,
> + uint32_t msi_s_phandle,
> + uint32_t *next_phandle,
> + uint32_t *intc_phandles,
> + uint32_t *aplic_phandles);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename
2026-08-28 20:39 ` [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename Daniel Henrique Barboza
@ 2026-08-29 3:10 ` Chao Liu
2026-09-01 5:15 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu @ 2026-08-29 3:10 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
qemu-stable, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:10PM +0800, Daniel Henrique Barboza wrote:
> Running 'dtc' to generate a readable fdt for the virt machine produce
> warnings:
>
> $ dtc -I dtb -O dts virt.dtb > virt.dts
> <stdout>: Warning (simple_bus_reg): /soc/mtimer@2000000: simple-bus unit address format error, expected "2007ff8"
> <stdout>: Warning (simple_bus_reg): /soc/mtimer@2008000: simple-bus unit address format error, expected "200fff8"
>
> This happens because the 'reg' field does not match the address in the
> nodename. The right fix, pointed out by Chao in [1], is to make the
> nodename match the reg value:
>
> "In the current QEMU implement, `addr` is the MTIMECMP base address,
> while the MTIME register is located at addr + RISCV_ACLINT_DEFAULT_MTIME."
>
> In other words, the 'reg' value is correct but the nodename isn't.
>
> We'll make the fix now, allowing the next patch to move the fixed version
> of aclint FDT to fdt-common.
>
> [1] https://lore.kernel.org/qemu-devel/apHH1upnh8udUUT-@ChaodeMacBook-Pro.local/
>
> Cc: qemu-stable@nongnu.org
> Suggested-by: Chao Liu <chao.liu@processmission.com>
> Fixes: 954886ea6d ("hw/riscv: virt: Add optional ACLINT support to virt machine")
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/virt.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index a6ec9def16..83a4b7710d 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -234,7 +234,8 @@ static void create_fdt_socket_aclint(RISCVVirtState *s,
> (s->memmap[VIRT_CLINT].size * socket);
> size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
> }
> - name = g_strdup_printf("/soc/mtimer@%lx", addr);
> + name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> + addr + RISCV_ACLINT_DEFAULT_MTIME);
> qemu_fdt_add_subnode(ms->fdt, name);
> qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> "riscv,aclint-mtimer");
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
2026-08-28 20:39 ` [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
@ 2026-08-29 3:10 ` Chao Liu via qemu development
2026-09-01 5:17 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:10 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:11PM +0800, Daniel Henrique Barboza wrote:
> Yet another FDT that we want to move to a helper to avoid copy/pasting
> code to other boards that will use a mtimer. In particular the future
> 'riscv-server-ref' board.
>
> No FDT changes made.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 97 ++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 102 ++++------------------------------
> include/hw/riscv/fdt-common.h | 11 ++++
> 3 files changed, 120 insertions(+), 90 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d815c5adff..d2ce93ad28 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -16,6 +16,7 @@
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/intc/riscv_aclint.h"
> #include "hw/intc/riscv_imsic.h"
> #include "hw/pci/pci.h"
> #include "hw/pci/pcie_host.h"
> @@ -702,3 +703,99 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
>
> aplic_phandles[props->socket] = aplic_s_phandle;
> }
> +
> +void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> + uint32_t *intc_phandles)
> +{
> + uint32_t aclint_cells_size = props->num_harts * sizeof(uint32_t) * 2;
> + g_autofree uint32_t *aclint_mswi_cells = NULL;
> + g_autofree uint32_t *aclint_sswi_cells = NULL;
> + g_autofree uint32_t *aclint_mtimer_cells = NULL;
> + hwaddr addr, size;
> + char *name;
> + int cpu;
> +
> + aclint_mswi_cells = g_new0(uint32_t, props->num_harts * 2);
> + aclint_mtimer_cells = g_new0(uint32_t, props->num_harts * 2);
> + aclint_sswi_cells = g_new0(uint32_t, props->num_harts * 2);
> +
> + for (cpu = 0; cpu < props->num_harts; cpu++) {
> + aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
> + aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
> + aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
> + }
> +
> + if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
> + addr = props->clint->base + (props->clint->size * props->socket);
> + name = g_strdup_printf("/soc/mswi@%"HWADDR_PRIx, addr);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "riscv,aclint-mswi");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_mswi_cells, aclint_cells_size);
> + qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
> + }
> +
> + g_free(name);
> + }
> +
> + if (props->aia_type == AIA_TYPE_APLIC_IMSIC) {
> + addr = props->clint->base +
> + (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * props->socket);
> + size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
> + } else {
> + addr = props->clint->base + RISCV_ACLINT_SWI_SIZE +
> + (props->clint->size * props->socket);
> + size = props->clint->size - RISCV_ACLINT_SWI_SIZE;
> + }
> +
> + name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> + addr + RISCV_ACLINT_DEFAULT_MTIME);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> + "riscv,aclint-mtimer");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> + 2, size - RISCV_ACLINT_DEFAULT_MTIME,
> + 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> + 2, RISCV_ACLINT_DEFAULT_MTIME);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_mtimer_cells, aclint_cells_size);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
> + }
> +
> + g_free(name);
> +
> + if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
> + addr = props->aclint_sswi->base
> + + (props->aclint_sswi->size * props->socket);
> +
> + name = g_strdup_printf("/soc/sswi@%"HWADDR_PRIx, addr);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> + "riscv,aclint-sswi");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr, 2, props->aclint_sswi->size);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_sswi_cells, aclint_cells_size);
> + qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
> + }
> +
> + g_free(name);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 83a4b7710d..717a01da8d 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -180,94 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
> sysmem);
> }
>
> -static void create_fdt_socket_aclint(RISCVVirtState *s,
> - int socket,
> - uint32_t *intc_phandles)
> -{
> - int cpu;
> - char *name;
> - unsigned long addr, size;
> - uint32_t aclint_cells_size;
> - g_autofree uint32_t *aclint_mswi_cells = NULL;
> - g_autofree uint32_t *aclint_sswi_cells = NULL;
> - g_autofree uint32_t *aclint_mtimer_cells = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
> - aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
> - aclint_sswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
> -
> - for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> - aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
> - aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
> - aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
> - }
> - aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2;
> -
> - if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_CLINT].base +
> - (s->memmap[VIRT_CLINT].size * socket);
> - name = g_strdup_printf("/soc/mswi@%lx", addr);
> -
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-mswi");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_mswi_cells, aclint_cells_size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> - }
> -
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_CLINT].base +
> - (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket);
> - size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
> - } else {
> - addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> - (s->memmap[VIRT_CLINT].size * socket);
> - size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
> - }
> - name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> - addr + RISCV_ACLINT_DEFAULT_MTIME);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-mtimer");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> - 2, size - RISCV_ACLINT_DEFAULT_MTIME,
> - 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> - 2, RISCV_ACLINT_DEFAULT_MTIME);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_mtimer_cells, aclint_cells_size);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> -
> - if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_ACLINT_SSWI].base +
> - (s->memmap[VIRT_ACLINT_SSWI].size * socket);
> -
> - name = g_strdup_printf("/soc/sswi@%lx", addr);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-sswi");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr, 2, s->memmap[VIRT_ACLINT_SSWI].size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_sswi_cells, aclint_cells_size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> - }
> -}
> -
> static void create_fdt_socket_plic(RISCVVirtState *s,
> int socket,
> uint32_t *phandle, uint32_t *intc_phandles,
> @@ -348,6 +260,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
> APLICFdtProps aplic_props;
> + ACLINTFdtProps aclint_props;
>
> riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
> @@ -355,6 +268,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
>
> intc_phandles = g_new0(uint32_t, ms->smp.cpus);
>
> + if (virt_aclint_allowed() && s->have_aclint) {
> + aclint_props.clint = &s->memmap[VIRT_CLINT];
> + aclint_props.aclint_sswi = &s->memmap[VIRT_ACLINT_SSWI];
> + aclint_props.aia_type = s->aia_type;
> + aclint_props.numa_enabled = numa_enabled;
> + }
> +
> phandle_pos = ms->smp.cpus;
> for (socket = (socket_count - 1); socket >= 0; socket--) {
> hwaddr memaddr = s->memmap[VIRT_DRAM].base +
> @@ -373,8 +293,10 @@ static void create_fdt_sockets(RISCVVirtState *s,
> socket, riscv_numa_enabled(ms));
>
> if (virt_aclint_allowed() && s->have_aclint) {
> - create_fdt_socket_aclint(s, socket,
> - &intc_phandles[phandle_pos]);
> + aclint_props.socket = socket;
> + aclint_props.num_harts = s->soc[socket].num_harts;
> + riscv_create_fdt_socket_aclint(ms->fdt, &aclint_props,
> + &intc_phandles[phandle_pos]);
> } else if (tcg_enabled()) {
> hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
> s->memmap[VIRT_CLINT].size * socket;
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index 8207cfee7b..a45b063f66 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -63,6 +63,15 @@ typedef struct APLICFdtProps {
> int aia_type;
> } APLICFdtProps;
>
> +typedef struct ACLINTFdtProps {
> + const MemMapEntry *clint;
> + const MemMapEntry *aclint_sswi;
> + int socket;
> + int num_harts;
> + int aia_type;
> + bool numa_enabled;
> +} ACLINTFdtProps;
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -117,4 +126,6 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> uint32_t *next_phandle,
> uint32_t *intc_phandles,
> uint32_t *aplic_phandles);
> +void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> + uint32_t *intc_phandles);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
@ 2026-08-29 3:10 ` Chao Liu via qemu development
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:10 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:11PM +0800, Daniel Henrique Barboza wrote:
> Yet another FDT that we want to move to a helper to avoid copy/pasting
> code to other boards that will use a mtimer. In particular the future
> 'riscv-server-ref' board.
>
> No FDT changes made.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 97 ++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 102 ++++------------------------------
> include/hw/riscv/fdt-common.h | 11 ++++
> 3 files changed, 120 insertions(+), 90 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d815c5adff..d2ce93ad28 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -16,6 +16,7 @@
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/intc/riscv_aclint.h"
> #include "hw/intc/riscv_imsic.h"
> #include "hw/pci/pci.h"
> #include "hw/pci/pcie_host.h"
> @@ -702,3 +703,99 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
>
> aplic_phandles[props->socket] = aplic_s_phandle;
> }
> +
> +void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> + uint32_t *intc_phandles)
> +{
> + uint32_t aclint_cells_size = props->num_harts * sizeof(uint32_t) * 2;
> + g_autofree uint32_t *aclint_mswi_cells = NULL;
> + g_autofree uint32_t *aclint_sswi_cells = NULL;
> + g_autofree uint32_t *aclint_mtimer_cells = NULL;
> + hwaddr addr, size;
> + char *name;
> + int cpu;
> +
> + aclint_mswi_cells = g_new0(uint32_t, props->num_harts * 2);
> + aclint_mtimer_cells = g_new0(uint32_t, props->num_harts * 2);
> + aclint_sswi_cells = g_new0(uint32_t, props->num_harts * 2);
> +
> + for (cpu = 0; cpu < props->num_harts; cpu++) {
> + aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
> + aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
> + aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
> + }
> +
> + if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
> + addr = props->clint->base + (props->clint->size * props->socket);
> + name = g_strdup_printf("/soc/mswi@%"HWADDR_PRIx, addr);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "riscv,aclint-mswi");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_mswi_cells, aclint_cells_size);
> + qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
> + }
> +
> + g_free(name);
> + }
> +
> + if (props->aia_type == AIA_TYPE_APLIC_IMSIC) {
> + addr = props->clint->base +
> + (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * props->socket);
> + size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
> + } else {
> + addr = props->clint->base + RISCV_ACLINT_SWI_SIZE +
> + (props->clint->size * props->socket);
> + size = props->clint->size - RISCV_ACLINT_SWI_SIZE;
> + }
> +
> + name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> + addr + RISCV_ACLINT_DEFAULT_MTIME);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> + "riscv,aclint-mtimer");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> + 2, size - RISCV_ACLINT_DEFAULT_MTIME,
> + 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> + 2, RISCV_ACLINT_DEFAULT_MTIME);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_mtimer_cells, aclint_cells_size);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
> + }
> +
> + g_free(name);
> +
> + if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
> + addr = props->aclint_sswi->base
> + + (props->aclint_sswi->size * props->socket);
> +
> + name = g_strdup_printf("/soc/sswi@%"HWADDR_PRIx, addr);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> + "riscv,aclint-sswi");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr, 2, props->aclint_sswi->size);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_sswi_cells, aclint_cells_size);
> + qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL, 0);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props->socket);
> + }
> +
> + g_free(name);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 83a4b7710d..717a01da8d 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -180,94 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
> sysmem);
> }
>
> -static void create_fdt_socket_aclint(RISCVVirtState *s,
> - int socket,
> - uint32_t *intc_phandles)
> -{
> - int cpu;
> - char *name;
> - unsigned long addr, size;
> - uint32_t aclint_cells_size;
> - g_autofree uint32_t *aclint_mswi_cells = NULL;
> - g_autofree uint32_t *aclint_sswi_cells = NULL;
> - g_autofree uint32_t *aclint_mtimer_cells = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
> - aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
> - aclint_sswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
> -
> - for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> - aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
> - aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
> - aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
> - }
> - aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2;
> -
> - if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_CLINT].base +
> - (s->memmap[VIRT_CLINT].size * socket);
> - name = g_strdup_printf("/soc/mswi@%lx", addr);
> -
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-mswi");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_mswi_cells, aclint_cells_size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> - }
> -
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_CLINT].base +
> - (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket);
> - size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
> - } else {
> - addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> - (s->memmap[VIRT_CLINT].size * socket);
> - size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
> - }
> - name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> - addr + RISCV_ACLINT_DEFAULT_MTIME);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-mtimer");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> - 2, size - RISCV_ACLINT_DEFAULT_MTIME,
> - 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> - 2, RISCV_ACLINT_DEFAULT_MTIME);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_mtimer_cells, aclint_cells_size);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> -
> - if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_ACLINT_SSWI].base +
> - (s->memmap[VIRT_ACLINT_SSWI].size * socket);
> -
> - name = g_strdup_printf("/soc/sswi@%lx", addr);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-sswi");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr, 2, s->memmap[VIRT_ACLINT_SSWI].size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_sswi_cells, aclint_cells_size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> - }
> -}
> -
> static void create_fdt_socket_plic(RISCVVirtState *s,
> int socket,
> uint32_t *phandle, uint32_t *intc_phandles,
> @@ -348,6 +260,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
> APLICFdtProps aplic_props;
> + ACLINTFdtProps aclint_props;
>
> riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc->harts[0]) :
> @@ -355,6 +268,13 @@ static void create_fdt_sockets(RISCVVirtState *s,
>
> intc_phandles = g_new0(uint32_t, ms->smp.cpus);
>
> + if (virt_aclint_allowed() && s->have_aclint) {
> + aclint_props.clint = &s->memmap[VIRT_CLINT];
> + aclint_props.aclint_sswi = &s->memmap[VIRT_ACLINT_SSWI];
> + aclint_props.aia_type = s->aia_type;
> + aclint_props.numa_enabled = numa_enabled;
> + }
> +
> phandle_pos = ms->smp.cpus;
> for (socket = (socket_count - 1); socket >= 0; socket--) {
> hwaddr memaddr = s->memmap[VIRT_DRAM].base +
> @@ -373,8 +293,10 @@ static void create_fdt_sockets(RISCVVirtState *s,
> socket, riscv_numa_enabled(ms));
>
> if (virt_aclint_allowed() && s->have_aclint) {
> - create_fdt_socket_aclint(s, socket,
> - &intc_phandles[phandle_pos]);
> + aclint_props.socket = socket;
> + aclint_props.num_harts = s->soc[socket].num_harts;
> + riscv_create_fdt_socket_aclint(ms->fdt, &aclint_props,
> + &intc_phandles[phandle_pos]);
> } else if (tcg_enabled()) {
> hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
> s->memmap[VIRT_CLINT].size * socket;
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index 8207cfee7b..a45b063f66 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -63,6 +63,15 @@ typedef struct APLICFdtProps {
> int aia_type;
> } APLICFdtProps;
>
> +typedef struct ACLINTFdtProps {
> + const MemMapEntry *clint;
> + const MemMapEntry *aclint_sswi;
> + int socket;
> + int num_harts;
> + int aia_type;
> + bool numa_enabled;
> +} ACLINTFdtProps;
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> @@ -117,4 +126,6 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> uint32_t *next_phandle,
> uint32_t *intc_phandles,
> uint32_t *aplic_phandles);
> +void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> + uint32_t *intc_phandles);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
2026-08-28 20:39 ` [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
@ 2026-08-29 3:11 ` Chao Liu via
2026-09-01 5:23 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:11 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:12PM +0800, Daniel Henrique Barboza wrote:
> Add a common uart FDT helper to be used by 'virt' and the future
> 'riscv-server-ref' board.
>
> The 'tt-atlantis' board is left out of this patch because it's going
> through UART related changes and its FDT might change soon, thus it's
> better to wait for the final DT to be determined and then we can
> evaluate whether it can share a common helper.
>
> The "/chosen" and "/alias" changes are UART0 only so we're keeping them
> out of the common helper. The board can set both manually as
> appropriate.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 29 +++++++++++++++++++++++++++++
> hw/riscv/virt.c | 35 +++++++++--------------------------
> include/hw/riscv/fdt-common.h | 5 +++++
> 3 files changed, 43 insertions(+), 26 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d2ce93ad28..0107aadaad 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -22,6 +22,8 @@
> #include "hw/pci/pcie_host.h"
> #include "hw/riscv/aia.h"
>
> +#define UART_STD_CLOCK_FREQ 3686400 /* 3.6864 MHz */
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size)
> {
> @@ -799,3 +801,30 @@ void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> g_free(name);
> }
> }
> +
> +char *riscv_fdt_get_uart_nodename(hwaddr addr)
> +{
> + return g_strdup_printf("/soc/serial@%"HWADDR_PRIx, addr);
> +}
> +
> +void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> + int uart_irq, int aia_type,
> + uint32_t irq_phandle)
> +{
> + g_autofree char *name = riscv_fdt_get_uart_nodename(uart_mem->base);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, uart_mem->base,
> + 2, uart_mem->size);
> +
> + qemu_fdt_setprop_cell(fdt, name, "clock-frequency", UART_STD_CLOCK_FREQ);
> + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle);
> +
> + if (aia_type == AIA_TYPE_NONE) {
> + qemu_fdt_setprop_cell(fdt, name, "interrupts", uart_irq);
> + } else {
> + qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq, 0x4);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 717a01da8d..3e40513dc1 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -418,39 +418,22 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
> }
> }
>
> -static void create_fdt_uart(RISCVVirtState *s,
> - uint32_t irq_mmio_phandle, int memId, int irqNo)
> +static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
> {
> g_autofree char *name = NULL;
> MachineState *ms = MACHINE(s);
>
> - name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx,
> - s->memmap[memId].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[memId].base,
> - 2, s->memmap[memId].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400);
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle);
> - if (s->aia_type == VIRT_AIA_TYPE_NONE) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", irqNo);
> - } else {
> - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqNo, 0x4);
> + if (s->uart1_present) {
> + riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART1],
> + UART1_IRQ, s->aia_type, irq_mmio_phandle);
> }
>
> - if (VIRT_UART0 == memId) {
> - qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
> - qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> - }
> -}
> + riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART0], UART0_IRQ,
> + s->aia_type, irq_mmio_phandle);
>
> -static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
> -{
> - if (s->uart1_present) {
> - create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ);
> - }
> - create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ);
> + name = riscv_fdt_get_uart_nodename(s->memmap[VIRT_UART0].base);
> + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
> + qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> }
>
> static void create_fdt_rtc(RISCVVirtState *s,
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index a45b063f66..c8b25348bd 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -128,4 +128,9 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> uint32_t *aplic_phandles);
> void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> uint32_t *intc_phandles);
> +/* Caller must free the returned string. */
> +char *riscv_fdt_get_uart_nodename(hwaddr addr);
> +void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> + int uart_irq, int aia_type,
> + uint32_t irq_phandle);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
@ 2026-08-29 3:11 ` Chao Liu via
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:11 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:12PM +0800, Daniel Henrique Barboza wrote:
> Add a common uart FDT helper to be used by 'virt' and the future
> 'riscv-server-ref' board.
>
> The 'tt-atlantis' board is left out of this patch because it's going
> through UART related changes and its FDT might change soon, thus it's
> better to wait for the final DT to be determined and then we can
> evaluate whether it can share a common helper.
>
> The "/chosen" and "/alias" changes are UART0 only so we're keeping them
> out of the common helper. The board can set both manually as
> appropriate.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 29 +++++++++++++++++++++++++++++
> hw/riscv/virt.c | 35 +++++++++--------------------------
> include/hw/riscv/fdt-common.h | 5 +++++
> 3 files changed, 43 insertions(+), 26 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d2ce93ad28..0107aadaad 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -22,6 +22,8 @@
> #include "hw/pci/pcie_host.h"
> #include "hw/riscv/aia.h"
>
> +#define UART_STD_CLOCK_FREQ 3686400 /* 3.6864 MHz */
> +
> void *riscv_create_board_device_tree(const char *model, const char *compatible,
> int *fdt_size)
> {
> @@ -799,3 +801,30 @@ void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> g_free(name);
> }
> }
> +
> +char *riscv_fdt_get_uart_nodename(hwaddr addr)
> +{
> + return g_strdup_printf("/soc/serial@%"HWADDR_PRIx, addr);
> +}
> +
> +void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> + int uart_irq, int aia_type,
> + uint32_t irq_phandle)
> +{
> + g_autofree char *name = riscv_fdt_get_uart_nodename(uart_mem->base);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, uart_mem->base,
> + 2, uart_mem->size);
> +
> + qemu_fdt_setprop_cell(fdt, name, "clock-frequency", UART_STD_CLOCK_FREQ);
> + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle);
> +
> + if (aia_type == AIA_TYPE_NONE) {
> + qemu_fdt_setprop_cell(fdt, name, "interrupts", uart_irq);
> + } else {
> + qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq, 0x4);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 717a01da8d..3e40513dc1 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -418,39 +418,22 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle)
> }
> }
>
> -static void create_fdt_uart(RISCVVirtState *s,
> - uint32_t irq_mmio_phandle, int memId, int irqNo)
> +static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
> {
> g_autofree char *name = NULL;
> MachineState *ms = MACHINE(s);
>
> - name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx,
> - s->memmap[memId].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[memId].base,
> - 2, s->memmap[memId].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400);
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle);
> - if (s->aia_type == VIRT_AIA_TYPE_NONE) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", irqNo);
> - } else {
> - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqNo, 0x4);
> + if (s->uart1_present) {
> + riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART1],
> + UART1_IRQ, s->aia_type, irq_mmio_phandle);
> }
>
> - if (VIRT_UART0 == memId) {
> - qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
> - qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> - }
> -}
> + riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART0], UART0_IRQ,
> + s->aia_type, irq_mmio_phandle);
>
> -static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
> -{
> - if (s->uart1_present) {
> - create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ);
> - }
> - create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ);
> + name = riscv_fdt_get_uart_nodename(s->memmap[VIRT_UART0].base);
> + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name);
> + qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> }
>
> static void create_fdt_rtc(RISCVVirtState *s,
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index a45b063f66..c8b25348bd 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -128,4 +128,9 @@ void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> uint32_t *aplic_phandles);
> void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props,
> uint32_t *intc_phandles);
> +/* Caller must free the returned string. */
> +char *riscv_fdt_get_uart_nodename(hwaddr addr);
> +void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> + int uart_irq, int aia_type,
> + uint32_t irq_phandle);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
2026-08-28 20:39 ` [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
@ 2026-08-29 3:12 ` Chao Liu via
2026-09-01 5:23 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:12 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:13PM +0800, Daniel Henrique Barboza wrote:
> The soon to be added 'riscv-server-ref' board will add a rtc FDT subnode
> that is similar to what the 'virt' board users. Put it into a helper to
> avoid copy/pasting code.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 21 +++++++++++++++++++++
> hw/riscv/virt.c | 26 ++------------------------
> include/hw/riscv/fdt-common.h | 3 +++
> 3 files changed, 26 insertions(+), 24 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 0107aadaad..ce2dcb43b4 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -828,3 +828,24 @@ void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq, 0x4);
> }
> }
> +
> +void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
> + int rtc_irq, int aia_type,
> + uint32_t irq_phandle)
> +{
> + g_autofree char *name = NULL;
> +
> + name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
> + rtc_mem->base);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, rtc_mem->base,
> + 2, rtc_mem->size);
> + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle);
> + if (aia_type == AIA_TYPE_NONE) {
> + qemu_fdt_setprop_cell(fdt, name, "interrupts", rtc_irq);
> + } else {
> + qemu_fdt_setprop_cells(fdt, name, "interrupts", rtc_irq, 0x4);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 3e40513dc1..ccea5784f0 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -436,29 +436,6 @@ static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
> qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> }
>
> -static void create_fdt_rtc(RISCVVirtState *s,
> - uint32_t irq_mmio_phandle)
> -{
> - g_autofree char *name = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
> - s->memmap[VIRT_RTC].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "google,goldfish-rtc");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[VIRT_RTC].base,
> - 2, s->memmap[VIRT_RTC].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
> - irq_mmio_phandle);
> - if (s->aia_type == VIRT_AIA_TYPE_NONE) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", RTC_IRQ);
> - } else {
> - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ, 0x4);
> - }
> -}
> -
> static void create_fdt_fw_cfg(RISCVVirtState *s)
> {
> MachineState *ms = MACHINE(s);
> @@ -566,7 +543,8 @@ static void finalize_fdt(RISCVVirtState *s)
>
> create_fdt_uarts(s, irq_mmio_phandle);
>
> - create_fdt_rtc(s, irq_mmio_phandle);
> + riscv_create_fdt_rtc(MACHINE(s)->fdt, &s->memmap[VIRT_RTC], RTC_IRQ,
> + s->aia_type, irq_mmio_phandle);
> }
>
> static void create_fdt(RISCVVirtState *s)
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index c8b25348bd..eb9db8278d 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -133,4 +133,7 @@ char *riscv_fdt_get_uart_nodename(hwaddr addr);
> void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> int uart_irq, int aia_type,
> uint32_t irq_phandle);
> +void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
> + int rtc_irq, int aia_type,
> + uint32_t irq_phandle);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
@ 2026-08-29 3:12 ` Chao Liu via
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:12 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:13PM +0800, Daniel Henrique Barboza wrote:
> The soon to be added 'riscv-server-ref' board will add a rtc FDT subnode
> that is similar to what the 'virt' board users. Put it into a helper to
> avoid copy/pasting code.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/fdt-common.c | 21 +++++++++++++++++++++
> hw/riscv/virt.c | 26 ++------------------------
> include/hw/riscv/fdt-common.h | 3 +++
> 3 files changed, 26 insertions(+), 24 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 0107aadaad..ce2dcb43b4 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -828,3 +828,24 @@ void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq, 0x4);
> }
> }
> +
> +void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
> + int rtc_irq, int aia_type,
> + uint32_t irq_phandle)
> +{
> + g_autofree char *name = NULL;
> +
> + name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
> + rtc_mem->base);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, rtc_mem->base,
> + 2, rtc_mem->size);
> + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle);
> + if (aia_type == AIA_TYPE_NONE) {
> + qemu_fdt_setprop_cell(fdt, name, "interrupts", rtc_irq);
> + } else {
> + qemu_fdt_setprop_cells(fdt, name, "interrupts", rtc_irq, 0x4);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 3e40513dc1..ccea5784f0 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -436,29 +436,6 @@ static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle)
> qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> }
>
> -static void create_fdt_rtc(RISCVVirtState *s,
> - uint32_t irq_mmio_phandle)
> -{
> - g_autofree char *name = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
> - s->memmap[VIRT_RTC].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "google,goldfish-rtc");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[VIRT_RTC].base,
> - 2, s->memmap[VIRT_RTC].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
> - irq_mmio_phandle);
> - if (s->aia_type == VIRT_AIA_TYPE_NONE) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", RTC_IRQ);
> - } else {
> - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ, 0x4);
> - }
> -}
> -
> static void create_fdt_fw_cfg(RISCVVirtState *s)
> {
> MachineState *ms = MACHINE(s);
> @@ -566,7 +543,8 @@ static void finalize_fdt(RISCVVirtState *s)
>
> create_fdt_uarts(s, irq_mmio_phandle);
>
> - create_fdt_rtc(s, irq_mmio_phandle);
> + riscv_create_fdt_rtc(MACHINE(s)->fdt, &s->memmap[VIRT_RTC], RTC_IRQ,
> + s->aia_type, irq_mmio_phandle);
> }
>
> static void create_fdt(RISCVVirtState *s)
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h
> index c8b25348bd..eb9db8278d 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -133,4 +133,7 @@ char *riscv_fdt_get_uart_nodename(hwaddr addr);
> void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> int uart_irq, int aia_type,
> uint32_t irq_phandle);
> +void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
> + int rtc_irq, int aia_type,
> + uint32_t irq_phandle);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
2026-08-28 20:39 ` [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
@ 2026-08-29 3:12 ` Chao Liu via qemu development
2026-09-01 5:24 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:12 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:14PM +0800, Daniel Henrique Barboza wrote:
> There will be code repetition instances added by the 'riscv-server-ref'
> board w.r.t device creation and initialization. Instead of waiting for
> that code to land we're adding helpers beforehand. The idea is to make
> the new board code shorter and more palatable for reviewers.
>
> A new 'device-common' file is created for such helpers. We'll start
> with the platform bus, a nice piece of software that only the 'virt'
> board uses so far, and the 'riscv-server-ref' will use to support TPM
> devices.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/device-common.c | 48 ++++++++++++++++++++++++++++++++
> hw/riscv/meson.build | 1 +
> hw/riscv/virt.c | 30 +++-----------------
> include/hw/riscv/device-common.h | 19 +++++++++++++
> 4 files changed, 72 insertions(+), 26 deletions(-)
> create mode 100644 hw/riscv/device-common.c
> create mode 100644 include/hw/riscv/device-common.h
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> new file mode 100644
> index 0000000000..d3c68a9e71
> --- /dev/null
> +++ b/hw/riscv/device-common.c
> @@ -0,0 +1,48 @@
> +/*
> + * RISC-V board helpers for FDT generation.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/riscv/device-common.h"
> +
> +#include "hw/core/platform-bus.h"
> +#include "hw/core/qdev.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/core/sysbus.h"
> +#include "qapi/error.h"
> +#include "system/address-spaces.h"
> +#include "system/memory.h"
> +
> +
> +DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> + const MemMapEntry *platform_bus_mem,
> + int platform_bus_base_irq,
> + int platform_bus_num_irqs)
> +{
> + MemoryRegion *sysmem = get_system_memory();
> + DeviceState *dev;
> + SysBusDevice *sysbus;
> +
> + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
> + dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
> + qdev_prop_set_uint32(dev, "num_irqs", platform_bus_num_irqs);
> + qdev_prop_set_uint32(dev, "mmio_size", platform_bus_mem->size);
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + sysbus = SYS_BUS_DEVICE(dev);
> + for (int i = 0; i < platform_bus_num_irqs; i++) {
> + int irq = platform_bus_base_irq + i;
> + sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
> + }
> +
> + memory_region_add_subregion(sysmem,
> + platform_bus_mem->base,
> + sysbus_mmio_get_region(sysbus, 0));
> +
> + return dev;
> +}
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 0d82ceacc4..7aa3c1578d 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -1,6 +1,7 @@
> riscv_ss = ss.source_set()
> riscv_ss.add(files('aia.c'))
> riscv_ss.add(files('boot.c'))
> +riscv_ss.add(files('device-common.c'))
> riscv_ss.add(files('fdt-common.c'))
> riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
> riscv_ss.add(files('riscv_hart.c'))
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index ccea5784f0..a2671ae341 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -35,6 +35,7 @@
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/virt.h"
> #include "hw/riscv/boot.h"
> +#include "hw/riscv/device-common.h"
> #include "hw/riscv/fdt-common.h"
> #include "hw/riscv/machines-qom.h"
> #include "hw/riscv/numa.h"
> @@ -683,31 +684,6 @@ static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket,
> memmap[VIRT_PLIC].size);
> }
>
> -static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
> -{
> - DeviceState *dev;
> - SysBusDevice *sysbus;
> - int i;
> - MemoryRegion *sysmem = get_system_memory();
> -
> - dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
> - dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
> - qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS);
> - qdev_prop_set_uint32(dev, "mmio_size", s->memmap[VIRT_PLATFORM_BUS].size);
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> - s->platform_bus_dev = dev;
> -
> - sysbus = SYS_BUS_DEVICE(dev);
> - for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) {
> - int irq = VIRT_PLATFORM_BUS_IRQ + i;
> - sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
> - }
> -
> - memory_region_add_subregion(sysmem,
> - s->memmap[VIRT_PLATFORM_BUS].base,
> - sysbus_mmio_get_region(sysbus, 0));
> -}
> -
> static void virt_build_smbios(RISCVVirtState *s)
> {
> MachineClass *mc = MACHINE_GET_CLASS(s);
> @@ -1030,7 +1006,9 @@ static void virt_machine_init(MachineState *machine)
>
> gpex_pcie_init(system_memory, pcie_irqchip, s);
>
> - create_platform_bus(s, mmio_irqchip);
> + s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
> + &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
> + VIRT_PLATFORM_BUS_NUM_IRQS);
>
> serial_mm_init(system_memory, s->memmap[VIRT_UART0].base,
> 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
> diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
> new file mode 100644
> index 0000000000..12af031bbf
> --- /dev/null
> +++ b/include/hw/riscv/device-common.h
> @@ -0,0 +1,19 @@
> +/*
> + * RISC-V board helpers for FDT generation.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef RISCV_DEVICE_COMMON_H
> +#define RISCV_DEVICE_COMMON_H
> +
> +#include "exec/hwaddr.h"
> +#include "hw/core/qdev.h"
> +
> +DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> + const MemMapEntry *platform_bus_mem,
> + int platform_bus_base_irq,
> + int platform_bus_num_irqs);
> +#endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
@ 2026-08-29 3:12 ` Chao Liu via qemu development
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:12 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:14PM +0800, Daniel Henrique Barboza wrote:
> There will be code repetition instances added by the 'riscv-server-ref'
> board w.r.t device creation and initialization. Instead of waiting for
> that code to land we're adding helpers beforehand. The idea is to make
> the new board code shorter and more palatable for reviewers.
>
> A new 'device-common' file is created for such helpers. We'll start
> with the platform bus, a nice piece of software that only the 'virt'
> board uses so far, and the 'riscv-server-ref' will use to support TPM
> devices.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/device-common.c | 48 ++++++++++++++++++++++++++++++++
> hw/riscv/meson.build | 1 +
> hw/riscv/virt.c | 30 +++-----------------
> include/hw/riscv/device-common.h | 19 +++++++++++++
> 4 files changed, 72 insertions(+), 26 deletions(-)
> create mode 100644 hw/riscv/device-common.c
> create mode 100644 include/hw/riscv/device-common.h
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> new file mode 100644
> index 0000000000..d3c68a9e71
> --- /dev/null
> +++ b/hw/riscv/device-common.c
> @@ -0,0 +1,48 @@
> +/*
> + * RISC-V board helpers for FDT generation.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/riscv/device-common.h"
> +
> +#include "hw/core/platform-bus.h"
> +#include "hw/core/qdev.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/core/sysbus.h"
> +#include "qapi/error.h"
> +#include "system/address-spaces.h"
> +#include "system/memory.h"
> +
> +
> +DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> + const MemMapEntry *platform_bus_mem,
> + int platform_bus_base_irq,
> + int platform_bus_num_irqs)
> +{
> + MemoryRegion *sysmem = get_system_memory();
> + DeviceState *dev;
> + SysBusDevice *sysbus;
> +
> + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
> + dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
> + qdev_prop_set_uint32(dev, "num_irqs", platform_bus_num_irqs);
> + qdev_prop_set_uint32(dev, "mmio_size", platform_bus_mem->size);
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + sysbus = SYS_BUS_DEVICE(dev);
> + for (int i = 0; i < platform_bus_num_irqs; i++) {
> + int irq = platform_bus_base_irq + i;
> + sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
> + }
> +
> + memory_region_add_subregion(sysmem,
> + platform_bus_mem->base,
> + sysbus_mmio_get_region(sysbus, 0));
> +
> + return dev;
> +}
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 0d82ceacc4..7aa3c1578d 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -1,6 +1,7 @@
> riscv_ss = ss.source_set()
> riscv_ss.add(files('aia.c'))
> riscv_ss.add(files('boot.c'))
> +riscv_ss.add(files('device-common.c'))
> riscv_ss.add(files('fdt-common.c'))
> riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
> riscv_ss.add(files('riscv_hart.c'))
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index ccea5784f0..a2671ae341 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -35,6 +35,7 @@
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/virt.h"
> #include "hw/riscv/boot.h"
> +#include "hw/riscv/device-common.h"
> #include "hw/riscv/fdt-common.h"
> #include "hw/riscv/machines-qom.h"
> #include "hw/riscv/numa.h"
> @@ -683,31 +684,6 @@ static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket,
> memmap[VIRT_PLIC].size);
> }
>
> -static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip)
> -{
> - DeviceState *dev;
> - SysBusDevice *sysbus;
> - int i;
> - MemoryRegion *sysmem = get_system_memory();
> -
> - dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
> - dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
> - qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS);
> - qdev_prop_set_uint32(dev, "mmio_size", s->memmap[VIRT_PLATFORM_BUS].size);
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> - s->platform_bus_dev = dev;
> -
> - sysbus = SYS_BUS_DEVICE(dev);
> - for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) {
> - int irq = VIRT_PLATFORM_BUS_IRQ + i;
> - sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq));
> - }
> -
> - memory_region_add_subregion(sysmem,
> - s->memmap[VIRT_PLATFORM_BUS].base,
> - sysbus_mmio_get_region(sysbus, 0));
> -}
> -
> static void virt_build_smbios(RISCVVirtState *s)
> {
> MachineClass *mc = MACHINE_GET_CLASS(s);
> @@ -1030,7 +1006,9 @@ static void virt_machine_init(MachineState *machine)
>
> gpex_pcie_init(system_memory, pcie_irqchip, s);
>
> - create_platform_bus(s, mmio_irqchip);
> + s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
> + &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
> + VIRT_PLATFORM_BUS_NUM_IRQS);
>
> serial_mm_init(system_memory, s->memmap[VIRT_UART0].base,
> 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
> diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
> new file mode 100644
> index 0000000000..12af031bbf
> --- /dev/null
> +++ b/include/hw/riscv/device-common.h
> @@ -0,0 +1,19 @@
> +/*
> + * RISC-V board helpers for FDT generation.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef RISCV_DEVICE_COMMON_H
> +#define RISCV_DEVICE_COMMON_H
> +
> +#include "exec/hwaddr.h"
> +#include "hw/core/qdev.h"
> +
> +DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> + const MemMapEntry *platform_bus_mem,
> + int platform_bus_base_irq,
> + int platform_bus_num_irqs);
> +#endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers
2026-08-28 20:39 ` [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
@ 2026-08-29 3:12 ` Chao Liu via
2026-09-01 5:28 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:12 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:15PM +0800, Daniel Henrique Barboza wrote:
> Move the flash device creating and flash map initialization to
> device-common.c.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/device-common.c | 44 ++++++++++++++++++++++++
> hw/riscv/virt.c | 57 +++++---------------------------
> include/hw/riscv/device-common.h | 6 ++++
> 3 files changed, 58 insertions(+), 49 deletions(-)
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> index d3c68a9e71..a054cd7114 100644
> --- a/hw/riscv/device-common.c
> +++ b/hw/riscv/device-common.c
> @@ -10,11 +10,13 @@
>
> #include "hw/riscv/device-common.h"
>
> +#include "hw/block/flash.h"
> #include "hw/core/platform-bus.h"
> #include "hw/core/qdev.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/sysbus.h"
> #include "qapi/error.h"
> +#include "qom/object.h"
> #include "system/address-spaces.h"
> #include "system/memory.h"
>
> @@ -46,3 +48,45 @@ DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
>
> return dev;
> }
> +
> +PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> + const char *alias_prop_name,
> + int flash_sector_size)
> +{
> + /*
> + * Create a single flash device. We use the same parameters as
> + * the flash devices on the ARM virt board.
> + */
> + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
> +
> + qdev_prop_set_uint64(dev, "sector-length", flash_sector_size);
> + qdev_prop_set_uint8(dev, "width", 4);
> + qdev_prop_set_uint8(dev, "device-width", 2);
> + qdev_prop_set_bit(dev, "big-endian", false);
> + qdev_prop_set_uint16(dev, "id0", 0x89);
> + qdev_prop_set_uint16(dev, "id1", 0x18);
> + qdev_prop_set_uint16(dev, "id2", 0x00);
> + qdev_prop_set_uint16(dev, "id3", 0x00);
> + qdev_prop_set_string(dev, "name", name);
> +
> + object_property_add_child(parent, name, OBJECT(dev));
> + object_property_add_alias(parent, alias_prop_name,
> + OBJECT(dev), "drive");
> +
> + return PFLASH_CFI01(dev);
> +}
> +
> +void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> + MemoryRegion *sysmem, int flash_sector_size)
> +{
> + DeviceState *dev = DEVICE(flash);
> +
> + assert(QEMU_IS_ALIGNED(size, flash_sector_size));
> + assert(size / flash_sector_size <= UINT32_MAX);
> +
> + qdev_prop_set_uint32(dev, "num-blocks", size / flash_sector_size);
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + memory_region_add_subregion(sysmem, base,
> + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index a2671ae341..9ff5beae77 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -120,53 +120,12 @@ static MemMapEntry virt_high_pcie_memmap;
>
> #define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
>
> -static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s,
> - const char *name,
> - const char *alias_prop_name)
> -{
> - /*
> - * Create a single flash device. We use the same parameters as
> - * the flash devices on the ARM virt board.
> - */
> - DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
> -
> - qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
> - qdev_prop_set_uint8(dev, "width", 4);
> - qdev_prop_set_uint8(dev, "device-width", 2);
> - qdev_prop_set_bit(dev, "big-endian", false);
> - qdev_prop_set_uint16(dev, "id0", 0x89);
> - qdev_prop_set_uint16(dev, "id1", 0x18);
> - qdev_prop_set_uint16(dev, "id2", 0x00);
> - qdev_prop_set_uint16(dev, "id3", 0x00);
> - qdev_prop_set_string(dev, "name", name);
> -
> - object_property_add_child(OBJECT(s), name, OBJECT(dev));
> - object_property_add_alias(OBJECT(s), alias_prop_name,
> - OBJECT(dev), "drive");
> -
> - return PFLASH_CFI01(dev);
> -}
> -
> static void virt_flash_create(RISCVVirtState *s)
> {
> - s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0");
> - s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1");
> -}
> -
> -static void virt_flash_map1(PFlashCFI01 *flash,
> - hwaddr base, hwaddr size,
> - MemoryRegion *sysmem)
> -{
> - DeviceState *dev = DEVICE(flash);
> -
> - assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE));
> - assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
> - qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -
> - memory_region_add_subregion(sysmem, base,
> - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
> - 0));
> + s->flash[0] = riscv_flash_create(OBJECT(s), "virt.flash0", "pflash0",
> + VIRT_FLASH_SECTOR_SIZE);
> + s->flash[1] = riscv_flash_create(OBJECT(s), "virt.flash1", "pflash1",
> + VIRT_FLASH_SECTOR_SIZE);
> }
>
> static void virt_flash_map(RISCVVirtState *s,
> @@ -175,10 +134,10 @@ static void virt_flash_map(RISCVVirtState *s,
> hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
> hwaddr flashbase = s->memmap[VIRT_FLASH].base;
>
> - virt_flash_map1(s->flash[0], flashbase, flashsize,
> - sysmem);
> - virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize,
> - sysmem);
> + riscv_init_flash_map(s->flash[0], flashbase, flashsize,
> + sysmem, VIRT_FLASH_SECTOR_SIZE);
> + riscv_init_flash_map(s->flash[1], flashbase + flashsize, flashsize,
> + sysmem, VIRT_FLASH_SECTOR_SIZE);
> }
>
> static void create_fdt_socket_plic(RISCVVirtState *s,
> diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
> index 12af031bbf..9f8bc67a1d 100644
> --- a/include/hw/riscv/device-common.h
> +++ b/include/hw/riscv/device-common.h
> @@ -10,10 +10,16 @@
> #define RISCV_DEVICE_COMMON_H
>
> #include "exec/hwaddr.h"
> +#include "hw/block/flash.h"
> #include "hw/core/qdev.h"
>
> DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> const MemMapEntry *platform_bus_mem,
> int platform_bus_base_irq,
> int platform_bus_num_irqs);
> +PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> + const char *alias_prop_name,
> + int flash_sector_size);
> +void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> + MemoryRegion *sysmem, int flash_sector_size);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers
@ 2026-08-29 3:12 ` Chao Liu via
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:12 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:15PM +0800, Daniel Henrique Barboza wrote:
> Move the flash device creating and flash map initialization to
> device-common.c.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/device-common.c | 44 ++++++++++++++++++++++++
> hw/riscv/virt.c | 57 +++++---------------------------
> include/hw/riscv/device-common.h | 6 ++++
> 3 files changed, 58 insertions(+), 49 deletions(-)
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> index d3c68a9e71..a054cd7114 100644
> --- a/hw/riscv/device-common.c
> +++ b/hw/riscv/device-common.c
> @@ -10,11 +10,13 @@
>
> #include "hw/riscv/device-common.h"
>
> +#include "hw/block/flash.h"
> #include "hw/core/platform-bus.h"
> #include "hw/core/qdev.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/sysbus.h"
> #include "qapi/error.h"
> +#include "qom/object.h"
> #include "system/address-spaces.h"
> #include "system/memory.h"
>
> @@ -46,3 +48,45 @@ DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
>
> return dev;
> }
> +
> +PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> + const char *alias_prop_name,
> + int flash_sector_size)
> +{
> + /*
> + * Create a single flash device. We use the same parameters as
> + * the flash devices on the ARM virt board.
> + */
> + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
> +
> + qdev_prop_set_uint64(dev, "sector-length", flash_sector_size);
> + qdev_prop_set_uint8(dev, "width", 4);
> + qdev_prop_set_uint8(dev, "device-width", 2);
> + qdev_prop_set_bit(dev, "big-endian", false);
> + qdev_prop_set_uint16(dev, "id0", 0x89);
> + qdev_prop_set_uint16(dev, "id1", 0x18);
> + qdev_prop_set_uint16(dev, "id2", 0x00);
> + qdev_prop_set_uint16(dev, "id3", 0x00);
> + qdev_prop_set_string(dev, "name", name);
> +
> + object_property_add_child(parent, name, OBJECT(dev));
> + object_property_add_alias(parent, alias_prop_name,
> + OBJECT(dev), "drive");
> +
> + return PFLASH_CFI01(dev);
> +}
> +
> +void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> + MemoryRegion *sysmem, int flash_sector_size)
> +{
> + DeviceState *dev = DEVICE(flash);
> +
> + assert(QEMU_IS_ALIGNED(size, flash_sector_size));
> + assert(size / flash_sector_size <= UINT32_MAX);
> +
> + qdev_prop_set_uint32(dev, "num-blocks", size / flash_sector_size);
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + memory_region_add_subregion(sysmem, base,
> + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index a2671ae341..9ff5beae77 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -120,53 +120,12 @@ static MemMapEntry virt_high_pcie_memmap;
>
> #define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
>
> -static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s,
> - const char *name,
> - const char *alias_prop_name)
> -{
> - /*
> - * Create a single flash device. We use the same parameters as
> - * the flash devices on the ARM virt board.
> - */
> - DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
> -
> - qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
> - qdev_prop_set_uint8(dev, "width", 4);
> - qdev_prop_set_uint8(dev, "device-width", 2);
> - qdev_prop_set_bit(dev, "big-endian", false);
> - qdev_prop_set_uint16(dev, "id0", 0x89);
> - qdev_prop_set_uint16(dev, "id1", 0x18);
> - qdev_prop_set_uint16(dev, "id2", 0x00);
> - qdev_prop_set_uint16(dev, "id3", 0x00);
> - qdev_prop_set_string(dev, "name", name);
> -
> - object_property_add_child(OBJECT(s), name, OBJECT(dev));
> - object_property_add_alias(OBJECT(s), alias_prop_name,
> - OBJECT(dev), "drive");
> -
> - return PFLASH_CFI01(dev);
> -}
> -
> static void virt_flash_create(RISCVVirtState *s)
> {
> - s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0");
> - s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1");
> -}
> -
> -static void virt_flash_map1(PFlashCFI01 *flash,
> - hwaddr base, hwaddr size,
> - MemoryRegion *sysmem)
> -{
> - DeviceState *dev = DEVICE(flash);
> -
> - assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE));
> - assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
> - qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -
> - memory_region_add_subregion(sysmem, base,
> - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
> - 0));
> + s->flash[0] = riscv_flash_create(OBJECT(s), "virt.flash0", "pflash0",
> + VIRT_FLASH_SECTOR_SIZE);
> + s->flash[1] = riscv_flash_create(OBJECT(s), "virt.flash1", "pflash1",
> + VIRT_FLASH_SECTOR_SIZE);
> }
>
> static void virt_flash_map(RISCVVirtState *s,
> @@ -175,10 +134,10 @@ static void virt_flash_map(RISCVVirtState *s,
> hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
> hwaddr flashbase = s->memmap[VIRT_FLASH].base;
>
> - virt_flash_map1(s->flash[0], flashbase, flashsize,
> - sysmem);
> - virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize,
> - sysmem);
> + riscv_init_flash_map(s->flash[0], flashbase, flashsize,
> + sysmem, VIRT_FLASH_SECTOR_SIZE);
> + riscv_init_flash_map(s->flash[1], flashbase + flashsize, flashsize,
> + sysmem, VIRT_FLASH_SECTOR_SIZE);
> }
>
> static void create_fdt_socket_plic(RISCVVirtState *s,
> diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
> index 12af031bbf..9f8bc67a1d 100644
> --- a/include/hw/riscv/device-common.h
> +++ b/include/hw/riscv/device-common.h
> @@ -10,10 +10,16 @@
> #define RISCV_DEVICE_COMMON_H
>
> #include "exec/hwaddr.h"
> +#include "hw/block/flash.h"
> #include "hw/core/qdev.h"
>
> DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> const MemMapEntry *platform_bus_mem,
> int platform_bus_base_irq,
> int platform_bus_num_irqs);
> +PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> + const char *alias_prop_name,
> + int flash_sector_size);
> +void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> + MemoryRegion *sysmem, int flash_sector_size);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
2026-08-28 20:39 ` [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
@ 2026-08-29 3:13 ` Chao Liu via qemu development
2026-09-01 5:28 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:13 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:16PM +0800, Daniel Henrique Barboza wrote:
> The GPEX_HOST initialization in 'virt' can be moved to device-common.c
> and be re-used later for other boards, namely the future
> 'riscv-server-ref' emulation.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/device-common.c | 76 +++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 77 ++------------------------------
> include/hw/riscv/device-common.h | 7 +++
> 3 files changed, 87 insertions(+), 73 deletions(-)
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> index a054cd7114..d1a6814f87 100644
> --- a/hw/riscv/device-common.c
> +++ b/hw/riscv/device-common.c
> @@ -15,6 +15,8 @@
> #include "hw/core/qdev.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/sysbus.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci-host/gpex.h"
> #include "qapi/error.h"
> #include "qom/object.h"
> #include "system/address-spaces.h"
> @@ -90,3 +92,77 @@ void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> memory_region_add_subregion(sysmem, base,
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
> }
> +
> +DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
> + DeviceState *irqchip,
> + const MemMapEntry *pcie_ecam_mem,
> + const MemMapEntry *pcie_mmio_mem,
> + const MemMapEntry *high_pcie_mmio_mem,
> + const MemMapEntry *pcie_pio_mem,
> + int pcie_irq)
> +{
> + DeviceState *dev;
> + MemoryRegion *ecam_alias, *ecam_reg;
> + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
> + hwaddr ecam_base = pcie_ecam_mem->base;
> + hwaddr ecam_size = pcie_ecam_mem->size;
> + hwaddr mmio_base = pcie_mmio_mem->base;
> + hwaddr mmio_size = pcie_mmio_mem->size;
> + hwaddr high_mmio_base = high_pcie_mmio_mem->base;
> + hwaddr high_mmio_size = high_pcie_mmio_mem->size;
> + hwaddr pio_base = pcie_pio_mem->base;
> + hwaddr pio_size = pcie_pio_mem->size;
> +
> + dev = qdev_new(TYPE_GPEX_HOST);
> +
> + /* Set GPEX object properties for the virt machine */
> + object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
> + ecam_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
> + ecam_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
> + mmio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
> + mmio_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
> + high_mmio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
> + high_mmio_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
> + pio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
> + pio_size, NULL);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + ecam_alias = g_new0(MemoryRegion, 1);
> + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> + ecam_reg, 0, ecam_size);
> + memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
> +
> + mmio_alias = g_new0(MemoryRegion, 1);
> + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> + mmio_reg, mmio_base, mmio_size);
> + memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
> +
> + /* Map high MMIO space */
> + high_mmio_alias = g_new0(MemoryRegion, 1);
> + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
> + mmio_reg, high_mmio_base, high_mmio_size);
> + memory_region_add_subregion(get_system_memory(), high_mmio_base,
> + high_mmio_alias);
> +
> + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
> +
> + for (int i = 0; i < PCI_NUM_PINS; i++) {
> + qemu_irq irq = qdev_get_gpio_in(irqchip, pcie_irq + i);
> +
> + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> + gpex_set_irq_num(GPEX_HOST(dev), i, pcie_irq + i);
> + }
> +
> + GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
> + return dev;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 9ff5beae77..d75dec2dd2 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -540,78 +540,6 @@ static void create_fdt(RISCVVirtState *s)
> create_fdt_pmu(s);
> }
>
> -static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
> - DeviceState *irqchip,
> - RISCVVirtState *s)
> -{
> - DeviceState *dev;
> - MemoryRegion *ecam_alias, *ecam_reg;
> - MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
> - hwaddr ecam_base = s->memmap[VIRT_PCIE_ECAM].base;
> - hwaddr ecam_size = s->memmap[VIRT_PCIE_ECAM].size;
> - hwaddr mmio_base = s->memmap[VIRT_PCIE_MMIO].base;
> - hwaddr mmio_size = s->memmap[VIRT_PCIE_MMIO].size;
> - hwaddr high_mmio_base = virt_high_pcie_memmap.base;
> - hwaddr high_mmio_size = virt_high_pcie_memmap.size;
> - hwaddr pio_base = s->memmap[VIRT_PCIE_PIO].base;
> - hwaddr pio_size = s->memmap[VIRT_PCIE_PIO].size;
> - qemu_irq irq;
> - int i;
> -
> - dev = qdev_new(TYPE_GPEX_HOST);
> -
> - /* Set GPEX object properties for the virt machine */
> - object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
> - ecam_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
> - ecam_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
> - mmio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
> - mmio_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
> - high_mmio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
> - high_mmio_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
> - pio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
> - pio_size, NULL);
> -
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -
> - ecam_alias = g_new0(MemoryRegion, 1);
> - ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> - memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> - ecam_reg, 0, ecam_size);
> - memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
> -
> - mmio_alias = g_new0(MemoryRegion, 1);
> - mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> - memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> - mmio_reg, mmio_base, mmio_size);
> - memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
> -
> - /* Map high MMIO space */
> - high_mmio_alias = g_new0(MemoryRegion, 1);
> - memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
> - mmio_reg, high_mmio_base, high_mmio_size);
> - memory_region_add_subregion(get_system_memory(), high_mmio_base,
> - high_mmio_alias);
> -
> - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
> -
> - for (i = 0; i < PCI_NUM_PINS; i++) {
> - irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
> -
> - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> - gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
> - }
> -
> - GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
> - return dev;
> -}
> -
> static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base)
> {
> FWCfgState *fw_cfg;
> @@ -963,7 +891,10 @@ static void virt_machine_init(MachineState *machine)
> qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i));
> }
>
> - gpex_pcie_init(system_memory, pcie_irqchip, s);
> + riscv_gpex_pcie_init(system_memory, pcie_irqchip,
> + &s->memmap[VIRT_PCIE_ECAM], &s->memmap[VIRT_PCIE_MMIO],
> + &virt_high_pcie_memmap, &s->memmap[VIRT_PCIE_PIO],
> + PCIE_IRQ);
>
> s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
> &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
> diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
> index 9f8bc67a1d..572912ec36 100644
> --- a/include/hw/riscv/device-common.h
> +++ b/include/hw/riscv/device-common.h
> @@ -22,4 +22,11 @@ PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> int flash_sector_size);
> void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> MemoryRegion *sysmem, int flash_sector_size);
> +DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
> + DeviceState *irqchip,
> + const MemMapEntry *pcie_ecam_mem,
> + const MemMapEntry *pcie_mmio_mem,
> + const MemMapEntry *high_pcie_mmio_mem,
> + const MemMapEntry *pcie_pio_mem,
> + int pcie_irq);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
@ 2026-08-29 3:13 ` Chao Liu via qemu development
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:13 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:16PM +0800, Daniel Henrique Barboza wrote:
> The GPEX_HOST initialization in 'virt' can be moved to device-common.c
> and be re-used later for other boards, namely the future
> 'riscv-server-ref' emulation.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/device-common.c | 76 +++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 77 ++------------------------------
> include/hw/riscv/device-common.h | 7 +++
> 3 files changed, 87 insertions(+), 73 deletions(-)
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> index a054cd7114..d1a6814f87 100644
> --- a/hw/riscv/device-common.c
> +++ b/hw/riscv/device-common.c
> @@ -15,6 +15,8 @@
> #include "hw/core/qdev.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/sysbus.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci-host/gpex.h"
> #include "qapi/error.h"
> #include "qom/object.h"
> #include "system/address-spaces.h"
> @@ -90,3 +92,77 @@ void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> memory_region_add_subregion(sysmem, base,
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
> }
> +
> +DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
> + DeviceState *irqchip,
> + const MemMapEntry *pcie_ecam_mem,
> + const MemMapEntry *pcie_mmio_mem,
> + const MemMapEntry *high_pcie_mmio_mem,
> + const MemMapEntry *pcie_pio_mem,
> + int pcie_irq)
> +{
> + DeviceState *dev;
> + MemoryRegion *ecam_alias, *ecam_reg;
> + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
> + hwaddr ecam_base = pcie_ecam_mem->base;
> + hwaddr ecam_size = pcie_ecam_mem->size;
> + hwaddr mmio_base = pcie_mmio_mem->base;
> + hwaddr mmio_size = pcie_mmio_mem->size;
> + hwaddr high_mmio_base = high_pcie_mmio_mem->base;
> + hwaddr high_mmio_size = high_pcie_mmio_mem->size;
> + hwaddr pio_base = pcie_pio_mem->base;
> + hwaddr pio_size = pcie_pio_mem->size;
> +
> + dev = qdev_new(TYPE_GPEX_HOST);
> +
> + /* Set GPEX object properties for the virt machine */
> + object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
> + ecam_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
> + ecam_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
> + mmio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
> + mmio_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
> + high_mmio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
> + high_mmio_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
> + pio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
> + pio_size, NULL);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + ecam_alias = g_new0(MemoryRegion, 1);
> + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> + ecam_reg, 0, ecam_size);
> + memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
> +
> + mmio_alias = g_new0(MemoryRegion, 1);
> + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> + mmio_reg, mmio_base, mmio_size);
> + memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
> +
> + /* Map high MMIO space */
> + high_mmio_alias = g_new0(MemoryRegion, 1);
> + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
> + mmio_reg, high_mmio_base, high_mmio_size);
> + memory_region_add_subregion(get_system_memory(), high_mmio_base,
> + high_mmio_alias);
> +
> + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
> +
> + for (int i = 0; i < PCI_NUM_PINS; i++) {
> + qemu_irq irq = qdev_get_gpio_in(irqchip, pcie_irq + i);
> +
> + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> + gpex_set_irq_num(GPEX_HOST(dev), i, pcie_irq + i);
> + }
> +
> + GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
> + return dev;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 9ff5beae77..d75dec2dd2 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -540,78 +540,6 @@ static void create_fdt(RISCVVirtState *s)
> create_fdt_pmu(s);
> }
>
> -static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
> - DeviceState *irqchip,
> - RISCVVirtState *s)
> -{
> - DeviceState *dev;
> - MemoryRegion *ecam_alias, *ecam_reg;
> - MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
> - hwaddr ecam_base = s->memmap[VIRT_PCIE_ECAM].base;
> - hwaddr ecam_size = s->memmap[VIRT_PCIE_ECAM].size;
> - hwaddr mmio_base = s->memmap[VIRT_PCIE_MMIO].base;
> - hwaddr mmio_size = s->memmap[VIRT_PCIE_MMIO].size;
> - hwaddr high_mmio_base = virt_high_pcie_memmap.base;
> - hwaddr high_mmio_size = virt_high_pcie_memmap.size;
> - hwaddr pio_base = s->memmap[VIRT_PCIE_PIO].base;
> - hwaddr pio_size = s->memmap[VIRT_PCIE_PIO].size;
> - qemu_irq irq;
> - int i;
> -
> - dev = qdev_new(TYPE_GPEX_HOST);
> -
> - /* Set GPEX object properties for the virt machine */
> - object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
> - ecam_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
> - ecam_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_BASE,
> - mmio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_BELOW_4G_MMIO_SIZE,
> - mmio_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_BASE,
> - high_mmio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_ABOVE_4G_MMIO_SIZE,
> - high_mmio_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
> - pio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
> - pio_size, NULL);
> -
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -
> - ecam_alias = g_new0(MemoryRegion, 1);
> - ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> - memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> - ecam_reg, 0, ecam_size);
> - memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
> -
> - mmio_alias = g_new0(MemoryRegion, 1);
> - mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> - memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> - mmio_reg, mmio_base, mmio_size);
> - memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
> -
> - /* Map high MMIO space */
> - high_mmio_alias = g_new0(MemoryRegion, 1);
> - memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high",
> - mmio_reg, high_mmio_base, high_mmio_size);
> - memory_region_add_subregion(get_system_memory(), high_mmio_base,
> - high_mmio_alias);
> -
> - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
> -
> - for (i = 0; i < PCI_NUM_PINS; i++) {
> - irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
> -
> - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> - gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
> - }
> -
> - GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
> - return dev;
> -}
> -
> static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base)
> {
> FWCfgState *fw_cfg;
> @@ -963,7 +891,10 @@ static void virt_machine_init(MachineState *machine)
> qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i));
> }
>
> - gpex_pcie_init(system_memory, pcie_irqchip, s);
> + riscv_gpex_pcie_init(system_memory, pcie_irqchip,
> + &s->memmap[VIRT_PCIE_ECAM], &s->memmap[VIRT_PCIE_MMIO],
> + &virt_high_pcie_memmap, &s->memmap[VIRT_PCIE_PIO],
> + PCIE_IRQ);
>
> s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
> &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
> diff --git a/include/hw/riscv/device-common.h b/include/hw/riscv/device-common.h
> index 9f8bc67a1d..572912ec36 100644
> --- a/include/hw/riscv/device-common.h
> +++ b/include/hw/riscv/device-common.h
> @@ -22,4 +22,11 @@ PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> int flash_sector_size);
> void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr size,
> MemoryRegion *sysmem, int flash_sector_size);
> +DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
> + DeviceState *irqchip,
> + const MemMapEntry *pcie_ecam_mem,
> + const MemMapEntry *pcie_mmio_mem,
> + const MemMapEntry *high_pcie_mmio_mem,
> + const MemMapEntry *pcie_pio_mem,
> + int pcie_irq);
> #endif
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
2026-08-28 20:39 ` [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
@ 2026-08-29 3:13 ` Chao Liu via
2026-09-01 5:28 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Chao Liu via qemu development @ 2026-08-29 3:13 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:17PM +0800, Daniel Henrique Barboza wrote:
> Move the creation of riscv-iommu-sys to its own file instead of open
> coding it in the 'virt' board. Other boards in the future might want to
> use this device and we want to avoid code duplication.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/riscv-iommu-sys.c | 25 +++++++++++++++++++++++++
> hw/riscv/riscv-iommu.h | 3 +++
> hw/riscv/virt.c | 23 +++--------------------
> 3 files changed, 31 insertions(+), 20 deletions(-)
>
> diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c
> index 3314adeed2..258c171efd 100644
> --- a/hw/riscv/riscv-iommu-sys.c
> +++ b/hw/riscv/riscv-iommu-sys.c
> @@ -217,6 +217,31 @@ static void riscv_iommu_sys_init(Object *obj)
> riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_BOTH);
> }
>
> +DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
> + hwaddr addr, int base_irq,
> + bool is_32_bit)
> +{
> + DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
> +
> + object_property_set_uint(OBJECT(iommu_sys), "addr", addr, &error_fatal);
> + object_property_set_uint(OBJECT(iommu_sys), "base-irq",
> + base_irq, &error_fatal);
> + object_property_set_link(OBJECT(iommu_sys), "irqchip",
> + OBJECT(mmio_irqchip),
> + &error_fatal);
> + /*
> + * For riscv64 use a physical address size of 56 bits (44 bit PPN),
> + * and for riscv32 use 34 bits (22 bit PPN).
> + */
> + object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
> + is_32_bit ? 34 : 56,
> + &error_fatal);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
> +
> + return iommu_sys;
> +}
> +
> static const Property riscv_iommu_sys_properties[] = {
> DEFINE_PROP_UINT64("addr", RISCVIOMMUStateSys, addr, 0),
> DEFINE_PROP_UINT32("base-irq", RISCVIOMMUStateSys, base_irq, 0),
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index da70e8bfa8..7c470ba084 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -104,6 +104,9 @@ void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
> void riscv_iommu_reset(RISCVIOMMUState *s);
> void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
> void riscv_iommu_fault(RISCVIOMMUState *s, struct riscv_iommu_fq_record *ev);
> +DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
> + hwaddr addr, int base_irq,
> + bool is_32_bit);
>
> typedef struct RISCVIOMMUContext RISCVIOMMUContext;
> /* Device translation context state. */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index d75dec2dd2..de7b99c6a5 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -32,6 +32,7 @@
> #include "hw/core/sysbus-fdt.h"
> #include "hw/riscv/riscv_hart.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/riscv/riscv-iommu.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/virt.h"
> #include "hw/riscv/boot.h"
> @@ -933,26 +934,8 @@ static void virt_machine_init(MachineState *machine)
> }
>
> if (virt_is_iommu_sys_enabled(s)) {
> - DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
> -
> - object_property_set_uint(OBJECT(iommu_sys), "addr",
> - s->memmap[VIRT_IOMMU_SYS].base,
> - &error_fatal);
> - object_property_set_uint(OBJECT(iommu_sys), "base-irq",
> - IOMMU_SYS_IRQ,
> - &error_fatal);
> - object_property_set_link(OBJECT(iommu_sys), "irqchip",
> - OBJECT(mmio_irqchip),
> - &error_fatal);
> - /*
> - * For riscv64 use a physical address size of 56 bits (44 bit PPN),
> - * and for riscv32 use 34 bits (22 bit PPN).
> - */
> - object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
> - riscv_is_32bit(&s->soc[0]) ? 34 : 56,
> - &error_fatal);
> -
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
> + riscv_create_iommu_sys(mmio_irqchip, s->memmap[VIRT_IOMMU_SYS].base,
> + IOMMU_SYS_IRQ, riscv_is_32bit(&s->soc[0]));
> }
>
> s->machine_done.notify = virt_machine_done;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
@ 2026-08-29 3:13 ` Chao Liu via
0 siblings, 0 replies; 55+ messages in thread
From: Chao Liu via @ 2026-08-29 3:13 UTC (permalink / raw)
To: Daniel Henrique Barboza
Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
Philippe Mathieu-Daudé, Palmer Dabbelt
On Fri, Aug 28, 2026 at 05:39:17PM +0800, Daniel Henrique Barboza wrote:
> Move the creation of riscv-iommu-sys to its own file instead of open
> coding it in the 'virt' board. Other boards in the future might want to
> use this device and we want to avoid code duplication.
>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Chao Liu <chao.liu@processmission.com>
Thanks,
Chao
> ---
> hw/riscv/riscv-iommu-sys.c | 25 +++++++++++++++++++++++++
> hw/riscv/riscv-iommu.h | 3 +++
> hw/riscv/virt.c | 23 +++--------------------
> 3 files changed, 31 insertions(+), 20 deletions(-)
>
> diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c
> index 3314adeed2..258c171efd 100644
> --- a/hw/riscv/riscv-iommu-sys.c
> +++ b/hw/riscv/riscv-iommu-sys.c
> @@ -217,6 +217,31 @@ static void riscv_iommu_sys_init(Object *obj)
> riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_BOTH);
> }
>
> +DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
> + hwaddr addr, int base_irq,
> + bool is_32_bit)
> +{
> + DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
> +
> + object_property_set_uint(OBJECT(iommu_sys), "addr", addr, &error_fatal);
> + object_property_set_uint(OBJECT(iommu_sys), "base-irq",
> + base_irq, &error_fatal);
> + object_property_set_link(OBJECT(iommu_sys), "irqchip",
> + OBJECT(mmio_irqchip),
> + &error_fatal);
> + /*
> + * For riscv64 use a physical address size of 56 bits (44 bit PPN),
> + * and for riscv32 use 34 bits (22 bit PPN).
> + */
> + object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
> + is_32_bit ? 34 : 56,
> + &error_fatal);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
> +
> + return iommu_sys;
> +}
> +
> static const Property riscv_iommu_sys_properties[] = {
> DEFINE_PROP_UINT64("addr", RISCVIOMMUStateSys, addr, 0),
> DEFINE_PROP_UINT32("base-irq", RISCVIOMMUStateSys, base_irq, 0),
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index da70e8bfa8..7c470ba084 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -104,6 +104,9 @@ void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
> void riscv_iommu_reset(RISCVIOMMUState *s);
> void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
> void riscv_iommu_fault(RISCVIOMMUState *s, struct riscv_iommu_fq_record *ev);
> +DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
> + hwaddr addr, int base_irq,
> + bool is_32_bit);
>
> typedef struct RISCVIOMMUContext RISCVIOMMUContext;
> /* Device translation context state. */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index d75dec2dd2..de7b99c6a5 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -32,6 +32,7 @@
> #include "hw/core/sysbus-fdt.h"
> #include "hw/riscv/riscv_hart.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/riscv/riscv-iommu.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/virt.h"
> #include "hw/riscv/boot.h"
> @@ -933,26 +934,8 @@ static void virt_machine_init(MachineState *machine)
> }
>
> if (virt_is_iommu_sys_enabled(s)) {
> - DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
> -
> - object_property_set_uint(OBJECT(iommu_sys), "addr",
> - s->memmap[VIRT_IOMMU_SYS].base,
> - &error_fatal);
> - object_property_set_uint(OBJECT(iommu_sys), "base-irq",
> - IOMMU_SYS_IRQ,
> - &error_fatal);
> - object_property_set_link(OBJECT(iommu_sys), "irqchip",
> - OBJECT(mmio_irqchip),
> - &error_fatal);
> - /*
> - * For riscv64 use a physical address size of 56 bits (44 bit PPN),
> - * and for riscv32 use 34 bits (22 bit PPN).
> - */
> - object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
> - riscv_is_32bit(&s->soc[0]) ? 34 : 56,
> - &error_fatal);
> -
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal);
> + riscv_create_iommu_sys(mmio_irqchip, s->memmap[VIRT_IOMMU_SYS].base,
> + IOMMU_SYS_IRQ, riscv_is_32bit(&s->soc[0]));
> }
>
> s->machine_done.notify = virt_machine_done;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_"
2026-08-28 20:39 ` [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
@ 2026-09-01 4:42 ` Alistair Francis
2026-09-02 16:24 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 4:42 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: npiggin@gmail.com, joel@jms.id.au, mpe@kernel.org,
portias@oss.tenstorrent.com, qemu-riscv@nongnu.org,
philmd@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com,
asrinivasan@oss.tenstorrent.com, palmer@dabbelt.com,
liwei1518@gmail.com, chao.liu@processmission.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Given that the helpers are public API we should prefix them with
> "riscv_" to avoid conflicts when linking with different targets in
> the
> future, i.e. we should not use generic names like
> "create_fdt_socket_memory".
>
> Despite the amount of lines this is a mechanical change and no real
> FDT changes are intended.
>
> Suggested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Chao Liu <chao.liu@processmission.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 45 ++++++++++++++++----------------
> hw/riscv/sifive_u.c | 34 +++++++++++++------------
> hw/riscv/spike.c | 30 ++++++++++++----------
> hw/riscv/tt_atlantis.c | 22 ++++++++--------
> hw/riscv/virt.c | 42 +++++++++++++++---------------
> include/hw/riscv/fdt-common.h | 48 ++++++++++++++++++---------------
> --
> 6 files changed, 117 insertions(+), 104 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index aa143a618b..3a8da03cfb 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -14,8 +14,8 @@
> #include "hw/riscv/fdt-common.h"
> #include "target/riscv/cpu_bits.h"
>
> -void *create_board_device_tree(const char *model, const char
> *compatible,
> - int *fdt_size)
> +void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> + int *fdt_size)
> {
> void *fdt = create_device_tree(fdt_size);
>
> @@ -38,8 +38,8 @@ void *create_board_device_tree(const char *model,
> const char *compatible,
> return fdt;
> }
>
> -void create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t size,
> - int socket_id, bool numa_enabled)
> +void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t
> size,
> + int socket_id, bool
> numa_enabled)
> {
> g_autofree char *mem_name =
> g_strdup_printf("/memory@%"HWADDR_PRIx, addr);
>
> @@ -52,9 +52,9 @@ void create_fdt_socket_memory(void *fdt, hwaddr
> addr, uint64_t size,
> }
> }
>
> -void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
> - int socket_id, uint32_t *intc_phandles,
> - int num_harts, bool numa_enabled)
> +void riscv_create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t
> size,
> + int socket_id, uint32_t
> *intc_phandles,
> + int num_harts, bool numa_enabled)
> {
> g_autofree uint32_t *clint_cells = g_new0(uint32_t, num_harts *
> 4);
> g_autofree char *clint_name = NULL;
> @@ -84,7 +84,8 @@ void create_fdt_socket_clint(void *fdt, hwaddr
> addr, uint64_t size,
> }
> }
>
> -void fdt_create_cpu_socket_subnode(void *fdt, uint64_t
> timebase_frequency)
> +void riscv_fdt_create_cpu_socket_subnode(void *fdt,
> + uint64_t
> timebase_frequency)
> {
> qemu_fdt_add_subnode(fdt, "/cpus");
> qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> @@ -169,11 +170,11 @@ create_fdt_socket_cpu_internal(void *fdt, char
> *clust_name, RISCVCPU *cpu_ptr,
> qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
> }
>
> -void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
> - int socket_id, int num_harts_socket,
> - int socket_hartid_base, uint32_t
> *phandle,
> - uint32_t *intc_phandles, bool
> numa_enabled,
> - bool is_32_bit)
> +void riscv_create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
> + int socket_id, int
> num_harts_socket,
> + int socket_hartid_base, uint32_t
> *phandle,
> + uint32_t *intc_phandles, bool
> numa_enabled,
> + bool is_32_bit)
> {
> g_autofree char *clust_name = NULL;
>
> @@ -191,21 +192,21 @@ void create_fdt_socket_cpus(void *fdt, RISCVCPU
> *socket_harts,
> }
>
> void
> -create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
> - int cpu_id, int socket_id,
> - int socket_hartid_base, uint32_t
> *phandle,
> - uint32_t *intc_phandles)
> +riscv_create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
> + int cpu_id, int socket_id,
> + int socket_hartid_base, uint32_t
> *phandle,
> + uint32_t *intc_phandles)
> {
> create_fdt_socket_cpu_internal(fdt, clust_name, NULL, cpu_id,
> socket_id, socket_hartid_base,
> phandle, intc_phandles, false,
> false);
> }
>
> -void create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
> - uint32_t plic_phandle, uint32_t int_cells,
> - uint32_t addr_cells, uint32_t *plic_cells,
> - uint32_t cells_size, uint32_t ndev_sources,
> - bool numa_enabled, int socket_id)
> +void riscv_create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
> + uint32_t plic_phandle, uint32_t
> int_cells,
> + uint32_t addr_cells, uint32_t
> *plic_cells,
> + uint32_t cells_size, uint32_t
> ndev_sources,
> + bool numa_enabled, int socket_id)
> {
> g_autofree char *nodename = NULL;
> static const char * const plic_compat[2] = {
> diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> index 57a57c96e1..852c48c056 100644
> --- a/hw/riscv/sifive_u.c
> +++ b/hw/riscv/sifive_u.c
> @@ -108,8 +108,10 @@ static void create_fdt(SiFiveUState *s, const
> MemMapEntry *memmap,
> g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms-
> >smp.cpus);
> g_autofree char *clust_name = NULL;
>
> - fdt = ms->fdt = create_board_device_tree("SiFive HiFive
> Unleashed A00",
> - "sifive,hifive-unleashed-a00", &s->fdt_size);
> + fdt = ms->fdt = riscv_create_board_device_tree(
> + "SiFive HiFive Unleashed A00",
> + "sifive,hifive-unleashed-a00",
> + &s->fdt_size);
>
> hfclk_phandle = phandle++;
> nodename = g_strdup_printf("/hfclk");
> @@ -133,10 +135,10 @@ static void create_fdt(SiFiveUState *s, const
> MemMapEntry *memmap,
> qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
> g_free(nodename);
>
> - create_fdt_socket_memory(fdt, memmap[SIFIVE_U_DEV_DRAM].base,
> - ms->ram_size, 0, false);
> + riscv_create_fdt_socket_memory(fdt,
> memmap[SIFIVE_U_DEV_DRAM].base,
> + ms->ram_size, 0, false);
>
> - fdt_create_cpu_socket_subnode(fdt, CLINT_TIMEBASE_FREQ);
> + riscv_fdt_create_cpu_socket_subnode(fdt, CLINT_TIMEBASE_FREQ);
>
> clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", 0);
> qemu_fdt_add_subnode(fdt, clust_name);
> @@ -157,15 +159,15 @@ static void create_fdt(SiFiveUState *s, const
> MemMapEntry *memmap,
> riscv_isa_write_fdt(&s->soc.e_cpus.harts[0], fdt,
> nodename);
> }
>
> - create_fdt_socket_cpu_sifive(fdt, clust_name, cpu, 0, 0,
> - &phandle, intc_phandles);
> + riscv_create_fdt_socket_cpu_sifive(fdt, clust_name, cpu, 0,
> 0,
> + &phandle, intc_phandles);
>
> g_free(nodename);
> }
>
> - create_fdt_socket_clint(fdt, memmap[SIFIVE_U_DEV_CLINT].base,
> - memmap[SIFIVE_U_DEV_CLINT].size, 0,
> - intc_phandles, ms->smp.cpus, false);
> + riscv_create_fdt_socket_clint(fdt,
> memmap[SIFIVE_U_DEV_CLINT].base,
> + memmap[SIFIVE_U_DEV_CLINT].size,
> 0,
> + intc_phandles, ms->smp.cpus,
> false);
>
> nodename = g_strdup_printf("/soc/otp@%lx",
> (long)memmap[SIFIVE_U_DEV_OTP].base);
> @@ -209,12 +211,12 @@ static void create_fdt(SiFiveUState *s, const
> MemMapEntry *memmap,
> }
> }
>
> - create_fdt_plic(fdt, memmap[SIFIVE_U_DEV_PLIC].base,
> - memmap[SIFIVE_U_DEV_PLIC].size,
> - plic_phandle, SIFIVE_U_PLIC_INT_CELLS,
> - SIFIVE_U_PLIC_ADDR_CELLS, cells,
> - cells_length * sizeof(uint32_t),
> - SIFIVE_U_PLIC_NUM_SOURCES - 1, false, 0);
> + riscv_create_fdt_plic(fdt, memmap[SIFIVE_U_DEV_PLIC].base,
> + memmap[SIFIVE_U_DEV_PLIC].size,
> + plic_phandle, SIFIVE_U_PLIC_INT_CELLS,
> + SIFIVE_U_PLIC_ADDR_CELLS, cells,
> + cells_length * sizeof(uint32_t),
> + SIFIVE_U_PLIC_NUM_SOURCES - 1, false, 0);
> g_free(cells);
>
> gpio_phandle = phandle++;
> diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> index 630b65f569..8d7e93807c 100644
> --- a/hw/riscv/spike.c
> +++ b/hw/riscv/spike.c
> @@ -61,8 +61,10 @@ static void create_fdt(SpikeState *s, const
> MemMapEntry *memmap,
> uint32_t phandle = 1;
> bool numa_enabled = riscv_numa_enabled(ms);
>
> - fdt = ms->fdt = create_board_device_tree("ucbbar,spike-
> bare,qemu",
> - "ucbbar,spike-bare-dev", &fdt_size);
> + fdt = ms->fdt = riscv_create_board_device_tree(
> + "ucbbar,spike-bare,qemu",
> + "ucbbar,spike-bare-dev",
> + &fdt_size);
>
> qemu_fdt_add_subnode(fdt, "/htif");
> qemu_fdt_setprop_string(fdt, "/htif", "compatible",
> "ucb,htif0");
> @@ -71,7 +73,8 @@ static void create_fdt(SpikeState *s, const
> MemMapEntry *memmap,
> 0x0, memmap[SPIKE_HTIF].base, 0x0,
> memmap[SPIKE_HTIF].size);
> }
>
> - fdt_create_cpu_socket_subnode(fdt,
> RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
> + riscv_fdt_create_cpu_socket_subnode(fdt,
> +
> RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
>
> for (socket = (riscv_socket_count(ms) - 1); socket >= 0; socket-
> -) {
> g_autofree uint32_t *intc_phandles = g_new0(uint32_t,
> @@ -80,20 +83,21 @@ static void create_fdt(SpikeState *s, const
> MemMapEntry *memmap,
> riscv_socket_mem_offset(ms, socket);
> uint64_t memsize = riscv_socket_mem_size(ms, socket);
>
> - create_fdt_socket_cpus(fdt, (&s->soc[socket])->harts,
> socket,
> - s->soc[socket].num_harts,
> - s->soc[socket].hartid_base,
> - &phandle, intc_phandles,
> numa_enabled,
> - is_32_bit);
> + riscv_create_fdt_socket_cpus(fdt, (&s->soc[socket])->harts,
> socket,
> + s->soc[socket].num_harts,
> + s->soc[socket].hartid_base,
> + &phandle, intc_phandles,
> numa_enabled,
> + is_32_bit);
>
> - create_fdt_socket_memory(fdt, memaddr, memsize, socket,
> - riscv_numa_enabled(ms));
> + riscv_create_fdt_socket_memory(fdt, memaddr, memsize,
> socket,
> + riscv_numa_enabled(ms));
>
> clint_addr = memmap[SPIKE_CLINT].base +
> (memmap[SPIKE_CLINT].size * socket);
> - create_fdt_socket_clint(fdt, clint_addr,
> memmap[SPIKE_CLINT].size,
> - socket, intc_phandles,
> - s->soc[socket].num_harts,
> numa_enabled);
> + riscv_create_fdt_socket_clint(fdt, clint_addr,
> + memmap[SPIKE_CLINT].size,
> socket,
> + intc_phandles, s-
> >soc[socket].num_harts,
> + numa_enabled);
> }
>
> riscv_socket_fdt_write_distance_matrix(ms);
> diff --git a/hw/riscv/tt_atlantis.c b/hw/riscv/tt_atlantis.c
> index babce2b680..812051a11f 100644
> --- a/hw/riscv/tt_atlantis.c
> +++ b/hw/riscv/tt_atlantis.c
> @@ -91,16 +91,17 @@ static void create_fdt_memory(TTAtlantisState *s)
> size_hi = MACHINE(s)->ram_size - size_lo;
> }
>
> - create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_LO].base,
> size_lo,
> - 0, false);
> + riscv_create_fdt_socket_memory(fdt, s-
> >memmap[TT_ATL_DDR_LO].base,
> + size_lo, 0, false);
> if (size_hi) {
> /*
> * The first part of the HI address is aliased at the LO
> address
> * so do not include that as usable memory. Is there any way
> * (or good reason) to describe that aliasing 2GB with DT?
> */
> - create_fdt_socket_memory(fdt, s->memmap[TT_ATL_DDR_HI].base
> + size_lo,
> - size_hi, 0, false);
> + riscv_create_fdt_socket_memory(fdt,
> + s->memmap[TT_ATL_DDR_HI].base
> + size_lo,
> + size_hi, 0, false);
> }
> }
>
> @@ -225,11 +226,11 @@ static void create_fdt_cpu(TTAtlantisState *s,
> const MemMapEntry *memmap,
> void *fdt = MACHINE(s)->fdt;
> g_autofree uint32_t *intc_phandles = g_new0(uint32_t, ms-
> >smp.cpus);
>
> - fdt_create_cpu_socket_subnode(fdt, TT_ACLINT_TIMEBASE_FREQ);
> + riscv_fdt_create_cpu_socket_subnode(fdt,
> TT_ACLINT_TIMEBASE_FREQ);
>
> - create_fdt_socket_cpus(fdt, s->soc.harts, 0, s->soc.num_harts,
> - s->soc.hartid_base, &fdt_phandle,
> intc_phandles,
> - false, false);
> + riscv_create_fdt_socket_cpus(fdt, s->soc.harts, 0, s-
> >soc.num_harts,
> + s->soc.hartid_base, &fdt_phandle,
> + intc_phandles, false, false);
>
> create_fdt_memory(s);
>
> @@ -367,8 +368,9 @@ static void create_fdt(TTAtlantisState *s)
> {
> MachineState *ms = MACHINE(s);
>
> - ms->fdt = create_board_device_tree("Tenstorrent Atlantis RISC-V
> Machine",
> - "tenstorrent,atlantis", &s-
> >fdt_size);
> + ms->fdt = riscv_create_board_device_tree(
> + "Tenstorrent Atlantis RISC-V Machine",
> + "tenstorrent,atlantis", &s->fdt_size);
>
> qemu_fdt_add_subnode(ms->fdt, "/chosen");
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 329ccdb5a7..b796220fc2 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -360,12 +360,12 @@ static void
> create_fdt_socket_plic(RISCVVirtState *s,
>
> plic_phandles[socket] = (*phandle)++;
>
> - create_fdt_plic(ms->fdt, plic_addr, s->memmap[VIRT_PLIC].size,
> - plic_phandles[socket], FDT_PLIC_INT_CELLS,
> - FDT_PLIC_ADDR_CELLS, plic_cells,
> - cells_length * sizeof(uint32_t),
> - VIRT_IRQCHIP_NUM_SOURCES - 1,
> - numa_enabled, socket);
> + riscv_create_fdt_plic(ms->fdt, plic_addr, s-
> >memmap[VIRT_PLIC].size,
> + plic_phandles[socket], FDT_PLIC_INT_CELLS,
> + FDT_PLIC_ADDR_CELLS, plic_cells,
> + cells_length * sizeof(uint32_t),
> + VIRT_IRQCHIP_NUM_SOURCES - 1,
> + numa_enabled, socket);
>
> if (!socket) {
> platform_bus_add_all_fdt_nodes(ms->fdt, plic_name,
> @@ -601,7 +601,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
>
> - fdt_create_cpu_socket_subnode(ms->fdt,
> + riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc-
> >harts[0]) :
> RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
>
> @@ -615,14 +615,14 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
>
> phandle_pos -= s->soc[socket].num_harts;
>
> - create_fdt_socket_cpus(ms->fdt, (&s->soc[socket])->harts,
> socket,
> - s->soc[socket].num_harts,
> - s->soc[socket].hartid_base,
> - phandle, &intc_phandles[phandle_pos],
> - numa_enabled, is_32_bit);
> + riscv_create_fdt_socket_cpus(ms->fdt, (&s->soc[socket])-
> >harts, socket,
> + s->soc[socket].num_harts,
> + s->soc[socket].hartid_base,
> + phandle,
> &intc_phandles[phandle_pos],
> + numa_enabled, is_32_bit);
>
> - create_fdt_socket_memory(ms->fdt, memaddr, memsize,
> - socket, riscv_numa_enabled(ms));
> + riscv_create_fdt_socket_memory(ms->fdt, memaddr, memsize,
> + socket,
> riscv_numa_enabled(ms));
>
> if (virt_aclint_allowed() && s->have_aclint) {
> create_fdt_socket_aclint(s, socket,
> @@ -631,10 +631,11 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
> hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
> s->memmap[VIRT_CLINT].size * socket;
>
> - create_fdt_socket_clint(ms->fdt, clintaddr,
> - s->memmap[VIRT_CLINT].size,
> - socket,
> &intc_phandles[phandle_pos],
> - s->soc[socket].num_harts,
> numa_enabled);
> + riscv_create_fdt_socket_clint(ms->fdt, clintaddr,
> + s-
> >memmap[VIRT_CLINT].size,
> + socket,
> &intc_phandles[phandle_pos],
> + s->soc[socket].num_harts,
> + numa_enabled);
> }
> }
>
> @@ -1021,8 +1022,9 @@ static void create_fdt(RISCVVirtState *s)
> uint8_t rng_seed[32];
> g_autofree char *name = NULL;
>
> - ms->fdt = create_board_device_tree("riscv-virtio,qemu", "riscv-
> virtio",
> - &s->fdt_size);
> + ms->fdt = riscv_create_board_device_tree("riscv-virtio,qemu",
> + "riscv-virtio",
> + &s->fdt_size);
>
> /*
> * The "/soc/pci@..." node is needed for PCIE hotplugs
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index 1729a6abc6..371971d79d 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -11,29 +11,31 @@
>
> #include "target/riscv/cpu.h"
>
> -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,
> - int socket_id, bool numa_enabled);
> -void create_fdt_clint(void *fdt, hwaddr addr, uint64_t size,
> - uint32_t *intc_phandles, int num_harts);
> -void create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t size,
> - int socket_id, uint32_t *intc_phandles,
> - int num_harts, bool numa_enabled);
> -void fdt_create_cpu_socket_subnode(void *fdt, uint64_t
> timebase_frequency);
> -void create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
> - int socket_id, int num_harts_socket,
> - int socket_hartid_base, uint32_t
> *phandle,
> - uint32_t *intc_phandles, bool
> numa_enabled,
> - bool is_32_bit);
> -void create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
> - int cpu_id, int socket_id,
> +void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> + int *fdt_size);
> +void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t
> size,
> + int socket_id, bool
> numa_enabled);
> +void riscv_create_fdt_clint(void *fdt, hwaddr addr, uint64_t size,
> + uint32_t *intc_phandles, int num_harts);
> +void riscv_create_fdt_socket_clint(void *fdt, hwaddr addr, uint64_t
> size,
> + int socket_id, uint32_t
> *intc_phandles,
> + int num_harts, bool
> numa_enabled);
> +void riscv_fdt_create_cpu_socket_subnode(void *fdt,
> + uint64_t
> timebase_frequency);
> +void riscv_create_fdt_socket_cpus(void *fdt, RISCVCPU *socket_harts,
> + int socket_id, int
> num_harts_socket,
> int socket_hartid_base, uint32_t
> *phandle,
> - uint32_t *intc_phandles);
> -void create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
> - uint32_t plic_phandle, uint32_t int_cells,
> - uint32_t addr_cells, uint32_t *plic_cells,
> - uint32_t cells_size, uint32_t ndev_sources,
> - bool numa_enabled, int socket);
> + uint32_t *intc_phandles, bool
> numa_enabled,
> + bool is_32_bit);
> +void riscv_create_fdt_socket_cpu_sifive(void *fdt, char *clust_name,
> + int cpu_id, int socket_id,
> + int socket_hartid_base,
> + uint32_t *phandle,
> + uint32_t *intc_phandles);
> +void riscv_create_fdt_plic(void *fdt, hwaddr addr, uint64_t size,
> + uint32_t plic_phandle, uint32_t
> int_cells,
> + uint32_t addr_cells, uint32_t
> *plic_cells,
> + uint32_t cells_size, uint32_t
> ndev_sources,
> + bool numa_enabled, int socket);
> void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char
> *pmu_name);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 03/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
2026-08-28 20:39 ` [PATCH v5 03/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
@ 2026-09-01 4:45 ` Alistair Francis
0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 4:45 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> The soon to be added riscv-server-ref board will declare a syscon FDT
> similar to what the 'virt' board already does.
>
> It won't have a 'sifive,test0' and 'sifive,test1' compat string
> though,
> hence we'll add a flag to enable/disable these additional properties.
>
> The FDT is slightly changed: the subnode is now named 'soc/syscon'
> instead
> of 'soc/test' to be compatible with the latest device-tree docs.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> Reviewed-by: Chao Liu <chao.liu@processmission.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 54
> +++++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 46 +++--------------------------
> include/hw/riscv/fdt-common.h | 4 +++
> 3 files changed, 62 insertions(+), 42 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 6fcc1ce21f..eac5ca9322 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -295,3 +295,57 @@ void riscv_create_fdt_flash(void *fdt, hwaddr
> flashbase, hwaddr flashsize)
> 2, flashbase + flashsize, 2,
> flashsize);
> qemu_fdt_setprop_cell(fdt, name, "bank-width", 4);
> }
> +
> +/*
> + * @sifive_test_compat is used to create a FDT that declares
> + * compat with "sifive,test1" and "sifive,test0". This happens
> + * to be the case for the 'virt' machine that also creates a
> + * 'sifive_test' syscon device.
> + */
> +void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,
> + hwaddr addr, hwaddr size,
> + uint32_t reboot, uint32_t poweroff,
> + bool sifive_test_compat)
> +{
> + uint32_t syscon_phandle;
> + char *name;
> +
> + name = g_strdup_printf("/soc/syscon@%"HWADDR_PRIx, addr);
> + qemu_fdt_add_subnode(fdt, name);
> +
> + if (sifive_test_compat) {
> + static const char * const compat[3] = {
> + "sifive,test1", "sifive,test0", "syscon"
> + };
> +
> + qemu_fdt_setprop_string_array(fdt, name, "compatible",
> + (char **)&compat,
> ARRAY_SIZE(compat));
> + } else {
> + qemu_fdt_setprop_string(fdt, name, "compatible", "syscon");
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr,
> + 2, size);
> +
> + syscon_phandle = next_phandle ? (*next_phandle)++ :
> qemu_fdt_alloc_phandle(fdt);
> + qemu_fdt_setprop_cell(fdt, name, "phandle", syscon_phandle);
> +
> + g_free(name);
> +
> + name = g_strdup_printf("/reboot");
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-
> reboot");
> + qemu_fdt_setprop_cell(fdt, name, "regmap", syscon_phandle);
> + qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> + qemu_fdt_setprop_cell(fdt, name, "value", reboot);
> + g_free(name);
> +
> + name = g_strdup_printf("/poweroff");
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-
> poweroff");
> + qemu_fdt_setprop_cell(fdt, name, "regmap", syscon_phandle);
> + qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> + qemu_fdt_setprop_cell(fdt, name, "value", poweroff);
> + g_free(name);
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index e48337dfd9..ab6c53c78a 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -768,47 +768,6 @@ static void create_fdt_pcie(RISCVVirtState *s,
> create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
> }
>
> -static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle)
> -{
> - char *name;
> - uint32_t test_phandle;
> - MachineState *ms = MACHINE(s);
> -
> - test_phandle = (*phandle)++;
> - name = g_strdup_printf("/soc/test@%"HWADDR_PRIx,
> - s->memmap[VIRT_TEST].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - {
> - static const char * const compat[3] = {
> - "sifive,test1", "sifive,test0", "syscon"
> - };
> - qemu_fdt_setprop_string_array(ms->fdt, name, "compatible",
> - (char **)&compat,
> ARRAY_SIZE(compat));
> - }
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[VIRT_TEST].base,
> - 2, s->memmap[VIRT_TEST].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle);
> - test_phandle = qemu_fdt_get_phandle(ms->fdt, name);
> - g_free(name);
> -
> - name = g_strdup_printf("/reboot");
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-
> reboot");
> - qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle);
> - qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_RESET);
> - g_free(name);
> -
> - name = g_strdup_printf("/poweroff");
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-
> poweroff");
> - qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle);
> - qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_PASS);
> - g_free(name);
> -}
> -
> static void create_fdt_uart(RISCVVirtState *s,
> uint32_t irq_mmio_phandle, int memId,
> int irqNo)
> {
> @@ -994,7 +953,10 @@ static void finalize_fdt(RISCVVirtState *s)
> create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
> iommu_sys_phandle);
>
> - create_fdt_reset(s, &phandle);
> + riscv_create_fdt_syscon(MACHINE(s)->fdt, &phandle,
> + s->memmap[VIRT_TEST].base,
> + s->memmap[VIRT_TEST].size,
> + FINISHER_RESET, FINISHER_PASS, true);
>
> create_fdt_uarts(s, irq_mmio_phandle);
>
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index b422da6aef..e377682b32 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -39,4 +39,8 @@ void riscv_create_fdt_plic(void *fdt, hwaddr addr,
> uint64_t size,
> bool numa_enabled, int socket);
> void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char
> *pmu_name);
> void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr
> flashsize);
> +void riscv_create_fdt_syscon(void *fdt, uint32_t *next_phandle,
> + hwaddr addr, hwaddr size,
> + uint32_t reboot, uint32_t poweroff,
> + bool sifive_test_compat);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 02/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
2026-08-28 20:39 ` [PATCH v5 02/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
@ 2026-09-01 4:45 ` Alistair Francis
0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 4:45 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Add a common helper to create a cfi-flash compatible flash subnode.
>
> This change only affects the existing 'virt' board for now but it
> will
> be used by the future 'riscv-server-ref' board in the future.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> Reviewed-by: Chao Liu <chao.liu@processmission.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 12 ++++++++++++
> hw/riscv/virt.c | 18 ++----------------
> include/hw/riscv/fdt-common.h | 1 +
> 3 files changed, 15 insertions(+), 16 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 3a8da03cfb..6fcc1ce21f 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -283,3 +283,15 @@ void riscv_pmu_generate_fdt_node(void *fdt,
> uint32_t cmask, char *pmu_name)
> qemu_fdt_setprop(fdt, pmu_name, "riscv,event-to-mhpmcounters",
> fdt_event_ctr_map, sizeof(fdt_event_ctr_map));
> }
> +
> +void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr
> flashsize)
> +{
> + g_autofree char *name = g_strdup_printf("/flash@%" PRIx64,
> flashbase);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, flashbase, 2, flashsize,
> + 2, flashbase + flashsize, 2,
> flashsize);
> + qemu_fdt_setprop_cell(fdt, name, "bank-width", 4);
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index b796220fc2..e48337dfd9 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -867,21 +867,6 @@ static void create_fdt_rtc(RISCVVirtState *s,
> }
> }
>
> -static void create_fdt_flash(RISCVVirtState *s)
> -{
> - MachineState *ms = MACHINE(s);
> - hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
> - hwaddr flashbase = s->memmap[VIRT_FLASH].base;
> - g_autofree char *name = g_strdup_printf("/flash@%" PRIx64,
> flashbase);
> -
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible", "cfi-
> flash");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, flashbase, 2, flashsize,
> - 2, flashbase + flashsize, 2,
> flashsize);
> - qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4);
> -}
> -
> static void create_fdt_fw_cfg(RISCVVirtState *s)
> {
> MachineState *ms = MACHINE(s);
> @@ -1043,7 +1028,8 @@ static void create_fdt(RISCVVirtState *s)
>
> qemu_fdt_add_subnode(ms->fdt, "/aliases");
>
> - create_fdt_flash(s);
> + riscv_create_fdt_flash(ms->fdt, s->memmap[VIRT_FLASH].base,
> + s->memmap[VIRT_FLASH].size / 2);
> create_fdt_fw_cfg(s);
> create_fdt_pmu(s);
> }
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index 371971d79d..b422da6aef 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -38,4 +38,5 @@ void riscv_create_fdt_plic(void *fdt, hwaddr addr,
> uint64_t size,
> uint32_t cells_size, uint32_t
> ndev_sources,
> bool numa_enabled, int socket);
> void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char
> *pmu_name);
> +void riscv_create_fdt_flash(void *fdt, hwaddr flashbase, hwaddr
> flashsize);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 04/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
2026-08-28 20:39 ` [PATCH v5 04/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
@ 2026-09-01 4:47 ` Alistair Francis
0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 4:47 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Both the 'virt' board and the future 'riscv-server-ref' boards uses
> an
> iommu-sys device that is declared in the DT. Create a helper to
> encapsulate the logic and avoid copy/pasting stuff between boards.
>
> The helper will return the iommu phandle value instead of returning
> void
> and writing the used phandle in an extra argument.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> Reviewed-by: Chao Liu <chao.liu@processmission.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 35 ++++++++++++++++++++++++
> hw/riscv/virt.c | 50 ++++++---------------------------
> --
> include/hw/riscv/fdt-common.h | 5 ++++
> 3 files changed, 48 insertions(+), 42 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index eac5ca9322..88589330fb 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -13,6 +13,8 @@
> #include "hw/core/boards.h"
> #include "hw/riscv/fdt-common.h"
> #include "target/riscv/cpu_bits.h"
> +#include "hw/riscv/riscv-iommu-bits.h"
> +#include "hw/riscv/iommu.h"
>
> void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size)
> @@ -349,3 +351,36 @@ void riscv_create_fdt_syscon(void *fdt, uint32_t
> *next_phandle,
> qemu_fdt_setprop_cell(fdt, name, "value", poweroff);
> g_free(name);
> }
> +
> +uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr,
> hwaddr size,
> + uint32_t *next_phandle,
> + uint32_t irq_chip,
> + uint32_t msi_phandle,
> + uint32_t iommu_sys_irq)
> +{
> + const char comp[] = "riscv,iommu";
> + g_autofree char *iommu_node = NULL;
> + uint32_t iommu_phandle;
> +
> + iommu_node = g_strdup_printf("/soc/iommu@%"HWADDR_PRIx, addr);
> + qemu_fdt_add_subnode(fdt, iommu_node);
> +
> + qemu_fdt_setprop(fdt, iommu_node, "compatible", comp,
> sizeof(comp));
> + qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
> +
> + iommu_phandle = next_phandle ? (*next_phandle)++ :
> qemu_fdt_alloc_phandle(fdt);
> + qemu_fdt_setprop_cell(fdt, iommu_node, "phandle",
> iommu_phandle);
> +
> + qemu_fdt_setprop_sized_cells(fdt, iommu_node, "reg", 2, addr, 2,
> size);
> + qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent",
> irq_chip);
> +
> + qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts",
> + iommu_sys_irq + RISCV_IOMMU_INTR_CQ, FDT_IRQ_TYPE_EDGE_LOW,
> + iommu_sys_irq + RISCV_IOMMU_INTR_FQ, FDT_IRQ_TYPE_EDGE_LOW,
> + iommu_sys_irq + RISCV_IOMMU_INTR_PM, FDT_IRQ_TYPE_EDGE_LOW,
> + iommu_sys_irq + RISCV_IOMMU_INTR_PQ, FDT_IRQ_TYPE_EDGE_LOW);
> +
> + qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent",
> msi_phandle);
> +
> + return iommu_phandle;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index ab6c53c78a..8a165f4d9e 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -869,46 +869,6 @@ static void
> create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf)
> bdf + 1, iommu_phandle, bdf + 1, 0xffff -
> bdf);
> }
>
> -static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t
> irq_chip,
> - uint32_t msi_phandle,
> - uint32_t *iommu_sys_phandle)
> -{
> - const char comp[] = "riscv,iommu";
> - void *fdt = MACHINE(s)->fdt;
> - uint32_t iommu_phandle;
> - g_autofree char *iommu_node = NULL;
> - hwaddr addr = s->memmap[VIRT_IOMMU_SYS].base;
> - hwaddr size = s->memmap[VIRT_IOMMU_SYS].size;
> - uint32_t iommu_irq_map[RISCV_IOMMU_INTR_COUNT] = {
> - IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_CQ,
> - IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_FQ,
> - IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PM,
> - IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PQ,
> - };
> -
> - iommu_node = g_strdup_printf("/soc/iommu@%x",
> - (unsigned int) s-
> >memmap[VIRT_IOMMU_SYS].base);
> - iommu_phandle = qemu_fdt_alloc_phandle(fdt);
> - qemu_fdt_add_subnode(fdt, iommu_node);
> -
> - qemu_fdt_setprop(fdt, iommu_node, "compatible", comp,
> sizeof(comp));
> - qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1);
> - qemu_fdt_setprop_cell(fdt, iommu_node, "phandle",
> iommu_phandle);
> -
> - qemu_fdt_setprop_sized_cells(fdt, iommu_node, "reg", 2, addr, 2,
> size);
> - qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent",
> irq_chip);
> -
> - qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts",
> - iommu_irq_map[0], FDT_IRQ_TYPE_EDGE_LOW,
> - iommu_irq_map[1], FDT_IRQ_TYPE_EDGE_LOW,
> - iommu_irq_map[2], FDT_IRQ_TYPE_EDGE_LOW,
> - iommu_irq_map[3], FDT_IRQ_TYPE_EDGE_LOW);
> -
> - qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent",
> msi_phandle);
> -
> - *iommu_sys_phandle = iommu_phandle;
> -}
> -
> static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf)
> {
> const char comp[] = "riscv,pci-iommu";
> @@ -947,8 +907,14 @@ static void finalize_fdt(RISCVVirtState *s)
> create_fdt_virtio(s, irq_virtio_phandle);
>
> if (virt_is_iommu_sys_enabled(s)) {
> - create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle,
> - &iommu_sys_phandle);
> + iommu_sys_phandle =
> + riscv_create_fdt_riscv_iommu_sys(MACHINE(s)->fdt,
> + s-
> >memmap[VIRT_IOMMU_SYS].base,
> + s-
> >memmap[VIRT_IOMMU_SYS].size,
> + &phandle,
> + irq_mmio_phandle,
> + msi_pcie_phandle,
> + IOMMU_SYS_IRQ);
> }
> create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
> iommu_sys_phandle);
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index e377682b32..65711468b8 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -43,4 +43,9 @@ void riscv_create_fdt_syscon(void *fdt, uint32_t
> *next_phandle,
> hwaddr addr, hwaddr size,
> uint32_t reboot, uint32_t poweroff,
> bool sifive_test_compat);
> +uint32_t riscv_create_fdt_riscv_iommu_sys(void *fdt, hwaddr addr,
> hwaddr size,
> + uint32_t *next_phandle,
> + uint32_t irq_chip,
> + uint32_t msi_phandle,
> + uint32_t iommu_sys_irq);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
2026-08-28 20:39 ` [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
2026-08-29 3:08 ` Chao Liu via qemu development
@ 2026-09-01 4:49 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 4:49 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> The pcie FDT is quite tedious but can be parametrized into a helper.
> This is going to benefit only the 'virt' board for now but it will be
> used by the 'riscv-server-ref' board in the near future too.
>
> Some other changes made:
>
> - FDT related macros are moved to fdt-common.h. Only a couple are
> being
> used by the helper ATM but more will be added in the next patches;
> - an RISCVAIAType enum is created. There are several FDTs that
> depends
> on the active AIA type being used, and we want a way to represent
> the
> different AIA modes that doesn't re-use the 'virt' specific
> VIRT_AIA_*
> macros. The enum vals are equivalent by design - we want "s-
> >aia_type"
> to be used by 'virt' when calling the fdt helpers, and other boards
> will use "AIA_*" macros in their code.
>
> No FDT changes made.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 111
> ++++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 111 +++-----------------------------
> --
> include/hw/riscv/fdt-common.h | 29 +++++++++
> include/hw/riscv/virt.h | 15 -----
> 4 files changed, 149 insertions(+), 117 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 88589330fb..38813b6aa7 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -15,6 +15,8 @@
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pcie_host.h"
>
> void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size)
> @@ -384,3 +386,112 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void
> *fdt, hwaddr addr, hwaddr size,
>
> return iommu_phandle;
> }
> +
> +static void create_pcie_irq_map(void *fdt, char *nodename,
> + uint32_t irqchip_phandle,
> + RISCVAIAType aia_type, uint32_t
> pcie_irq)
> +{
> + int pin, dev;
> + uint32_t irq_map_stride = 0;
> + uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
> + FDT_MAX_INT_MAP_WIDTH] = {};
> + uint32_t *irq_map = full_irq_map;
> +
> + /*
> + * This code creates a standard swizzle of interrupts such that
> + * each device's first interrupt is based on it's PCI_SLOT
> number.
> + * (See pci_swizzle_map_irq_fn())
> + *
> + * We only need one entry per interrupt in the table (not one
> per
> + * possible slot) seeing the interrupt-map-mask will allow the
> table
> + * to wrap to any number of devices.
> + */
> + for (dev = 0; dev < PCI_NUM_PINS; dev++) {
> + int devfn = dev * 0x8;
> +
> + for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> + int irq_nr = pcie_irq + ((pin + PCI_SLOT(devfn)) %
> PCI_NUM_PINS);
> + int i = 0;
> +
> + /* Fill PCI address cells */
> + irq_map[i] = cpu_to_be32(devfn << 8);
> + i += FDT_PCI_ADDR_CELLS;
> +
> + /* Fill PCI Interrupt cells */
> + irq_map[i] = cpu_to_be32(pin + 1);
> + i += FDT_PCI_INT_CELLS;
> +
> + /* Fill interrupt controller phandle and cells */
> + irq_map[i++] = cpu_to_be32(irqchip_phandle);
> + irq_map[i++] = cpu_to_be32(irq_nr);
> +
> + if (aia_type != AIA_TYPE_NONE) {
> + irq_map[i++] = cpu_to_be32(0x4);
> + }
> +
> + if (!irq_map_stride) {
> + irq_map_stride = i;
> + }
> + irq_map += irq_map_stride;
> + }
> + }
> +
> + qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
> + PCI_NUM_PINS * PCI_NUM_PINS *
> + irq_map_stride * sizeof(uint32_t));
> +
> + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
> + 0x1800, 0, 0, 0x7);
> +}
> +
> +/*
> + * NOTE: this function uses a "/soc/pci@..." FDT subnode that
> + * should be created beforehand.
> + */
> +void riscv_create_fdt_pcie(void *fdt, int aia_type, bool
> has_iommu_sys,
> + const MemMapEntry *pcie_ecam,
> + const MemMapEntry *pcie_pio,
> + 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)
> +{
> + g_autofree char *name = NULL;
> +
> + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, pcie_ecam-
> >base);
> + qemu_fdt_setprop_cell(fdt, name, "#address-cells",
> FDT_PCI_ADDR_CELLS);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells",
> FDT_PCI_INT_CELLS);
> + qemu_fdt_setprop_cell(fdt, name, "#size-cells", 0x2);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "pci-host-ecam-
> generic");
> + qemu_fdt_setprop_string(fdt, name, "device_type", "pci");
> + qemu_fdt_setprop_cell(fdt, name, "linux,pci-domain", 0);
> +
> + qemu_fdt_setprop_cells(fdt, name, "bus-range", 0,
> + pcie_ecam->size / PCIE_MMCFG_SIZE_MIN -
> 1);
> + qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> +
> + if (aia_type == AIA_TYPE_APLIC_IMSIC) {
> + qemu_fdt_setprop_cell(fdt, name, "msi-parent",
> msi_pcie_phandle);
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2,
> + pcie_ecam->base, 2, pcie_ecam-
> >size);
> +
> + qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> + 1, FDT_PCI_RANGE_IOPORT, 2, 0,
> + 2, pcie_pio->base, 2, pcie_pio->size,
> + 1, FDT_PCI_RANGE_MMIO,
> + 2, pcie_mmio->base,
> + 2, pcie_mmio->base, 2, pcie_mmio->size,
> + 1, FDT_PCI_RANGE_MMIO_64BIT,
> + 2, high_pcie->base,
> + 2, high_pcie->base, 2, high_pcie->size);
> +
> + if (has_iommu_sys) {
> + qemu_fdt_setprop_cells(fdt, name, "iommu-map",
> + 0, iommu_sys_phandle, 0, 0x10000);
> + }
> +
> + create_pcie_irq_map(fdt, name, irq_pcie_phandle, aia_type,
> pcie_irq);
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 8a165f4d9e..a28e6d200a 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -180,61 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
> sysmem);
> }
>
> -static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char
> *nodename,
> - uint32_t irqchip_phandle)
> -{
> - int pin, dev;
> - uint32_t irq_map_stride = 0;
> - uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS *
> - FDT_MAX_INT_MAP_WIDTH] = {};
> - uint32_t *irq_map = full_irq_map;
> -
> - /*
> - * This code creates a standard swizzle of interrupts such that
> - * each device's first interrupt is based on it's PCI_SLOT
> number.
> - * (See pci_swizzle_map_irq_fn())
> - *
> - * We only need one entry per interrupt in the table (not one
> per
> - * possible slot) seeing the interrupt-map-mask will allow the
> table
> - * to wrap to any number of devices.
> - */
> - for (dev = 0; dev < PCI_NUM_PINS; dev++) {
> - int devfn = dev * 0x8;
> -
> - for (pin = 0; pin < PCI_NUM_PINS; pin++) {
> - int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) %
> PCI_NUM_PINS);
> - int i = 0;
> -
> - /* Fill PCI address cells */
> - irq_map[i] = cpu_to_be32(devfn << 8);
> - i += FDT_PCI_ADDR_CELLS;
> -
> - /* Fill PCI Interrupt cells */
> - irq_map[i] = cpu_to_be32(pin + 1);
> - i += FDT_PCI_INT_CELLS;
> -
> - /* Fill interrupt controller phandle and cells */
> - irq_map[i++] = cpu_to_be32(irqchip_phandle);
> - irq_map[i++] = cpu_to_be32(irq_nr);
> - if (s->aia_type != VIRT_AIA_TYPE_NONE) {
> - irq_map[i++] = cpu_to_be32(0x4);
> - }
> -
> - if (!irq_map_stride) {
> - irq_map_stride = i;
> - }
> - irq_map += irq_map_stride;
> - }
> - }
> -
> - qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
> - PCI_NUM_PINS * PCI_NUM_PINS *
> - irq_map_stride * sizeof(uint32_t));
> -
> - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
> - 0x1800, 0, 0, 0x7);
> -}
> -
> static void create_fdt_socket_aclint(RISCVVirtState *s,
> int socket,
> uint32_t *intc_phandles)
> @@ -723,51 +668,6 @@ static void create_fdt_virtio(RISCVVirtState *s,
> uint32_t irq_virtio_phandle)
> }
> }
>
> -static void create_fdt_pcie(RISCVVirtState *s,
> - uint32_t irq_pcie_phandle,
> - uint32_t msi_pcie_phandle,
> - uint32_t iommu_sys_phandle)
> -{
> - g_autofree char *name = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx,
> - s->memmap[VIRT_PCIE_ECAM].base);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells",
> - FDT_PCI_ADDR_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells",
> - FDT_PCI_INT_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "pci-host-ecam-generic");
> - qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci");
> - qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0);
> - qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0,
> - s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> - qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0);
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent",
> msi_pcie_phandle);
> - }
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", 2,
> - s->memmap[VIRT_PCIE_ECAM].base, 2, s-
> >memmap[VIRT_PCIE_ECAM].size);
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges",
> - 1, FDT_PCI_RANGE_IOPORT, 2, 0,
> - 2, s->memmap[VIRT_PCIE_PIO].base, 2, s-
> >memmap[VIRT_PCIE_PIO].size,
> - 1, FDT_PCI_RANGE_MMIO,
> - 2, s->memmap[VIRT_PCIE_MMIO].base,
> - 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s-
> >memmap[VIRT_PCIE_MMIO].size,
> - 1, FDT_PCI_RANGE_MMIO_64BIT,
> - 2, virt_high_pcie_memmap.base,
> - 2, virt_high_pcie_memmap.base, 2,
> virt_high_pcie_memmap.size);
> -
> - if (virt_is_iommu_sys_enabled(s)) {
> - qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map",
> - 0, iommu_sys_phandle, 0, 0x10000);
> - }
> -
> - create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle);
> -}
> -
> static void create_fdt_uart(RISCVVirtState *s,
> uint32_t irq_mmio_phandle, int memId,
> int irqNo)
> {
> @@ -916,8 +816,15 @@ static void finalize_fdt(RISCVVirtState *s)
> msi_pcie_phandle,
> IOMMU_SYS_IRQ);
> }
> - create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle,
> - iommu_sys_phandle);
> +
> + riscv_create_fdt_pcie(MACHINE(s)->fdt, s->aia_type,
> + virt_is_iommu_sys_enabled(s),
> + &s->memmap[VIRT_PCIE_ECAM],
> + &s->memmap[VIRT_PCIE_PIO],
> + &s->memmap[VIRT_PCIE_MMIO],
> + &virt_high_pcie_memmap,
> + irq_pcie_phandle, msi_pcie_phandle,
> + iommu_sys_phandle, PCIE_IRQ);
>
> riscv_create_fdt_syscon(MACHINE(s)->fdt, &phandle,
> s->memmap[VIRT_TEST].base,
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index 65711468b8..3750230865 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -11,6 +11,27 @@
>
> #include "target/riscv/cpu.h"
>
> +#define FDT_PCI_ADDR_CELLS 3
> +#define FDT_PCI_INT_CELLS 1
> +#define FDT_PLIC_ADDR_CELLS 0
> +#define FDT_PLIC_INT_CELLS 1
> +#define FDT_APLIC_INT_CELLS 2
> +#define FDT_APLIC_ADDR_CELLS 0
> +#define FDT_IMSIC_INT_CELLS 0
> +#define FDT_MAX_INT_CELLS 2
> +#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS +
> FDT_PCI_INT_CELLS + \
> + 1 + FDT_MAX_INT_CELLS)
> +#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS +
> FDT_PCI_INT_CELLS + \
> + 1 + FDT_PLIC_INT_CELLS)
> +#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS +
> FDT_PCI_INT_CELLS + \
> + 1 + FDT_APLIC_INT_CELLS)
> +
> +typedef enum RISCVAIAType {
> + AIA_TYPE_NONE = 0,
> + AIA_TYPE_APLIC,
> + AIA_TYPE_APLIC_IMSIC,
> +} RISCVAIAType;
> +
> void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t
> size,
> @@ -48,4 +69,12 @@ uint32_t riscv_create_fdt_riscv_iommu_sys(void
> *fdt, hwaddr addr, hwaddr size,
> uint32_t irq_chip,
> uint32_t msi_phandle,
> uint32_t iommu_sys_irq);
> +void riscv_create_fdt_pcie(void *fdt, int aia_type, bool
> has_iommu_sys,
> + const MemMapEntry *pcie_ecam,
> + const MemMapEntry *pcie_pio,
> + 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);
> #endif
> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> index 7c862b0da2..e516898f9a 100644
> --- a/include/hw/riscv/virt.h
> +++ b/include/hw/riscv/virt.h
> @@ -121,21 +121,6 @@ enum {
> #define VIRT_PLIC_SIZE(__num_context) \
> (VIRT_PLIC_CONTEXT_BASE + (__num_context) *
> VIRT_PLIC_CONTEXT_STRIDE)
>
> -#define FDT_PCI_ADDR_CELLS 3
> -#define FDT_PCI_INT_CELLS 1
> -#define FDT_PLIC_ADDR_CELLS 0
> -#define FDT_PLIC_INT_CELLS 1
> -#define FDT_APLIC_INT_CELLS 2
> -#define FDT_APLIC_ADDR_CELLS 0
> -#define FDT_IMSIC_INT_CELLS 0
> -#define FDT_MAX_INT_CELLS 2
> -#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS +
> FDT_PCI_INT_CELLS + \
> - 1 + FDT_MAX_INT_CELLS)
> -#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS +
> FDT_PCI_INT_CELLS + \
> - 1 + FDT_PLIC_INT_CELLS)
> -#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS +
> FDT_PCI_INT_CELLS + \
> - 1 + FDT_APLIC_INT_CELLS)
> -
> bool virt_is_acpi_enabled(RISCVVirtState *s);
> bool virt_is_iommu_sys_enabled(RISCVVirtState *s);
> void virt_acpi_setup(RISCVVirtState *vms);
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
2026-08-28 20:39 ` [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
2026-08-29 3:08 ` Chao Liu via qemu development
@ 2026-09-01 4:51 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 4:51 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> 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
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 98 ++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 108 +++++---------------------------
> --
> include/hw/riscv/fdt-common.h | 21 +++++++
> 3 files changed, 133 insertions(+), 94 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 38813b6aa7..ae24ad0011 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 *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size)
> @@ -495,3 +497,99 @@ void riscv_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;
> + g_autofree uint32_t *imsic_cells = NULL;
> + g_autofree uint32_t *imsic_regs = NULL;
> + uint32_t imsic_max_hart_per_socket = 0;
> + static const char * const imsic_compat[2] = {
> + "qemu,imsics", "riscv,imsics"
> + };
> +
> + imsic_cells = g_new0(uint32_t, props->smp_cpus * 2);
> + imsic_regs = g_new0(uint32_t, props->socket_count * 4);
> +
> + for (int 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);
> + }
> +
> + for (int socket = 0; socket < props->socket_count; socket++) {
> + hwaddr imsic_addr = base_addr + socket * props-
> >imsic_group_max_size;
> + uint32_t imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) *
> + soc[socket].num_harts;
> +
> + imsic_regs[socket * 4 + 0] = cpu_to_be32(imsic_addr >> 32);
> + 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 riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *props,
> + uint32_t *next_phandle, uint32_t
> *intc_phandles,
> + uint32_t *msi_m_phandle, uint32_t
> *msi_s_phandle)
> +{
> + if (next_phandle) {
> + *msi_m_phandle = (*next_phandle)++;
> + *msi_s_phandle = (*next_phandle)++;
> + } else {
> + *msi_m_phandle = qemu_fdt_alloc_phandle(fdt);
> + *msi_s_phandle = qemu_fdt_alloc_phandle(fdt);
> + }
> +
> + 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 a28e6d200a..468ec90696 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -320,98 +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_size;
> - hwaddr imsic_addr;
> - 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] = cpu_to_be32(imsic_addr >> 32);
> - 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)
> {
> @@ -585,8 +493,20 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
> }
>
> if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - create_fdt_imsic(s, phandle, intc_phandles,
> - &msi_m_phandle, &msi_s_phandle);
> + 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
> + };
> +
> + riscv_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 3750230865..182c03d8ce 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,22 @@ 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 *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t
> size,
> @@ -77,4 +95,7 @@ void riscv_create_fdt_pcie(void *fdt, int aia_type,
> bool has_iommu_sys,
> uint32_t irq_pcie_phandle,
> uint32_t msi_pcie_phandle,
> uint32_t iommu_sys_phandle, uint32_t
> pcie_irq);
> +void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
> + uint32_t *next_phandle, uint32_t
> *intc_phandles,
> + uint32_t *msi_m_phandle, uint32_t
> *msi_s_phandle);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
2026-08-28 20:39 ` [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
2026-08-29 3:09 ` Chao Liu via qemu development
@ 2026-09-01 5:14 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:14 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Similar to what we did with 'imsic' in the previous patch, including
> creating a helper struct to encapsulate the extra arguments required
> to
> create the FDT.
>
> TODO: I believe the tt-atlantis board can use this same helper too.
> We
> just need to verify how to map the phandles used by it and what the
> helper is using (which was inherited by the 'virt' board).
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 109 ++++++++++++++++++++++++++
> hw/riscv/virt.c | 139 ++++++--------------------------
> --
> include/hw/riscv/fdt-common.h | 19 +++++
> 3 files changed, 151 insertions(+), 116 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index ae24ad0011..d815c5adff 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -11,6 +11,7 @@
> #include "qemu/error-report.h"
> #include "system/device_tree.h"
> #include "hw/core/boards.h"
> +#include "hw/core/sysbus-fdt.h"
> #include "hw/riscv/fdt-common.h"
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> @@ -593,3 +594,111 @@ void riscv_create_fdt_imsic(void *fdt,
> IMSICFdtProps *props,
> imsic_num_bits(props->aia_guests + 1));
>
> }
> +
> +/* Caller must free string after use */
> +static char *fdt_get_aplic_nodename(hwaddr aplic_addr)
> +{
> + return g_strdup_printf("/soc/interrupt-controller@%"HWADDR_PRIx,
> + aplic_addr);
> +}
> +
> +static void create_fdt_one_aplic(void *fdt, APLICFdtProps *props,
> + hwaddr aplic_addr, uint32_t
> aplic_size,
> + uint32_t msi_phandle,
> + uint32_t *intc_phandles,
> + uint32_t aplic_phandle,
> + uint32_t aplic_child_phandle,
> + bool m_mode)
> +{
> + g_autofree char *aplic_name =
> fdt_get_aplic_nodename(aplic_addr);
> + g_autofree uint32_t *aplic_cells = g_new0(uint32_t, props-
> >num_harts * 2);
> + static const char * const aplic_compat[2] = {
> + "qemu,aplic", "riscv,aplic"
> + };
> +
> + for (int cpu = 0; cpu < props->num_harts; cpu++) {
> + aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> + aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT :
> IRQ_S_EXT);
> + }
> +
> + qemu_fdt_add_subnode(fdt, aplic_name);
> + qemu_fdt_setprop_string_array(fdt, aplic_name, "compatible",
> + (char **)&aplic_compat,
> + ARRAY_SIZE(aplic_compat));
> + qemu_fdt_setprop_cell(fdt, aplic_name, "#address-cells",
> + FDT_APLIC_ADDR_CELLS);
> + qemu_fdt_setprop_cell(fdt, aplic_name,
> + "#interrupt-cells", FDT_APLIC_INT_CELLS);
> + qemu_fdt_setprop(fdt, aplic_name, "interrupt-controller", NULL,
> 0);
> +
> + if (props->aia_type == AIA_TYPE_APLIC) {
> + qemu_fdt_setprop(fdt, aplic_name, "interrupts-extended",
> + aplic_cells, props->num_harts *
> sizeof(uint32_t) * 2);
> + } else {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "msi-parent",
> msi_phandle);
> + }
> +
> + qemu_fdt_setprop_sized_cells(fdt, aplic_name, "reg",
> + 2, aplic_addr, 2, aplic_size);
> + qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,num-sources",
> + props->irqchip_num_sources);
> +
> + if (aplic_child_phandle) {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "riscv,children",
> + aplic_child_phandle);
> + qemu_fdt_setprop_cells(fdt, aplic_name, "riscv,delegation",
> + aplic_child_phandle, 0x1,
> + props->irqchip_num_sources);
> + }
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, aplic_name, "numa-node-id",
> props->socket);
> + }
> +
> + qemu_fdt_setprop_cell(fdt, aplic_name, "phandle",
> aplic_phandle);
> +}
> +
> +void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> + uint32_t msi_m_phandle,
> + uint32_t msi_s_phandle,
> + uint32_t *next_phandle,
> + uint32_t *intc_phandles,
> + uint32_t *aplic_phandles)
> +{
> + uint32_t aplic_m_phandle, aplic_s_phandle;
> + hwaddr aplic_addr;
> +
> + if (next_phandle) {
> + aplic_m_phandle = (*next_phandle)++;
> + aplic_s_phandle = (*next_phandle)++;
> + } else {
> + aplic_m_phandle = qemu_fdt_alloc_phandle(fdt);
> + aplic_s_phandle = qemu_fdt_alloc_phandle(fdt);
> + }
> +
> + if (props->aplic_m) {
> + /* M-level APLIC node */
> + aplic_addr = props->aplic_m->base + (props->aplic_m->size *
> props->socket);
> + create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_m-
> >size,
> + msi_m_phandle, intc_phandles,
> + aplic_m_phandle, aplic_s_phandle,
> + true);
> + }
> +
> + /* S-level APLIC node */
> + aplic_addr = props->aplic_s->base + (props->aplic_s->size *
> props->socket);
> + create_fdt_one_aplic(fdt, props, aplic_addr, props->aplic_s-
> >size,
> + msi_s_phandle, intc_phandles,
> + aplic_s_phandle, 0,
> + false);
> +
> + if (!props->socket && props->platform_bus_irq) {
> + g_autofree char *aplic_name =
> fdt_get_aplic_nodename(aplic_addr);
> + platform_bus_add_all_fdt_nodes(fdt, aplic_name,
> + props->platform_bus->base,
> + props->platform_bus->size,
> + props->platform_bus_irq);
> + }
> +
> + aplic_phandles[props->socket] = aplic_s_phandle;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 468ec90696..a6ec9def16 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -320,113 +320,6 @@ static void
> create_fdt_socket_plic(RISCVVirtState *s,
> }
> }
>
> -/* Caller must free string after use */
> -static char *fdt_get_aplic_nodename(unsigned long aplic_addr)
> -{
> - return g_strdup_printf("/soc/interrupt-controller@%lx",
> aplic_addr);
> -}
> -
> -static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
> - unsigned long aplic_addr, uint32_t
> aplic_size,
> - uint32_t msi_phandle,
> - uint32_t *intc_phandles,
> - uint32_t aplic_phandle,
> - uint32_t aplic_child_phandle,
> - bool m_mode, int num_harts)
> -{
> - int cpu;
> - g_autofree char *aplic_name =
> fdt_get_aplic_nodename(aplic_addr);
> - g_autofree uint32_t *aplic_cells = g_new0(uint32_t, num_harts *
> 2);
> - MachineState *ms = MACHINE(s);
> - static const char * const aplic_compat[2] = {
> - "qemu,aplic", "riscv,aplic"
> - };
> -
> - for (cpu = 0; cpu < num_harts; cpu++) {
> - aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
> - aplic_cells[cpu * 2 + 1] = cpu_to_be32(m_mode ? IRQ_M_EXT :
> IRQ_S_EXT);
> - }
> -
> - qemu_fdt_add_subnode(ms->fdt, aplic_name);
> - qemu_fdt_setprop_string_array(ms->fdt, aplic_name, "compatible",
> - (char **)&aplic_compat,
> - ARRAY_SIZE(aplic_compat));
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "#address-cells",
> - FDT_APLIC_ADDR_CELLS);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name,
> - "#interrupt-cells", FDT_APLIC_INT_CELLS);
> - qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller",
> NULL, 0);
> -
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
> - qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended",
> - aplic_cells, num_harts * sizeof(uint32_t) *
> 2);
> - } else {
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent",
> msi_phandle);
> - }
> -
> - qemu_fdt_setprop_sized_cells(ms->fdt, aplic_name, "reg",
> - 2, aplic_addr, 2, aplic_size);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources",
> - VIRT_IRQCHIP_NUM_SOURCES);
> -
> - if (aplic_child_phandle) {
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children",
> - aplic_child_phandle);
> - qemu_fdt_setprop_cells(ms->fdt, aplic_name,
> "riscv,delegation",
> - aplic_child_phandle, 0x1,
> - VIRT_IRQCHIP_NUM_SOURCES);
> - }
> -
> - riscv_socket_fdt_write_id(ms, aplic_name, socket);
> - qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle",
> aplic_phandle);
> -}
> -
> -static void create_fdt_socket_aplic(RISCVVirtState *s,
> - int socket,
> - uint32_t msi_m_phandle,
> - uint32_t msi_s_phandle,
> - uint32_t *phandle,
> - uint32_t *intc_phandles,
> - uint32_t *aplic_phandles,
> - int num_harts)
> -{
> - unsigned long aplic_addr;
> - MachineState *ms = MACHINE(s);
> - uint32_t aplic_m_phandle, aplic_s_phandle;
> -
> - aplic_m_phandle = (*phandle)++;
> - aplic_s_phandle = (*phandle)++;
> -
> - if (!kvm_enabled()) {
> - /* M-level APLIC node */
> - aplic_addr = s->memmap[VIRT_APLIC_M].base +
> - (s->memmap[VIRT_APLIC_M].size * socket);
> - create_fdt_one_aplic(s, socket, aplic_addr,
> - s->memmap[VIRT_APLIC_M].size,
> - msi_m_phandle, intc_phandles,
> - aplic_m_phandle, aplic_s_phandle,
> - true, num_harts);
> - }
> -
> - /* S-level APLIC node */
> - aplic_addr = s->memmap[VIRT_APLIC_S].base +
> - (s->memmap[VIRT_APLIC_S].size * socket);
> - create_fdt_one_aplic(s, socket, aplic_addr, s-
> >memmap[VIRT_APLIC_S].size,
> - msi_s_phandle, intc_phandles,
> - aplic_s_phandle, 0,
> - false, num_harts);
> -
> - if (!socket) {
> - g_autofree char *aplic_name =
> fdt_get_aplic_nodename(aplic_addr);
> - platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name,
> - s-
> >memmap[VIRT_PLATFORM_BUS].base,
> - s-
> >memmap[VIRT_PLATFORM_BUS].size,
> - VIRT_PLATFORM_BUS_IRQ);
> - }
> -
> - aplic_phandles[socket] = aplic_s_phandle;
> -}
> -
> static void create_fdt_pmu(RISCVVirtState *s)
> {
> g_autofree char *pmu_name = g_strdup_printf("/pmu");
> @@ -453,6 +346,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> int socket_count = riscv_socket_count(ms);
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
> + APLICFdtProps aplic_props;
>
> riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc-
> >harts[0]) :
> @@ -510,15 +404,26 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
> *msi_pcie_phandle = msi_s_phandle;
> }
>
> + if (s->aia_type != VIRT_AIA_TYPE_NONE) {
> + aplic_props.aplic_m = !kvm_enabled() ? &s-
> >memmap[VIRT_APLIC_M] : NULL;
> + aplic_props.aplic_s = &s->memmap[VIRT_APLIC_S];
> + aplic_props.platform_bus = &s->memmap[VIRT_PLATFORM_BUS];
> + aplic_props.platform_bus_irq = VIRT_PLATFORM_BUS_IRQ;
> + aplic_props.socket = 0;
> + aplic_props.num_harts = ms->smp.cpus;
> + aplic_props.numa_enabled = numa_enabled;
> + aplic_props.irqchip_num_sources = VIRT_IRQCHIP_NUM_SOURCES;
> + aplic_props.aia_type = s->aia_type;
> + }
> +
> /*
> * With KVM AIA aplic-imsic, using an irqchip without split
> * mode, we'll use only one APLIC instance.
> */
> if (!virt_use_emulated_aplic(s->aia_type)) {
> - create_fdt_socket_aplic(s, 0,
> - msi_m_phandle, msi_s_phandle,
> phandle,
> - &intc_phandles[0], xplic_phandles,
> - ms->smp.cpus);
> + riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
> + msi_m_phandle, msi_s_phandle,
> phandle,
> + &intc_phandles[0],
> xplic_phandles);
>
> *irq_mmio_phandle = xplic_phandles[0];
> *irq_virtio_phandle = xplic_phandles[0];
> @@ -533,11 +438,13 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
> &intc_phandles[phandle_pos],
> xplic_phandles);
> } else {
> - create_fdt_socket_aplic(s, socket,
> - msi_m_phandle,
> msi_s_phandle, phandle,
> - &intc_phandles[phandle_pos],
> - xplic_phandles,
> - s->soc[socket].num_harts);
> + aplic_props.socket = socket;
> + aplic_props.num_harts = s->soc[socket].num_harts;
> + riscv_create_fdt_socket_aplic(ms->fdt, &aplic_props,
> + msi_m_phandle,
> msi_s_phandle,
> + phandle,
> +
> &intc_phandles[phandle_pos],
> + xplic_phandles);
> }
> }
>
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index 182c03d8ce..8207cfee7b 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -12,6 +12,7 @@
> #include "target/riscv/cpu.h"
> #include "hw/core/boards.h"
> #include "hw/riscv/riscv_hart.h"
> +#include "exec/hwaddr.h"
>
> #define FDT_PCI_ADDR_CELLS 3
> #define FDT_PCI_INT_CELLS 1
> @@ -50,6 +51,18 @@ typedef struct IMSICFdtProps {
> int aia_guests;
> } IMSICFdtProps;
>
> +typedef struct APLICFdtProps {
> + const MemMapEntry *aplic_m;
> + const MemMapEntry *aplic_s;
> + const MemMapEntry *platform_bus;
> + int platform_bus_irq;
> + int socket;
> + int num_harts;
> + bool numa_enabled;
> + int irqchip_num_sources;
> + int aia_type;
> +} APLICFdtProps;
> +
> void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t
> size,
> @@ -98,4 +111,10 @@ void riscv_create_fdt_pcie(void *fdt, int
> aia_type, bool has_iommu_sys,
> void riscv_create_fdt_imsic(void *fdt, IMSICFdtProps *fdt_props,
> uint32_t *next_phandle, uint32_t
> *intc_phandles,
> uint32_t *msi_m_phandle, uint32_t
> *msi_s_phandle);
> +void riscv_create_fdt_socket_aplic(void *fdt, APLICFdtProps *props,
> + uint32_t msi_m_phandle,
> + uint32_t msi_s_phandle,
> + uint32_t *next_phandle,
> + uint32_t *intc_phandles,
> + uint32_t *aplic_phandles);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename
2026-08-28 20:39 ` [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename Daniel Henrique Barboza
2026-08-29 3:10 ` Chao Liu
@ 2026-09-01 5:15 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:15 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: qemu-stable@nongnu.org, qemu-riscv@nongnu.org, palmer@dabbelt.com,
chao.liu@processmission.com, liwei1518@gmail.com,
zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Running 'dtc' to generate a readable fdt for the virt machine produce
> warnings:
>
> $ dtc -I dtb -O dts virt.dtb > virt.dts
> <stdout>: Warning (simple_bus_reg): /soc/mtimer@2000000: simple-bus
> unit address format error, expected "2007ff8"
> <stdout>: Warning (simple_bus_reg): /soc/mtimer@2008000: simple-bus
> unit address format error, expected "200fff8"
>
> This happens because the 'reg' field does not match the address in
> the
> nodename. The right fix, pointed out by Chao in [1], is to make the
> nodename match the reg value:
>
> "In the current QEMU implement, `addr` is the MTIMECMP base address,
> while the MTIME register is located at addr +
> RISCV_ACLINT_DEFAULT_MTIME."
>
> In other words, the 'reg' value is correct but the nodename isn't.
>
> We'll make the fix now, allowing the next patch to move the fixed
> version
> of aclint FDT to fdt-common.
>
> [1]
> https://lore.kernel.org/qemu-devel/apHH1upnh8udUUT-@ChaodeMacBook-Pro.local/
>
> Cc: qemu-stable@nongnu.org
> Suggested-by: Chao Liu <chao.liu@processmission.com>
> Fixes: 954886ea6d ("hw/riscv: virt: Add optional ACLINT support to
> virt machine")
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/virt.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index a6ec9def16..83a4b7710d 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -234,7 +234,8 @@ static void
> create_fdt_socket_aclint(RISCVVirtState *s,
> (s->memmap[VIRT_CLINT].size * socket);
> size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
> }
> - name = g_strdup_printf("/soc/mtimer@%lx", addr);
> + name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> + addr + RISCV_ACLINT_DEFAULT_MTIME);
> qemu_fdt_add_subnode(ms->fdt, name);
> qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> "riscv,aclint-mtimer");
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
2026-08-28 20:39 ` [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
2026-08-29 3:10 ` Chao Liu via qemu development
@ 2026-09-01 5:17 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:17 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Yet another FDT that we want to move to a helper to avoid
> copy/pasting
> code to other boards that will use a mtimer. In particular the
> future
> 'riscv-server-ref' board.
>
> No FDT changes made.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 97 ++++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 102 ++++----------------------------
> --
> include/hw/riscv/fdt-common.h | 11 ++++
> 3 files changed, 120 insertions(+), 90 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d815c5adff..d2ce93ad28 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -16,6 +16,7 @@
> #include "target/riscv/cpu_bits.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/intc/riscv_aclint.h"
> #include "hw/intc/riscv_imsic.h"
> #include "hw/pci/pci.h"
> #include "hw/pci/pcie_host.h"
> @@ -702,3 +703,99 @@ void riscv_create_fdt_socket_aplic(void *fdt,
> APLICFdtProps *props,
>
> aplic_phandles[props->socket] = aplic_s_phandle;
> }
> +
> +void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps
> *props,
> + uint32_t *intc_phandles)
> +{
> + uint32_t aclint_cells_size = props->num_harts * sizeof(uint32_t)
> * 2;
> + g_autofree uint32_t *aclint_mswi_cells = NULL;
> + g_autofree uint32_t *aclint_sswi_cells = NULL;
> + g_autofree uint32_t *aclint_mtimer_cells = NULL;
> + hwaddr addr, size;
> + char *name;
> + int cpu;
> +
> + aclint_mswi_cells = g_new0(uint32_t, props->num_harts * 2);
> + aclint_mtimer_cells = g_new0(uint32_t, props->num_harts * 2);
> + aclint_sswi_cells = g_new0(uint32_t, props->num_harts * 2);
> +
> + for (cpu = 0; cpu < props->num_harts; cpu++) {
> + aclint_mswi_cells[cpu * 2 + 0] =
> cpu_to_be32(intc_phandles[cpu]);
> + aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
> + aclint_mtimer_cells[cpu * 2 + 0] =
> cpu_to_be32(intc_phandles[cpu]);
> + aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
> + aclint_sswi_cells[cpu * 2 + 0] =
> cpu_to_be32(intc_phandles[cpu]);
> + aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
> + }
> +
> + if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
> + addr = props->clint->base + (props->clint->size * props-
> >socket);
> + name = g_strdup_printf("/soc/mswi@%"HWADDR_PRIx, addr);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> "riscv,aclint-mswi");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr, 2,
> RISCV_ACLINT_SWI_SIZE);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_mswi_cells, aclint_cells_size);
> + qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL,
> 0);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props-
> >socket);
> + }
> +
> + g_free(name);
> + }
> +
> + if (props->aia_type == AIA_TYPE_APLIC_IMSIC) {
> + addr = props->clint->base +
> + (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * props->socket);
> + size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
> + } else {
> + addr = props->clint->base + RISCV_ACLINT_SWI_SIZE +
> + (props->clint->size * props->socket);
> + size = props->clint->size - RISCV_ACLINT_SWI_SIZE;
> + }
> +
> + name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> + addr + RISCV_ACLINT_DEFAULT_MTIME);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> + "riscv,aclint-mtimer");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> + 2, size - RISCV_ACLINT_DEFAULT_MTIME,
> + 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> + 2, RISCV_ACLINT_DEFAULT_MTIME);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_mtimer_cells, aclint_cells_size);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props-
> >socket);
> + }
> +
> + g_free(name);
> +
> + if (props->aia_type != AIA_TYPE_APLIC_IMSIC) {
> + addr = props->aclint_sswi->base
> + + (props->aclint_sswi->size * props->socket);
> +
> + name = g_strdup_printf("/soc/sswi@%"HWADDR_PRIx, addr);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> + "riscv,aclint-sswi");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, addr, 2, props->aclint_sswi-
> >size);
> + qemu_fdt_setprop(fdt, name, "interrupts-extended",
> + aclint_sswi_cells, aclint_cells_size);
> + qemu_fdt_setprop(fdt, name, "interrupt-controller", NULL,
> 0);
> + qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 0);
> +
> + if (props->numa_enabled) {
> + qemu_fdt_setprop_cell(fdt, name, "numa-node-id", props-
> >socket);
> + }
> +
> + g_free(name);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 83a4b7710d..717a01da8d 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -180,94 +180,6 @@ static void virt_flash_map(RISCVVirtState *s,
> sysmem);
> }
>
> -static void create_fdt_socket_aclint(RISCVVirtState *s,
> - int socket,
> - uint32_t *intc_phandles)
> -{
> - int cpu;
> - char *name;
> - unsigned long addr, size;
> - uint32_t aclint_cells_size;
> - g_autofree uint32_t *aclint_mswi_cells = NULL;
> - g_autofree uint32_t *aclint_sswi_cells = NULL;
> - g_autofree uint32_t *aclint_mtimer_cells = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts *
> 2);
> - aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts
> * 2);
> - aclint_sswi_cells = g_new0(uint32_t, s->soc[socket].num_harts *
> 2);
> -
> - for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> - aclint_mswi_cells[cpu * 2 + 0] =
> cpu_to_be32(intc_phandles[cpu]);
> - aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT);
> - aclint_mtimer_cells[cpu * 2 + 0] =
> cpu_to_be32(intc_phandles[cpu]);
> - aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER);
> - aclint_sswi_cells[cpu * 2 + 0] =
> cpu_to_be32(intc_phandles[cpu]);
> - aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT);
> - }
> - aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t)
> * 2;
> -
> - if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_CLINT].base +
> - (s->memmap[VIRT_CLINT].size * socket);
> - name = g_strdup_printf("/soc/mswi@%lx", addr);
> -
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-mswi");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr, 2, RISCV_ACLINT_SWI_SIZE);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_mswi_cells, aclint_cells_size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupt-controller",
> NULL, 0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> - }
> -
> - if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_CLINT].base +
> - (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket);
> - size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE;
> - } else {
> - addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> - (s->memmap[VIRT_CLINT].size * socket);
> - size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE;
> - }
> - name = g_strdup_printf("/soc/mtimer@%"HWADDR_PRIx,
> - addr + RISCV_ACLINT_DEFAULT_MTIME);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-mtimer");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> - 2, size - RISCV_ACLINT_DEFAULT_MTIME,
> - 2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> - 2, RISCV_ACLINT_DEFAULT_MTIME);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_mtimer_cells, aclint_cells_size);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> -
> - if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) {
> - addr = s->memmap[VIRT_ACLINT_SSWI].base +
> - (s->memmap[VIRT_ACLINT_SSWI].size * socket);
> -
> - name = g_strdup_printf("/soc/sswi@%lx", addr);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "riscv,aclint-sswi");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, addr, 2, s->memmap[VIRT_ACLINT_SSWI].size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupts-extended",
> - aclint_sswi_cells, aclint_cells_size);
> - qemu_fdt_setprop(ms->fdt, name, "interrupt-controller",
> NULL, 0);
> - qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0);
> - riscv_socket_fdt_write_id(ms, name, socket);
> - g_free(name);
> - }
> -}
> -
> static void create_fdt_socket_plic(RISCVVirtState *s,
> int socket,
> uint32_t *phandle, uint32_t
> *intc_phandles,
> @@ -348,6 +260,7 @@ static void create_fdt_sockets(RISCVVirtState *s,
> bool numa_enabled = riscv_numa_enabled(ms);
> bool is_32_bit = riscv_is_32bit(&s->soc[0]);
> APLICFdtProps aplic_props;
> + ACLINTFdtProps aclint_props;
>
> riscv_fdt_create_cpu_socket_subnode(ms->fdt,
> kvm_enabled() ? kvm_riscv_get_timebase_frequency(&s->soc-
> >harts[0]) :
> @@ -355,6 +268,13 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
>
> intc_phandles = g_new0(uint32_t, ms->smp.cpus);
>
> + if (virt_aclint_allowed() && s->have_aclint) {
> + aclint_props.clint = &s->memmap[VIRT_CLINT];
> + aclint_props.aclint_sswi = &s->memmap[VIRT_ACLINT_SSWI];
> + aclint_props.aia_type = s->aia_type;
> + aclint_props.numa_enabled = numa_enabled;
> + }
> +
> phandle_pos = ms->smp.cpus;
> for (socket = (socket_count - 1); socket >= 0; socket--) {
> hwaddr memaddr = s->memmap[VIRT_DRAM].base +
> @@ -373,8 +293,10 @@ static void create_fdt_sockets(RISCVVirtState
> *s,
> socket,
> riscv_numa_enabled(ms));
>
> if (virt_aclint_allowed() && s->have_aclint) {
> - create_fdt_socket_aclint(s, socket,
> - &intc_phandles[phandle_pos]);
> + aclint_props.socket = socket;
> + aclint_props.num_harts = s->soc[socket].num_harts;
> + riscv_create_fdt_socket_aclint(ms->fdt, &aclint_props,
> +
> &intc_phandles[phandle_pos]);
> } else if (tcg_enabled()) {
> hwaddr clintaddr = s->memmap[VIRT_CLINT].base +
> s->memmap[VIRT_CLINT].size * socket;
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index 8207cfee7b..a45b063f66 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -63,6 +63,15 @@ typedef struct APLICFdtProps {
> int aia_type;
> } APLICFdtProps;
>
> +typedef struct ACLINTFdtProps {
> + const MemMapEntry *clint;
> + const MemMapEntry *aclint_sswi;
> + int socket;
> + int num_harts;
> + int aia_type;
> + bool numa_enabled;
> +} ACLINTFdtProps;
> +
> void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size);
> void riscv_create_fdt_socket_memory(void *fdt, hwaddr addr, uint64_t
> size,
> @@ -117,4 +126,6 @@ void riscv_create_fdt_socket_aplic(void *fdt,
> APLICFdtProps *props,
> uint32_t *next_phandle,
> uint32_t *intc_phandles,
> uint32_t *aplic_phandles);
> +void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps
> *props,
> + uint32_t *intc_phandles);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
2026-08-28 20:39 ` [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
2026-08-29 3:11 ` Chao Liu via
@ 2026-09-01 5:23 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:23 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Add a common uart FDT helper to be used by 'virt' and the future
> 'riscv-server-ref' board.
>
> The 'tt-atlantis' board is left out of this patch because it's going
> through UART related changes and its FDT might change soon, thus it's
> better to wait for the final DT to be determined and then we can
> evaluate whether it can share a common helper.
>
> The "/chosen" and "/alias" changes are UART0 only so we're keeping
> them
> out of the common helper. The board can set both manually as
> appropriate.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 29 +++++++++++++++++++++++++++++
> hw/riscv/virt.c | 35 +++++++++------------------------
> --
> include/hw/riscv/fdt-common.h | 5 +++++
> 3 files changed, 43 insertions(+), 26 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d2ce93ad28..0107aadaad 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -22,6 +22,8 @@
> #include "hw/pci/pcie_host.h"
> #include "hw/riscv/aia.h"
>
> +#define UART_STD_CLOCK_FREQ 3686400 /* 3.6864 MHz */
> +
> void *riscv_create_board_device_tree(const char *model, const char
> *compatible,
> int *fdt_size)
> {
> @@ -799,3 +801,30 @@ void riscv_create_fdt_socket_aclint(void *fdt,
> ACLINTFdtProps *props,
> g_free(name);
> }
> }
> +
> +char *riscv_fdt_get_uart_nodename(hwaddr addr)
> +{
> + return g_strdup_printf("/soc/serial@%"HWADDR_PRIx, addr);
> +}
> +
> +void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> + int uart_irq, int aia_type,
> + uint32_t irq_phandle)
> +{
> + g_autofree char *name = riscv_fdt_get_uart_nodename(uart_mem-
> >base);
> +
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, uart_mem->base,
> + 2, uart_mem->size);
> +
> + qemu_fdt_setprop_cell(fdt, name, "clock-frequency",
> UART_STD_CLOCK_FREQ);
> + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
> irq_phandle);
> +
> + if (aia_type == AIA_TYPE_NONE) {
> + qemu_fdt_setprop_cell(fdt, name, "interrupts", uart_irq);
> + } else {
> + qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq,
> 0x4);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 717a01da8d..3e40513dc1 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -418,39 +418,22 @@ static void create_fdt_virtio(RISCVVirtState
> *s, uint32_t irq_virtio_phandle)
> }
> }
>
> -static void create_fdt_uart(RISCVVirtState *s,
> - uint32_t irq_mmio_phandle, int memId,
> int irqNo)
> +static void create_fdt_uarts(RISCVVirtState *s, uint32_t
> irq_mmio_phandle)
> {
> g_autofree char *name = NULL;
> MachineState *ms = MACHINE(s);
>
> - name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx,
> - s->memmap[memId].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> "ns16550a");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[memId].base,
> - 2, s->memmap[memId].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency",
> 3686400);
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
> irq_mmio_phandle);
> - if (s->aia_type == VIRT_AIA_TYPE_NONE) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", irqNo);
> - } else {
> - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", irqNo,
> 0x4);
> + if (s->uart1_present) {
> + riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART1],
> + UART1_IRQ, s->aia_type,
> irq_mmio_phandle);
> }
>
> - if (VIRT_UART0 == memId) {
> - qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path",
> name);
> - qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0",
> name);
> - }
> -}
> + riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART0],
> UART0_IRQ,
> + s->aia_type, irq_mmio_phandle);
>
> -static void create_fdt_uarts(RISCVVirtState *s, uint32_t
> irq_mmio_phandle)
> -{
> - if (s->uart1_present) {
> - create_fdt_uart(s, irq_mmio_phandle, VIRT_UART1, UART1_IRQ);
> - }
> - create_fdt_uart(s, irq_mmio_phandle, VIRT_UART0, UART0_IRQ);
> + name = riscv_fdt_get_uart_nodename(s->memmap[VIRT_UART0].base);
> + qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path",
> name);
> + qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> }
>
> static void create_fdt_rtc(RISCVVirtState *s,
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index a45b063f66..c8b25348bd 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -128,4 +128,9 @@ void riscv_create_fdt_socket_aplic(void *fdt,
> APLICFdtProps *props,
> uint32_t *aplic_phandles);
> void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps
> *props,
> uint32_t *intc_phandles);
> +/* Caller must free the returned string. */
> +char *riscv_fdt_get_uart_nodename(hwaddr addr);
> +void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> + int uart_irq, int aia_type,
> + uint32_t irq_phandle);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
2026-08-28 20:39 ` [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via
@ 2026-09-01 5:23 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:23 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> The soon to be added 'riscv-server-ref' board will add a rtc FDT
> subnode
> that is similar to what the 'virt' board users. Put it into a helper
> to
> avoid copy/pasting code.
>
> No FDT changes intended.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/fdt-common.c | 21 +++++++++++++++++++++
> hw/riscv/virt.c | 26 ++------------------------
> include/hw/riscv/fdt-common.h | 3 +++
> 3 files changed, 26 insertions(+), 24 deletions(-)
>
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index 0107aadaad..ce2dcb43b4 100644
> --- a/hw/riscv/fdt-common.c
> +++ b/hw/riscv/fdt-common.c
> @@ -828,3 +828,24 @@ void riscv_create_fdt_uart(void *fdt, const
> MemMapEntry *uart_mem,
> qemu_fdt_setprop_cells(fdt, name, "interrupts", uart_irq,
> 0x4);
> }
> }
> +
> +void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
> + int rtc_irq, int aia_type,
> + uint32_t irq_phandle)
> +{
> + g_autofree char *name = NULL;
> +
> + name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
> + rtc_mem->base);
> + qemu_fdt_add_subnode(fdt, name);
> + qemu_fdt_setprop_string(fdt, name, "compatible",
> "google,goldfish-rtc");
> + qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> + 2, rtc_mem->base,
> + 2, rtc_mem->size);
> + qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
> irq_phandle);
> + if (aia_type == AIA_TYPE_NONE) {
> + qemu_fdt_setprop_cell(fdt, name, "interrupts", rtc_irq);
> + } else {
> + qemu_fdt_setprop_cells(fdt, name, "interrupts", rtc_irq,
> 0x4);
> + }
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 3e40513dc1..ccea5784f0 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -436,29 +436,6 @@ static void create_fdt_uarts(RISCVVirtState *s,
> uint32_t irq_mmio_phandle)
> qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name);
> }
>
> -static void create_fdt_rtc(RISCVVirtState *s,
> - uint32_t irq_mmio_phandle)
> -{
> - g_autofree char *name = NULL;
> - MachineState *ms = MACHINE(s);
> -
> - name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx,
> - s->memmap[VIRT_RTC].base);
> - qemu_fdt_add_subnode(ms->fdt, name);
> - qemu_fdt_setprop_string(ms->fdt, name, "compatible",
> - "google,goldfish-rtc");
> - qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> - 2, s->memmap[VIRT_RTC].base,
> - 2, s->memmap[VIRT_RTC].size);
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent",
> - irq_mmio_phandle);
> - if (s->aia_type == VIRT_AIA_TYPE_NONE) {
> - qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", RTC_IRQ);
> - } else {
> - qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ,
> 0x4);
> - }
> -}
> -
> static void create_fdt_fw_cfg(RISCVVirtState *s)
> {
> MachineState *ms = MACHINE(s);
> @@ -566,7 +543,8 @@ static void finalize_fdt(RISCVVirtState *s)
>
> create_fdt_uarts(s, irq_mmio_phandle);
>
> - create_fdt_rtc(s, irq_mmio_phandle);
> + riscv_create_fdt_rtc(MACHINE(s)->fdt, &s->memmap[VIRT_RTC],
> RTC_IRQ,
> + s->aia_type, irq_mmio_phandle);
> }
>
> static void create_fdt(RISCVVirtState *s)
> diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-
> common.h
> index c8b25348bd..eb9db8278d 100644
> --- a/include/hw/riscv/fdt-common.h
> +++ b/include/hw/riscv/fdt-common.h
> @@ -133,4 +133,7 @@ char *riscv_fdt_get_uart_nodename(hwaddr addr);
> void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem,
> int uart_irq, int aia_type,
> uint32_t irq_phandle);
> +void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem,
> + int rtc_irq, int aia_type,
> + uint32_t irq_phandle);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
2026-08-28 20:39 ` [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via qemu development
@ 2026-09-01 5:24 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:24 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> There will be code repetition instances added by the 'riscv-server-
> ref'
> board w.r.t device creation and initialization. Instead of waiting
> for
> that code to land we're adding helpers beforehand. The idea is to
> make
> the new board code shorter and more palatable for reviewers.
>
> A new 'device-common' file is created for such helpers. We'll start
> with the platform bus, a nice piece of software that only the 'virt'
> board uses so far, and the 'riscv-server-ref' will use to support TPM
> devices.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/device-common.c | 48
> ++++++++++++++++++++++++++++++++
> hw/riscv/meson.build | 1 +
> hw/riscv/virt.c | 30 +++-----------------
> include/hw/riscv/device-common.h | 19 +++++++++++++
> 4 files changed, 72 insertions(+), 26 deletions(-)
> create mode 100644 hw/riscv/device-common.c
> create mode 100644 include/hw/riscv/device-common.h
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> new file mode 100644
> index 0000000000..d3c68a9e71
> --- /dev/null
> +++ b/hw/riscv/device-common.c
> @@ -0,0 +1,48 @@
> +/*
> + * RISC-V board helpers for FDT generation.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its
> subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/riscv/device-common.h"
> +
> +#include "hw/core/platform-bus.h"
> +#include "hw/core/qdev.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/core/sysbus.h"
> +#include "qapi/error.h"
> +#include "system/address-spaces.h"
> +#include "system/memory.h"
> +
> +
> +DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> + const MemMapEntry
> *platform_bus_mem,
> + int platform_bus_base_irq,
> + int platform_bus_num_irqs)
> +{
> + MemoryRegion *sysmem = get_system_memory();
> + DeviceState *dev;
> + SysBusDevice *sysbus;
> +
> + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
> + dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
> + qdev_prop_set_uint32(dev, "num_irqs", platform_bus_num_irqs);
> + qdev_prop_set_uint32(dev, "mmio_size", platform_bus_mem->size);
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + sysbus = SYS_BUS_DEVICE(dev);
> + for (int i = 0; i < platform_bus_num_irqs; i++) {
> + int irq = platform_bus_base_irq + i;
> + sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip,
> irq));
> + }
> +
> + memory_region_add_subregion(sysmem,
> + platform_bus_mem->base,
> + sysbus_mmio_get_region(sysbus, 0));
> +
> + return dev;
> +}
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 0d82ceacc4..7aa3c1578d 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -1,6 +1,7 @@
> riscv_ss = ss.source_set()
> riscv_ss.add(files('aia.c'))
> riscv_ss.add(files('boot.c'))
> +riscv_ss.add(files('device-common.c'))
> riscv_ss.add(files('fdt-common.c'))
> riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
> riscv_ss.add(files('riscv_hart.c'))
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index ccea5784f0..a2671ae341 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -35,6 +35,7 @@
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/virt.h"
> #include "hw/riscv/boot.h"
> +#include "hw/riscv/device-common.h"
> #include "hw/riscv/fdt-common.h"
> #include "hw/riscv/machines-qom.h"
> #include "hw/riscv/numa.h"
> @@ -683,31 +684,6 @@ static DeviceState *virt_create_plic(const
> MemMapEntry *memmap, int socket,
> memmap[VIRT_PLIC].size);
> }
>
> -static void create_platform_bus(RISCVVirtState *s, DeviceState
> *irqchip)
> -{
> - DeviceState *dev;
> - SysBusDevice *sysbus;
> - int i;
> - MemoryRegion *sysmem = get_system_memory();
> -
> - dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
> - dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
> - qdev_prop_set_uint32(dev, "num_irqs",
> VIRT_PLATFORM_BUS_NUM_IRQS);
> - qdev_prop_set_uint32(dev, "mmio_size", s-
> >memmap[VIRT_PLATFORM_BUS].size);
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> - s->platform_bus_dev = dev;
> -
> - sysbus = SYS_BUS_DEVICE(dev);
> - for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) {
> - int irq = VIRT_PLATFORM_BUS_IRQ + i;
> - sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip,
> irq));
> - }
> -
> - memory_region_add_subregion(sysmem,
> - s->memmap[VIRT_PLATFORM_BUS].base,
> - sysbus_mmio_get_region(sysbus, 0));
> -}
> -
> static void virt_build_smbios(RISCVVirtState *s)
> {
> MachineClass *mc = MACHINE_GET_CLASS(s);
> @@ -1030,7 +1006,9 @@ static void virt_machine_init(MachineState
> *machine)
>
> gpex_pcie_init(system_memory, pcie_irqchip, s);
>
> - create_platform_bus(s, mmio_irqchip);
> + s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
> + &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
> + VIRT_PLATFORM_BUS_NUM_IRQS);
>
> serial_mm_init(system_memory, s->memmap[VIRT_UART0].base,
> 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193,
> diff --git a/include/hw/riscv/device-common.h
> b/include/hw/riscv/device-common.h
> new file mode 100644
> index 0000000000..12af031bbf
> --- /dev/null
> +++ b/include/hw/riscv/device-common.h
> @@ -0,0 +1,19 @@
> +/*
> + * RISC-V board helpers for FDT generation.
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its
> subsidiaries.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef RISCV_DEVICE_COMMON_H
> +#define RISCV_DEVICE_COMMON_H
> +
> +#include "exec/hwaddr.h"
> +#include "hw/core/qdev.h"
> +
> +DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> + const MemMapEntry
> *platform_bus_mem,
> + int platform_bus_base_irq,
> + int platform_bus_num_irqs);
> +#endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers
2026-08-28 20:39 ` [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via
@ 2026-09-01 5:28 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:28 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Move the flash device creating and flash map initialization to
> device-common.c.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/device-common.c | 44 ++++++++++++++++++++++++
> hw/riscv/virt.c | 57 +++++-------------------------
> --
> include/hw/riscv/device-common.h | 6 ++++
> 3 files changed, 58 insertions(+), 49 deletions(-)
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> index d3c68a9e71..a054cd7114 100644
> --- a/hw/riscv/device-common.c
> +++ b/hw/riscv/device-common.c
> @@ -10,11 +10,13 @@
>
> #include "hw/riscv/device-common.h"
>
> +#include "hw/block/flash.h"
> #include "hw/core/platform-bus.h"
> #include "hw/core/qdev.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/sysbus.h"
> #include "qapi/error.h"
> +#include "qom/object.h"
> #include "system/address-spaces.h"
> #include "system/memory.h"
>
> @@ -46,3 +48,45 @@ DeviceState *riscv_create_platform_bus(DeviceState
> *irqchip,
>
> return dev;
> }
> +
> +PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> + const char *alias_prop_name,
> + int flash_sector_size)
> +{
> + /*
> + * Create a single flash device. We use the same parameters as
> + * the flash devices on the ARM virt board.
> + */
> + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
> +
> + qdev_prop_set_uint64(dev, "sector-length", flash_sector_size);
> + qdev_prop_set_uint8(dev, "width", 4);
> + qdev_prop_set_uint8(dev, "device-width", 2);
> + qdev_prop_set_bit(dev, "big-endian", false);
> + qdev_prop_set_uint16(dev, "id0", 0x89);
> + qdev_prop_set_uint16(dev, "id1", 0x18);
> + qdev_prop_set_uint16(dev, "id2", 0x00);
> + qdev_prop_set_uint16(dev, "id3", 0x00);
> + qdev_prop_set_string(dev, "name", name);
> +
> + object_property_add_child(parent, name, OBJECT(dev));
> + object_property_add_alias(parent, alias_prop_name,
> + OBJECT(dev), "drive");
> +
> + return PFLASH_CFI01(dev);
> +}
> +
> +void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr
> size,
> + MemoryRegion *sysmem, int
> flash_sector_size)
> +{
> + DeviceState *dev = DEVICE(flash);
> +
> + assert(QEMU_IS_ALIGNED(size, flash_sector_size));
> + assert(size / flash_sector_size <= UINT32_MAX);
> +
> + qdev_prop_set_uint32(dev, "num-blocks", size /
> flash_sector_size);
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + memory_region_add_subregion(sysmem, base,
> +
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index a2671ae341..9ff5beae77 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -120,53 +120,12 @@ static MemMapEntry virt_high_pcie_memmap;
>
> #define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
>
> -static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s,
> - const char *name,
> - const char *alias_prop_name)
> -{
> - /*
> - * Create a single flash device. We use the same parameters as
> - * the flash devices on the ARM virt board.
> - */
> - DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01);
> -
> - qdev_prop_set_uint64(dev, "sector-length",
> VIRT_FLASH_SECTOR_SIZE);
> - qdev_prop_set_uint8(dev, "width", 4);
> - qdev_prop_set_uint8(dev, "device-width", 2);
> - qdev_prop_set_bit(dev, "big-endian", false);
> - qdev_prop_set_uint16(dev, "id0", 0x89);
> - qdev_prop_set_uint16(dev, "id1", 0x18);
> - qdev_prop_set_uint16(dev, "id2", 0x00);
> - qdev_prop_set_uint16(dev, "id3", 0x00);
> - qdev_prop_set_string(dev, "name", name);
> -
> - object_property_add_child(OBJECT(s), name, OBJECT(dev));
> - object_property_add_alias(OBJECT(s), alias_prop_name,
> - OBJECT(dev), "drive");
> -
> - return PFLASH_CFI01(dev);
> -}
> -
> static void virt_flash_create(RISCVVirtState *s)
> {
> - s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0");
> - s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1");
> -}
> -
> -static void virt_flash_map1(PFlashCFI01 *flash,
> - hwaddr base, hwaddr size,
> - MemoryRegion *sysmem)
> -{
> - DeviceState *dev = DEVICE(flash);
> -
> - assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE));
> - assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
> - qdev_prop_set_uint32(dev, "num-blocks", size /
> VIRT_FLASH_SECTOR_SIZE);
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -
> - memory_region_add_subregion(sysmem, base,
> -
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
> - 0));
> + s->flash[0] = riscv_flash_create(OBJECT(s), "virt.flash0",
> "pflash0",
> + VIRT_FLASH_SECTOR_SIZE);
> + s->flash[1] = riscv_flash_create(OBJECT(s), "virt.flash1",
> "pflash1",
> + VIRT_FLASH_SECTOR_SIZE);
> }
>
> static void virt_flash_map(RISCVVirtState *s,
> @@ -175,10 +134,10 @@ static void virt_flash_map(RISCVVirtState *s,
> hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2;
> hwaddr flashbase = s->memmap[VIRT_FLASH].base;
>
> - virt_flash_map1(s->flash[0], flashbase, flashsize,
> - sysmem);
> - virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize,
> - sysmem);
> + riscv_init_flash_map(s->flash[0], flashbase, flashsize,
> + sysmem, VIRT_FLASH_SECTOR_SIZE);
> + riscv_init_flash_map(s->flash[1], flashbase + flashsize,
> flashsize,
> + sysmem, VIRT_FLASH_SECTOR_SIZE);
> }
>
> static void create_fdt_socket_plic(RISCVVirtState *s,
> diff --git a/include/hw/riscv/device-common.h
> b/include/hw/riscv/device-common.h
> index 12af031bbf..9f8bc67a1d 100644
> --- a/include/hw/riscv/device-common.h
> +++ b/include/hw/riscv/device-common.h
> @@ -10,10 +10,16 @@
> #define RISCV_DEVICE_COMMON_H
>
> #include "exec/hwaddr.h"
> +#include "hw/block/flash.h"
> #include "hw/core/qdev.h"
>
> DeviceState *riscv_create_platform_bus(DeviceState *irqchip,
> const MemMapEntry
> *platform_bus_mem,
> int platform_bus_base_irq,
> int platform_bus_num_irqs);
> +PFlashCFI01 *riscv_flash_create(Object *parent, const char *name,
> + const char *alias_prop_name,
> + int flash_sector_size);
> +void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr
> size,
> + MemoryRegion *sysmem, int
> flash_sector_size);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
2026-08-28 20:39 ` [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
2026-08-29 3:13 ` Chao Liu via qemu development
@ 2026-09-01 5:28 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:28 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> The GPEX_HOST initialization in 'virt' can be moved to device-
> common.c
> and be re-used later for other boards, namely the future
> 'riscv-server-ref' emulation.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/device-common.c | 76
> +++++++++++++++++++++++++++++++
> hw/riscv/virt.c | 77 ++----------------------------
> --
> include/hw/riscv/device-common.h | 7 +++
> 3 files changed, 87 insertions(+), 73 deletions(-)
>
> diff --git a/hw/riscv/device-common.c b/hw/riscv/device-common.c
> index a054cd7114..d1a6814f87 100644
> --- a/hw/riscv/device-common.c
> +++ b/hw/riscv/device-common.c
> @@ -15,6 +15,8 @@
> #include "hw/core/qdev.h"
> #include "hw/core/qdev-properties.h"
> #include "hw/core/sysbus.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci-host/gpex.h"
> #include "qapi/error.h"
> #include "qom/object.h"
> #include "system/address-spaces.h"
> @@ -90,3 +92,77 @@ void riscv_init_flash_map(PFlashCFI01 *flash,
> hwaddr base, hwaddr size,
> memory_region_add_subregion(sysmem, base,
>
> sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
> }
> +
> +DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
> + DeviceState *irqchip,
> + const MemMapEntry *pcie_ecam_mem,
> + const MemMapEntry *pcie_mmio_mem,
> + const MemMapEntry
> *high_pcie_mmio_mem,
> + const MemMapEntry *pcie_pio_mem,
> + int pcie_irq)
> +{
> + DeviceState *dev;
> + MemoryRegion *ecam_alias, *ecam_reg;
> + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
> + hwaddr ecam_base = pcie_ecam_mem->base;
> + hwaddr ecam_size = pcie_ecam_mem->size;
> + hwaddr mmio_base = pcie_mmio_mem->base;
> + hwaddr mmio_size = pcie_mmio_mem->size;
> + hwaddr high_mmio_base = high_pcie_mmio_mem->base;
> + hwaddr high_mmio_size = high_pcie_mmio_mem->size;
> + hwaddr pio_base = pcie_pio_mem->base;
> + hwaddr pio_size = pcie_pio_mem->size;
> +
> + dev = qdev_new(TYPE_GPEX_HOST);
> +
> + /* Set GPEX object properties for the virt machine */
> + object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
> + ecam_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
> + ecam_size, NULL);
> + object_property_set_uint(OBJECT(dev),
> PCI_HOST_BELOW_4G_MMIO_BASE,
> + mmio_base, NULL);
> + object_property_set_int(OBJECT(dev),
> PCI_HOST_BELOW_4G_MMIO_SIZE,
> + mmio_size, NULL);
> + object_property_set_uint(OBJECT(dev),
> PCI_HOST_ABOVE_4G_MMIO_BASE,
> + high_mmio_base, NULL);
> + object_property_set_int(OBJECT(dev),
> PCI_HOST_ABOVE_4G_MMIO_SIZE,
> + high_mmio_size, NULL);
> + object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
> + pio_base, NULL);
> + object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
> + pio_size, NULL);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> + ecam_alias = g_new0(MemoryRegion, 1);
> + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> + ecam_reg, 0, ecam_size);
> + memory_region_add_subregion(get_system_memory(), ecam_base,
> ecam_alias);
> +
> + mmio_alias = g_new0(MemoryRegion, 1);
> + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> + mmio_reg, mmio_base, mmio_size);
> + memory_region_add_subregion(get_system_memory(), mmio_base,
> mmio_alias);
> +
> + /* Map high MMIO space */
> + high_mmio_alias = g_new0(MemoryRegion, 1);
> + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-
> mmio-high",
> + mmio_reg, high_mmio_base,
> high_mmio_size);
> + memory_region_add_subregion(get_system_memory(), high_mmio_base,
> + high_mmio_alias);
> +
> + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
> +
> + for (int i = 0; i < PCI_NUM_PINS; i++) {
> + qemu_irq irq = qdev_get_gpio_in(irqchip, pcie_irq + i);
> +
> + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> + gpex_set_irq_num(GPEX_HOST(dev), i, pcie_irq + i);
> + }
> +
> + GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
> + return dev;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 9ff5beae77..d75dec2dd2 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -540,78 +540,6 @@ static void create_fdt(RISCVVirtState *s)
> create_fdt_pmu(s);
> }
>
> -static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
> - DeviceState *irqchip,
> - RISCVVirtState *s)
> -{
> - DeviceState *dev;
> - MemoryRegion *ecam_alias, *ecam_reg;
> - MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg;
> - hwaddr ecam_base = s->memmap[VIRT_PCIE_ECAM].base;
> - hwaddr ecam_size = s->memmap[VIRT_PCIE_ECAM].size;
> - hwaddr mmio_base = s->memmap[VIRT_PCIE_MMIO].base;
> - hwaddr mmio_size = s->memmap[VIRT_PCIE_MMIO].size;
> - hwaddr high_mmio_base = virt_high_pcie_memmap.base;
> - hwaddr high_mmio_size = virt_high_pcie_memmap.size;
> - hwaddr pio_base = s->memmap[VIRT_PCIE_PIO].base;
> - hwaddr pio_size = s->memmap[VIRT_PCIE_PIO].size;
> - qemu_irq irq;
> - int i;
> -
> - dev = qdev_new(TYPE_GPEX_HOST);
> -
> - /* Set GPEX object properties for the virt machine */
> - object_property_set_uint(OBJECT(dev), PCI_HOST_ECAM_BASE,
> - ecam_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_ECAM_SIZE,
> - ecam_size, NULL);
> - object_property_set_uint(OBJECT(dev),
> PCI_HOST_BELOW_4G_MMIO_BASE,
> - mmio_base, NULL);
> - object_property_set_int(OBJECT(dev),
> PCI_HOST_BELOW_4G_MMIO_SIZE,
> - mmio_size, NULL);
> - object_property_set_uint(OBJECT(dev),
> PCI_HOST_ABOVE_4G_MMIO_BASE,
> - high_mmio_base, NULL);
> - object_property_set_int(OBJECT(dev),
> PCI_HOST_ABOVE_4G_MMIO_SIZE,
> - high_mmio_size, NULL);
> - object_property_set_uint(OBJECT(dev), PCI_HOST_PIO_BASE,
> - pio_base, NULL);
> - object_property_set_int(OBJECT(dev), PCI_HOST_PIO_SIZE,
> - pio_size, NULL);
> -
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -
> - ecam_alias = g_new0(MemoryRegion, 1);
> - ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> - memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> - ecam_reg, 0, ecam_size);
> - memory_region_add_subregion(get_system_memory(), ecam_base,
> ecam_alias);
> -
> - mmio_alias = g_new0(MemoryRegion, 1);
> - mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> - memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> - mmio_reg, mmio_base, mmio_size);
> - memory_region_add_subregion(get_system_memory(), mmio_base,
> mmio_alias);
> -
> - /* Map high MMIO space */
> - high_mmio_alias = g_new0(MemoryRegion, 1);
> - memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-
> mmio-high",
> - mmio_reg, high_mmio_base,
> high_mmio_size);
> - memory_region_add_subregion(get_system_memory(), high_mmio_base,
> - high_mmio_alias);
> -
> - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
> -
> - for (i = 0; i < PCI_NUM_PINS; i++) {
> - irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
> -
> - sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> - gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
> - }
> -
> - GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(dev)->bus;
> - return dev;
> -}
> -
> static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr
> base)
> {
> FWCfgState *fw_cfg;
> @@ -963,7 +891,10 @@ static void virt_machine_init(MachineState
> *machine)
> qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i));
> }
>
> - gpex_pcie_init(system_memory, pcie_irqchip, s);
> + riscv_gpex_pcie_init(system_memory, pcie_irqchip,
> + &s->memmap[VIRT_PCIE_ECAM], &s-
> >memmap[VIRT_PCIE_MMIO],
> + &virt_high_pcie_memmap, &s-
> >memmap[VIRT_PCIE_PIO],
> + PCIE_IRQ);
>
> s->platform_bus_dev = riscv_create_platform_bus(mmio_irqchip,
> &s->memmap[VIRT_PLATFORM_BUS], VIRT_PLATFORM_BUS_IRQ,
> diff --git a/include/hw/riscv/device-common.h
> b/include/hw/riscv/device-common.h
> index 9f8bc67a1d..572912ec36 100644
> --- a/include/hw/riscv/device-common.h
> +++ b/include/hw/riscv/device-common.h
> @@ -22,4 +22,11 @@ PFlashCFI01 *riscv_flash_create(Object *parent,
> const char *name,
> int flash_sector_size);
> void riscv_init_flash_map(PFlashCFI01 *flash, hwaddr base, hwaddr
> size,
> MemoryRegion *sysmem, int
> flash_sector_size);
> +DeviceState *riscv_gpex_pcie_init(MemoryRegion *sys_mem,
> + DeviceState *irqchip,
> + const MemMapEntry *pcie_ecam_mem,
> + const MemMapEntry *pcie_mmio_mem,
> + const MemMapEntry
> *high_pcie_mmio_mem,
> + const MemMapEntry *pcie_pio_mem,
> + int pcie_irq);
> #endif
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
2026-08-28 20:39 ` [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
2026-08-29 3:13 ` Chao Liu via
@ 2026-09-01 5:28 ` Alistair Francis
1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:28 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: philmd@oss.qualcomm.com, qemu-riscv@nongnu.org,
palmer@dabbelt.com, chao.liu@processmission.com,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Move the creation of riscv-iommu-sys to its own file instead of open
> coding it in the 'virt' board. Other boards in the future might want
> to
> use this device and we want to avoid code duplication.
>
> Signed-off-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/riscv-iommu-sys.c | 25 +++++++++++++++++++++++++
> hw/riscv/riscv-iommu.h | 3 +++
> hw/riscv/virt.c | 23 +++--------------------
> 3 files changed, 31 insertions(+), 20 deletions(-)
>
> diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c
> index 3314adeed2..258c171efd 100644
> --- a/hw/riscv/riscv-iommu-sys.c
> +++ b/hw/riscv/riscv-iommu-sys.c
> @@ -217,6 +217,31 @@ static void riscv_iommu_sys_init(Object *obj)
> riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_BOTH);
> }
>
> +DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
> + hwaddr addr, int base_irq,
> + bool is_32_bit)
> +{
> + DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
> +
> + object_property_set_uint(OBJECT(iommu_sys), "addr", addr,
> &error_fatal);
> + object_property_set_uint(OBJECT(iommu_sys), "base-irq",
> + base_irq, &error_fatal);
> + object_property_set_link(OBJECT(iommu_sys), "irqchip",
> + OBJECT(mmio_irqchip),
> + &error_fatal);
> + /*
> + * For riscv64 use a physical address size of 56 bits (44 bit
> PPN),
> + * and for riscv32 use 34 bits (22 bit PPN).
> + */
> + object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
> + is_32_bit ? 34 : 56,
> + &error_fatal);
> +
> + sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys),
> &error_fatal);
> +
> + return iommu_sys;
> +}
> +
> static const Property riscv_iommu_sys_properties[] = {
> DEFINE_PROP_UINT64("addr", RISCVIOMMUStateSys, addr, 0),
> DEFINE_PROP_UINT32("base-irq", RISCVIOMMUStateSys, base_irq, 0),
> diff --git a/hw/riscv/riscv-iommu.h b/hw/riscv/riscv-iommu.h
> index da70e8bfa8..7c470ba084 100644
> --- a/hw/riscv/riscv-iommu.h
> +++ b/hw/riscv/riscv-iommu.h
> @@ -104,6 +104,9 @@ void riscv_iommu_set_cap_igs(RISCVIOMMUState *s,
> riscv_iommu_igs_mode mode);
> void riscv_iommu_reset(RISCVIOMMUState *s);
> void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type);
> void riscv_iommu_fault(RISCVIOMMUState *s, struct
> riscv_iommu_fq_record *ev);
> +DeviceState *riscv_create_iommu_sys(DeviceState *mmio_irqchip,
> + hwaddr addr, int base_irq,
> + bool is_32_bit);
>
> typedef struct RISCVIOMMUContext RISCVIOMMUContext;
> /* Device translation context state. */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index d75dec2dd2..de7b99c6a5 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -32,6 +32,7 @@
> #include "hw/core/sysbus-fdt.h"
> #include "hw/riscv/riscv_hart.h"
> #include "hw/riscv/iommu.h"
> +#include "hw/riscv/riscv-iommu.h"
> #include "hw/riscv/riscv-iommu-bits.h"
> #include "hw/riscv/virt.h"
> #include "hw/riscv/boot.h"
> @@ -933,26 +934,8 @@ static void virt_machine_init(MachineState
> *machine)
> }
>
> if (virt_is_iommu_sys_enabled(s)) {
> - DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS);
> -
> - object_property_set_uint(OBJECT(iommu_sys), "addr",
> - s->memmap[VIRT_IOMMU_SYS].base,
> - &error_fatal);
> - object_property_set_uint(OBJECT(iommu_sys), "base-irq",
> - IOMMU_SYS_IRQ,
> - &error_fatal);
> - object_property_set_link(OBJECT(iommu_sys), "irqchip",
> - OBJECT(mmio_irqchip),
> - &error_fatal);
> - /*
> - * For riscv64 use a physical address size of 56 bits (44
> bit PPN),
> - * and for riscv32 use 34 bits (22 bit PPN).
> - */
> - object_property_set_uint(OBJECT(iommu_sys), "pas-bits",
> - riscv_is_32bit(&s->soc[0]) ? 34 :
> 56,
> - &error_fatal);
> -
> - sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys),
> &error_fatal);
> + riscv_create_iommu_sys(mmio_irqchip, s-
> >memmap[VIRT_IOMMU_SYS].base,
> + IOMMU_SYS_IRQ, riscv_is_32bit(&s-
> >soc[0]));
> }
>
> s->machine_done.notify = virt_machine_done;
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep)
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
` (14 preceding siblings ...)
2026-08-28 20:39 ` [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
@ 2026-09-01 5:32 ` Alistair Francis
15 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2026-09-01 5:32 UTC (permalink / raw)
To: daniel.barboza@oss.qualcomm.com, qemu-devel@nongnu.org
Cc: qemu-trivial@nongnu.org, qemu-riscv@nongnu.org, mjt@tls.msk.ru,
chao.liu@processmission.com, laurent@vivier.eu,
liwei1518@gmail.com, zhiwei_liu@linux.alibaba.com
On Fri, 2026-08-28 at 17:39 -0300, Daniel Henrique Barboza wrote:
> Hi,
>
> In this new version a new patch was added. It is a fix for the
> aclint
> FDT, suggested by Chao in the v4 review. We're fixing the FDT before
> moving the aclint FDT to the helper in the patch that follows.
>
> No other changes made. Patches based on alistair/riscv-to-
> apply.next.
>
> Changes from v4:
> - patch 8 (new): fix aclint soc/mtimer node
> - patch 9:
> - move the aclint FDT to the helper without any changes, as stated
> in
> the commit msg.
> - v4 link:
> https://lore.kernel.org/qemu-devel/20260827222608.329788-1-daniel.barboza@oss.qualcomm.com/
>
>
> Daniel Henrique Barboza (15):
> hw/riscv/fdt-common: prepend helpers with "riscv_"
> hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
> hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
> hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
> hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
> hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
> hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
> hw/riscv/virt.c: fix aclint soc/mtimer nodename
> hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
> hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
> hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
> hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
> hw/riscv/device-common, virt.c: add flash helpers
> hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
> hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
Thanks!
Applied to riscv-to-apply.next
Alistair
>
> hw/riscv/device-common.c | 168 ++++++
> hw/riscv/fdt-common.c | 613 +++++++++++++++++++++-
> hw/riscv/meson.build | 1 +
> hw/riscv/riscv-iommu-sys.c | 25 +
> hw/riscv/riscv-iommu.h | 3 +
> hw/riscv/sifive_u.c | 34 +-
> hw/riscv/spike.c | 30 +-
> hw/riscv/tt_atlantis.c | 22 +-
> hw/riscv/virt.c | 861 +++++------------------------
> --
> include/hw/riscv/device-common.h | 32 ++
> include/hw/riscv/fdt-common.h | 146 +++++-
> include/hw/riscv/virt.h | 15 -
> 12 files changed, 1112 insertions(+), 838 deletions(-)
> create mode 100644 hw/riscv/device-common.c
> create mode 100644 include/hw/riscv/device-common.h
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_"
2026-08-28 20:39 ` [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
2026-09-01 4:42 ` Alistair Francis
@ 2026-09-02 16:24 ` Philippe Mathieu-Daudé
2026-09-02 16:38 ` Daniel Henrique Barboza
1 sibling, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 16:24 UTC (permalink / raw)
To: Daniel Henrique Barboza, qemu-devel, Yonggang Luo
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Palmer Dabbelt, Joel Stanley, Nicholas Piggin, Anirudh Srinivasan,
Michael Ellerman, Portia Stephens
Hi Daniel,
On 28/8/26 22:39, Daniel Henrique Barboza wrote:
> Given that the helpers are public API we should prefix them with
> "riscv_" to avoid conflicts when linking with different targets in the
> future, i.e. we should not use generic names like
> "create_fdt_socket_memory".
>
> Despite the amount of lines this is a mechanical change and no real
> FDT changes are intended.
>
> Suggested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
> Reviewed-by: Chao Liu <chao.liu@processmission.com>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> hw/riscv/fdt-common.c | 45 ++++++++++++++++----------------
> hw/riscv/sifive_u.c | 34 +++++++++++++------------
> hw/riscv/spike.c | 30 ++++++++++++----------
> hw/riscv/tt_atlantis.c | 22 ++++++++--------
> hw/riscv/virt.c | 42 +++++++++++++++---------------
> include/hw/riscv/fdt-common.h | 48 ++++++++++++++++++-----------------
> 6 files changed, 117 insertions(+), 104 deletions(-)
I had the following patch tagged but it will conflict with your
series which is apparently ready (and at v5):
https://lore.kernel.org/qemu-devel/20260823150731.896-6-luoyonggang@gmail.com/
I'll let see with Yonggang what is the simpler (likely have
his patch rebased once your series is merged).
Regards,
Phil.
^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_"
2026-09-02 16:24 ` Philippe Mathieu-Daudé
@ 2026-09-02 16:38 ` Daniel Henrique Barboza
0 siblings, 0 replies; 55+ messages in thread
From: Daniel Henrique Barboza @ 2026-09-02 16:38 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel, Yonggang Luo
Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
Palmer Dabbelt, Joel Stanley, Nicholas Piggin, Anirudh Srinivasan,
Michael Ellerman, Portia Stephens
On 9/2/2026 1:24 PM, Philippe Mathieu-Daudé wrote:
> Hi Daniel,
>
> On 28/8/26 22:39, Daniel Henrique Barboza wrote:
>> Given that the helpers are public API we should prefix them with
>> "riscv_" to avoid conflicts when linking with different targets in the
>> future, i.e. we should not use generic names like
>> "create_fdt_socket_memory".
>>
>> Despite the amount of lines this is a mechanical change and no real
>> FDT changes are intended.
>>
>> Suggested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
>> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
>> Reviewed-by: Chao Liu <chao.liu@processmission.com>
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
>> ---
>> hw/riscv/fdt-common.c | 45 ++++++++++++++++----------------
>> hw/riscv/sifive_u.c | 34 +++++++++++++------------
>> hw/riscv/spike.c | 30 ++++++++++++----------
>> hw/riscv/tt_atlantis.c | 22 ++++++++--------
>> hw/riscv/virt.c | 42 +++++++++++++++---------------
>> include/hw/riscv/fdt-common.h | 48 ++++++++++++++++++-----------------
>> 6 files changed, 117 insertions(+), 104 deletions(-)
>
> I had the following patch tagged but it will conflict with your
> series which is apparently ready (and at v5):
> https://lore.kernel.org/qemu-devel/20260823150731.896-6-luoyonggang@gmail.com/
> I'll let see with Yonggang what is the simpler (likely have
> his patch rebased once your series is merged).
Yeah, I appreciate if you can wait for this series to be merged and then rebase
things on top of it, in particular because the patches are already queued
Another alternative is to rebase the prefix ACPI helpers patch on top of
alistair/riscv-to-apply.next, given that it should already contain these patches.
Then we could queue that patch alone via a qemu-riscv PR. It would alleviate
the size of that single-binary series a bit.
Cheers,
Daniel
>
> Regards,
>
> Phil.
^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2026-09-02 16:39 UTC | newest]
Thread overview: 55+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28 20:39 [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
2026-08-28 20:39 ` [PATCH v5 01/15] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
2026-09-01 4:42 ` Alistair Francis
2026-09-02 16:24 ` Philippe Mathieu-Daudé
2026-09-02 16:38 ` Daniel Henrique Barboza
2026-08-28 20:39 ` [PATCH v5 02/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
2026-09-01 4:45 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 03/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
2026-09-01 4:45 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 04/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
2026-09-01 4:47 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 05/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
2026-08-29 3:08 ` Chao Liu via
2026-08-29 3:08 ` Chao Liu via qemu development
2026-09-01 4:49 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 06/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
2026-08-29 3:08 ` Chao Liu via
2026-08-29 3:08 ` Chao Liu via qemu development
2026-09-01 4:51 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 07/15] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
2026-08-29 3:09 ` Chao Liu via
2026-08-29 3:09 ` Chao Liu via qemu development
2026-09-01 5:14 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 08/15] hw/riscv/virt.c: fix aclint soc/mtimer nodename Daniel Henrique Barboza
2026-08-29 3:10 ` Chao Liu
2026-09-01 5:15 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 09/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
2026-08-29 3:10 ` Chao Liu via
2026-08-29 3:10 ` Chao Liu via qemu development
2026-09-01 5:17 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 10/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
2026-08-29 3:11 ` Chao Liu via qemu development
2026-08-29 3:11 ` Chao Liu via
2026-09-01 5:23 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 11/15] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via qemu development
2026-08-29 3:12 ` Chao Liu via
2026-09-01 5:23 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 12/15] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via
2026-08-29 3:12 ` Chao Liu via qemu development
2026-09-01 5:24 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 13/15] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
2026-08-29 3:12 ` Chao Liu via qemu development
2026-08-29 3:12 ` Chao Liu via
2026-09-01 5:28 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 14/15] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
2026-08-29 3:13 ` Chao Liu via
2026-08-29 3:13 ` Chao Liu via qemu development
2026-09-01 5:28 ` Alistair Francis
2026-08-28 20:39 ` [PATCH v5 15/15] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
2026-08-29 3:13 ` Chao Liu via qemu development
2026-08-29 3:13 ` Chao Liu via
2026-09-01 5:28 ` Alistair Francis
2026-09-01 5:32 ` [PATCH v5 00/15] hw/riscv: trivial code dup work (riscv-server-ref prep) Alistair Francis
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.