All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep)
@ 2026-08-27 22:25 Daniel Henrique Barboza
  2026-08-27 22:25 ` [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
                   ` (13 more replies)
  0 siblings, 14 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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

Hello,

In this version the most notable change is in patch 9, where we left the
tt-atlantis out of the changes being done.  The reason is that the board
will have UART related changes soon, and the UART FDT will be most
likely impacted, thus it's better to wait for the DT to stabilize first.

Other change done is the "local phandle" handling.  For all helpers that
receives a 'next_phandle' pointer we'll check if the pointer is valid
and use its val as next phandle.  Otherwise we'll use
qemu_fdt_alloc_phandle().

Other minor changes were also done following the discussions in v3.

Patches based on alistair/riscv-to-apply.next.

Changes from v3:
- patch 3:
  - renamed 'phandle' to 'next_phandle'.  If non-null the helper will
    use (*next_phandle) as the phandle value for the new subnode.
    Otherwise the helper will retrieve a phandle via qemu_fdt_alloc_phandle().
- patch 4:
  - added a new 'next_phandle' optional pointer.  If non-null the helper
    will use (*next_phandle) as the phandle value for the new subnode.
    Otherwise the helper will retrieve a phandle via qemu_fdt_alloc_phandle();
  - removed the iommu_irq_map array;
  - instead of returning 'void' return the DT iommu phandle.
- patch 6:
  - renamed 'phandle' to 'next_phandle'.  If non-null the helper will
    use (*next_phandle) as the phandle value for the new subnode.
    Otherwise the helper will retrieve a phandle via qemu_fdt_alloc_phandle().
- patch 7:
  - renamed 'phandle' to 'next_phandle'.  If non-null the helper will
    use (*next_phandle) as the phandle value for the new subnode.
    Otherwise the helper will retrieve a phandle via qemu_fdt_alloc_phandle().
- patch 9:
  - removed all tt-atlantis.c changes;
  - renamed irq_mmio_phandle to irq_phandle;
  - removed both bool flags;
  - "/chosen" and "/alias" are now set manually by the board;
  - a new riscv_fdt_get_uart_nodename() helper were added;
  - added an UART_STD_CLOCK_FREQ to hide the magic 3.6864 MHz hardcoded
    clock value.
- patch 10:
  - renamed irq_mmio_phandle to irq_phandle.
- v3 link: https://lore.kernel.org/qemu-devel/20260826214643.122728-1-daniel.barboza@oss.qualcomm.com/

Daniel Henrique Barboza (14):
  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/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            | 612 +++++++++++++++++++++-
 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, 1111 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] 30+ messages in thread

* [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_"
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
@ 2026-08-27 22:25 ` Daniel Henrique Barboza
  2026-08-28  2:54     ` Chao Liu via qemu development
  2026-08-28  7:16   ` Philippe Mathieu-Daudé
  2026-08-27 22:25 ` [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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>
---
 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] 30+ messages in thread

* [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
  2026-08-27 22:25 ` [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
@ 2026-08-27 22:25 ` Daniel Henrique Barboza
  2026-08-28  2:55     ` Chao Liu via
  2026-08-27 22:25 ` [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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>
---
 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] 30+ messages in thread

* [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
  2026-08-27 22:25 ` [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
  2026-08-27 22:25 ` [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
@ 2026-08-27 22:25 ` Daniel Henrique Barboza
  2026-08-28  2:56     ` Chao Liu via
  2026-08-27 22:25 ` [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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>
---
 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] 30+ messages in thread

* [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (2 preceding siblings ...)
  2026-08-27 22:25 ` [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
@ 2026-08-27 22:25 ` Daniel Henrique Barboza
  2026-08-28  2:57     ` Chao Liu via
  2026-08-27 22:25 ` [PATCH v4 05/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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>
---
 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] 30+ messages in thread

* [PATCH v4 05/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (3 preceding siblings ...)
  2026-08-27 22:25 ` [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
@ 2026-08-27 22:25 ` Daniel Henrique Barboza
  2026-08-27 22:25 ` [PATCH v4 06/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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] 30+ messages in thread

* [PATCH v4 06/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (4 preceding siblings ...)
  2026-08-27 22:25 ` [PATCH v4 05/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
@ 2026-08-27 22:25 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 07/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:25 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] 30+ messages in thread

* [PATCH v4 07/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (5 preceding siblings ...)
  2026-08-27 22:25 ` [PATCH v4 06/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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] 30+ messages in thread

* [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (6 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 07/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-28  4:13     ` Chao Liu via qemu development
  2026-08-27 22:26 ` [PATCH v4 09/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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         |  96 ++++++++++++++++++++++++++++++++
 hw/riscv/virt.c               | 101 ++++------------------------------
 include/hw/riscv/fdt-common.h |  11 ++++
 3 files changed, 119 insertions(+), 89 deletions(-)

diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
index d815c5adff..76a783709d 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,98 @@ 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);
+    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,
+        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 a6ec9def16..717a01da8d 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -180,93 +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@%lx", addr);
-    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,
@@ -347,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]) :
@@ -354,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 +
@@ -372,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] 30+ messages in thread

* [PATCH v4 09/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (7 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 10/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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 76a783709d..e8186230b7 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)
 {
@@ -798,3 +800,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] 30+ messages in thread

* [PATCH v4 10/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (8 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 09/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 11/14] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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 e8186230b7..05042ce312 100644
--- a/hw/riscv/fdt-common.c
+++ b/hw/riscv/fdt-common.c
@@ -827,3 +827,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] 30+ messages in thread

* [PATCH v4 11/14] hw/riscv/device-common, virt.c: add riscv_create_platform_bus()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (9 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 10/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 12/14] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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] 30+ messages in thread

* [PATCH v4 12/14] hw/riscv/device-common, virt.c: add flash helpers
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (10 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 11/14] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 13/14] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 14/14] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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] 30+ messages in thread

* [PATCH v4 13/14] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (11 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 12/14] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  2026-08-27 22:26 ` [PATCH v4 14/14] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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] 30+ messages in thread

* [PATCH v4 14/14] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys()
  2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
                   ` (12 preceding siblings ...)
  2026-08-27 22:26 ` [PATCH v4 13/14] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
@ 2026-08-27 22:26 ` Daniel Henrique Barboza
  13 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-27 22:26 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] 30+ messages in thread

* Re: [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_"
  2026-08-27 22:25 ` [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
@ 2026-08-28  2:54     ` Chao Liu via qemu development
  2026-08-28  7:16   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 30+ messages in thread
From: Chao Liu via @ 2026-08-28  2:54 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt, Joel Stanley,
	Nicholas Piggin, Anirudh Srinivasan, Michael Ellerman,
	Portia Stephens

On Thu, Aug 27, 2026 at 07:25:54PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_"
@ 2026-08-28  2:54     ` Chao Liu via qemu development
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via qemu development @ 2026-08-28  2:54 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt, Joel Stanley,
	Nicholas Piggin, Anirudh Srinivasan, Michael Ellerman,
	Portia Stephens

On Thu, Aug 27, 2026 at 07:25:54PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
  2026-08-27 22:25 ` [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
@ 2026-08-28  2:55     ` Chao Liu via
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via qemu development @ 2026-08-28  2:55 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:25:55PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash()
@ 2026-08-28  2:55     ` Chao Liu via
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via @ 2026-08-28  2:55 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:25:55PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
  2026-08-27 22:25 ` [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
@ 2026-08-28  2:56     ` Chao Liu via
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via qemu development @ 2026-08-28  2:56 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:25:56PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon()
@ 2026-08-28  2:56     ` Chao Liu via
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via @ 2026-08-28  2:56 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:25:56PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
  2026-08-27 22:25 ` [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
@ 2026-08-28  2:57     ` Chao Liu via
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via qemu development @ 2026-08-28  2:57 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:25:57PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys()
@ 2026-08-28  2:57     ` Chao Liu via
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via @ 2026-08-28  2:57 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:25:57PM +0800, 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>

Thanks,
Chao

> ---
>  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	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
  2026-08-27 22:26 ` [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
@ 2026-08-28  4:13     ` Chao Liu via qemu development
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via @ 2026-08-28  4:13 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:26:01PM +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>
> ---
>  hw/riscv/fdt-common.c         |  96 ++++++++++++++++++++++++++++++++
>  hw/riscv/virt.c               | 101 ++++------------------------------
>  include/hw/riscv/fdt-common.h |  11 ++++
>  3 files changed, 119 insertions(+), 89 deletions(-)
> 
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d815c5adff..76a783709d 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,98 @@ 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);
> +    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,
Should be:
	   2, addr + RISCV_ACLINT_DEFAULT_MTIME,

I found an MTIMER FDT issue in the virt machine FDT.

Command:

```
  timeout 30s ./build/qemu-system-riscv64 \
    -machine virt,aia=aplic-imsic,aia-guests=5,aclint=on,dumpdtb=/tmp/virt.dtb \
    -smp 2 -display none -nodefaults

  dtc -I dtb -O dts /tmp/virt.dtb | grep -A4 mtimer@
```

The generated FDT contains:

                mtimer@2000000 {
                        interrupts-extended = <0x04 0x07 0x02 0x07>;
                        reg = <0x00 0x2000000 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
                        compatible = "riscv,aclint-mtimer";
                };

without this patches:

                  mtimer@2000000 {
                          interrupts-extended = <0x04 0x07 0x02 0x07>;
                          reg = <0x00 0x2007ff8 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
                          compatible = "riscv,aclint-mtimer";
                  };

The first address should be 0x20007ff8.

> +        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> +        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> +        2, RISCV_ACLINT_DEFAULT_MTIME);

[...]

> +    qemu_fdt_setprop(fdt, name, "interrupts-extended",
> -    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> -        2, addr + RISCV_ACLINT_DEFAULT_MTIME,
I think this is the original code that was moved here.

Thanks,
Chao
> -        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> -        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> -        2, RISCV_ACLINT_DEFAULT_MTIME);



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
@ 2026-08-28  4:13     ` Chao Liu via qemu development
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via qemu development @ 2026-08-28  4:13 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

On Thu, Aug 27, 2026 at 07:26:01PM +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>
> ---
>  hw/riscv/fdt-common.c         |  96 ++++++++++++++++++++++++++++++++
>  hw/riscv/virt.c               | 101 ++++------------------------------
>  include/hw/riscv/fdt-common.h |  11 ++++
>  3 files changed, 119 insertions(+), 89 deletions(-)
> 
> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> index d815c5adff..76a783709d 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,98 @@ 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);
> +    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,
Should be:
	   2, addr + RISCV_ACLINT_DEFAULT_MTIME,

I found an MTIMER FDT issue in the virt machine FDT.

Command:

```
  timeout 30s ./build/qemu-system-riscv64 \
    -machine virt,aia=aplic-imsic,aia-guests=5,aclint=on,dumpdtb=/tmp/virt.dtb \
    -smp 2 -display none -nodefaults

  dtc -I dtb -O dts /tmp/virt.dtb | grep -A4 mtimer@
```

The generated FDT contains:

                mtimer@2000000 {
                        interrupts-extended = <0x04 0x07 0x02 0x07>;
                        reg = <0x00 0x2000000 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
                        compatible = "riscv,aclint-mtimer";
                };

without this patches:

                  mtimer@2000000 {
                          interrupts-extended = <0x04 0x07 0x02 0x07>;
                          reg = <0x00 0x2007ff8 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
                          compatible = "riscv,aclint-mtimer";
                  };

The first address should be 0x20007ff8.

> +        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> +        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> +        2, RISCV_ACLINT_DEFAULT_MTIME);

[...]

> +    qemu_fdt_setprop(fdt, name, "interrupts-extended",
> -    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> -        2, addr + RISCV_ACLINT_DEFAULT_MTIME,
I think this is the original code that was moved here.

Thanks,
Chao
> -        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> -        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> -        2, RISCV_ACLINT_DEFAULT_MTIME);



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_"
  2026-08-27 22:25 ` [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
  2026-08-28  2:54     ` Chao Liu via qemu development
@ 2026-08-28  7:16   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 30+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-28  7:16 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: qemu-riscv, alistair.francis, liwei1518, zhiwei_liu, chao.liu,
	Palmer Dabbelt, Joel Stanley, Nicholas Piggin, Anirudh Srinivasan,
	Michael Ellerman, Portia Stephens

On 28/8/26 00:25, 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>
> ---
>   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(-)

Thank you!

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
  2026-08-28  4:13     ` Chao Liu via qemu development
  (?)
@ 2026-08-28 15:40     ` Daniel Henrique Barboza
  2026-08-28 19:01         ` Chao Liu via qemu development
  -1 siblings, 1 reply; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 15:40 UTC (permalink / raw)
  To: Chao Liu
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt



On 8/28/2026 1:13 AM, Chao Liu wrote:
> On Thu, Aug 27, 2026 at 07:26:01PM +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>
>> ---
>>   hw/riscv/fdt-common.c         |  96 ++++++++++++++++++++++++++++++++
>>   hw/riscv/virt.c               | 101 ++++------------------------------
>>   include/hw/riscv/fdt-common.h |  11 ++++
>>   3 files changed, 119 insertions(+), 89 deletions(-)
>>
>> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
>> index d815c5adff..76a783709d 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,98 @@ 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);
>> +    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,
> Should be:
> 	   2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> 
> I found an MTIMER FDT issue in the virt machine FDT.
> 
> Command:
> 
> ```
>    timeout 30s ./build/qemu-system-riscv64 \
>      -machine virt,aia=aplic-imsic,aia-guests=5,aclint=on,dumpdtb=/tmp/virt.dtb \
>      -smp 2 -display none -nodefaults
> 
>    dtc -I dtb -O dts /tmp/virt.dtb | grep -A4 mtimer@
> ```
> 
> The generated FDT contains:
> 
>                  mtimer@2000000 {
>                          interrupts-extended = <0x04 0x07 0x02 0x07>;
>                          reg = <0x00 0x2000000 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
>                          compatible = "riscv,aclint-mtimer";
>                  };
> 
> without this patches:
> 
>                    mtimer@2000000 {
>                            interrupts-extended = <0x04 0x07 0x02 0x07>;
>                            reg = <0x00 0x2007ff8 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
>                            compatible = "riscv,aclint-mtimer";
>                    };
> 
> The first address should be 0x20007ff8.

That was intentional and I forgot to document it in the commit msg. The
"No FDT changes made" I said doesn't apply here. My bad!

If you use 'dtc' in the current 'virt' DT you'll get 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 unit address in the node name doesn't match the
first address in 'reg'.  For mtimer@2000000, "reg" must be reg = <0x00 0x2000000 (...)>.
For mtimer@2008000, reg = <0x00 2008000 (...)> and so on.


Now, does this change break aclint in 'virt'?  Because in that case we'll
just keep the "dtc" warning and live with it.  Aside from the existing tests
we have in QEMU I didn't do a deep dive in aclint.


Thanks,
Daniel

> 
>> +        2, size - RISCV_ACLINT_DEFAULT_MTIME,
>> +        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
>> +        2, RISCV_ACLINT_DEFAULT_MTIME);
> 
> [...]
> 
>> +    qemu_fdt_setprop(fdt, name, "interrupts-extended",
>> -    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
>> -        2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> I think this is the original code that was moved here.
> 
> Thanks,
> Chao
>> -        2, size - RISCV_ACLINT_DEFAULT_MTIME,
>> -        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
>> -        2, RISCV_ACLINT_DEFAULT_MTIME);
> 



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
  2026-08-28 15:40     ` Daniel Henrique Barboza
@ 2026-08-28 19:01         ` Chao Liu via qemu development
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via @ 2026-08-28 19:01 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

Hi Daniel,

On Fri, Aug 28, 2026 at 12:40:38PM +0800, Daniel Henrique Barboza wrote:
> 
> 
> On 8/28/2026 1:13 AM, Chao Liu wrote:
> > On Thu, Aug 27, 2026 at 07:26:01PM +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>
> > > ---
> > >   hw/riscv/fdt-common.c         |  96 ++++++++++++++++++++++++++++++++
> > >   hw/riscv/virt.c               | 101 ++++------------------------------
> > >   include/hw/riscv/fdt-common.h |  11 ++++
> > >   3 files changed, 119 insertions(+), 89 deletions(-)
> > > 
> > > diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> > > index d815c5adff..76a783709d 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,98 @@ 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);
> > > +    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,
> > Should be:
> > 	   2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> > 
> > I found an MTIMER FDT issue in the virt machine FDT.
> > 
> > Command:
> > 
> > ```
> >    timeout 30s ./build/qemu-system-riscv64 \
> >      -machine virt,aia=aplic-imsic,aia-guests=5,aclint=on,dumpdtb=/tmp/virt.dtb \
> >      -smp 2 -display none -nodefaults
> > 
> >    dtc -I dtb -O dts /tmp/virt.dtb | grep -A4 mtimer@
> > ```
> > 
> > The generated FDT contains:
> > 
> >                  mtimer@2000000 {
> >                          interrupts-extended = <0x04 0x07 0x02 0x07>;
> >                          reg = <0x00 0x2000000 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
> >                          compatible = "riscv,aclint-mtimer";
> >                  };
> > 
> > without this patches:
> > 
> >                    mtimer@2000000 {
> >                            interrupts-extended = <0x04 0x07 0x02 0x07>;
> >                            reg = <0x00 0x2007ff8 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
> >                            compatible = "riscv,aclint-mtimer";
> >                    };
> > 
> > The first address should be 0x20007ff8.
> 
> That was intentional and I forgot to document it in the commit msg. The
> "No FDT changes made" I said doesn't apply here. My bad!
Thanks for clarifying. I also noticed this waring during my previous
review and testing.

> 
> If you use 'dtc' in the current 'virt' DT you'll get 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"
Yes, the warning is valid, and I can reproduce it as well.

> 
> 
> This happens because the unit address in the node name doesn't match the
> first address in 'reg'.  For mtimer@2000000, "reg" must be reg = <0x00 0x2000000 (...)>.
> For mtimer@2008000, reg = <0x00 2008000 (...)> and so on.
I agree that the address in the node name should match the first address
in `reg`, as described by the Devicetree Spec [1].

However, I think the value that needs to change is the node name, not
the first address in `reg`.

See ACLINT spec, an MITER device has two separate base addr: one for MTIME
and another for the MTIMECMP registers [2].

In the current QEMU implement, `addr` is the MTIMECMP base address, while
the MTIME register is located at:

	addr + RISCV_ACLINT_DEFAULT_METIME

For this example:

	MTIMECMP base = 0x2000000
	MITIME   base = 0x2007ff8

So the existing `reg` property correctly describes the two register
regions:

	reg = <0x00 0x2007ff8 0x00 0x08
	       0x00 0x2000000 0x00 0x7ff8>

> 
> 
> Now, does this change break aclint in 'virt'?  Because in that case we'll
> just keep the "dtc" warning and live with it.  Aside from the existing tests
> we have in QEMU I didn't do a deep dive in aclint.
Yes, I think using `addr` here would make the ACLINT description
incorrect. `addr` is the MTIMECMP base address, while MTIME is located
at `addr + RISCV_ACLINT_DEFAULT_MTIME`.

Please keep the first `reg` address as it was:

      qemu_fdt_setprop_sized_cells(fdt, name, "reg",
-          2, addr,
+          2, addr + RISCV_ACLINT_DEFAULT_MTIME,
           2, size - RISCV_ACLINT_DEFAULT_MTIME,
           2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
           2, RISCV_ACLINT_DEFAULT_MTIME);

Since this patch is mainly a code-duplication cleanup, I suggest
leaving the generated FDT unchanged here. The unit-address fix can be
sent as a separate follow-up patch:

- name = g_strdup_printf("/soc/mtimer@%" HWADDR_PRIx, addr);
+ name = g_strdup_printf("/soc/mtimer@%" HWADDR_PRIx,
+                        addr + RISCV_ACLINT_DEFAULT_MTIME);

--

LINK:

[1] Devicetree Specification, Section 2.2.1, "Node Names":
    https://devicetree-specification.readthedocs.io/en/stable/devicetree-basics.html#node-names

[2] RISC-V ACLINT Specification, "Machine-level Timer Device (MTIMER)",
    Section "Register Map":
    https://github.com/riscvarchive/riscv-aclint/blob/main/riscv-aclint.adoc


Thanks,
Chao
> 
> 
> Thanks,
> Daniel
> 
> > 
> > > +        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> > > +        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> > > +        2, RISCV_ACLINT_DEFAULT_MTIME);
> > 
> > [...]
> > 
> > > +    qemu_fdt_setprop(fdt, name, "interrupts-extended",
> > > -    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> > > -        2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> > I think this is the original code that was moved here.
> > 
> > Thanks,
> > Chao
> > > -        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> > > -        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> > > -        2, RISCV_ACLINT_DEFAULT_MTIME);
> > 
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
@ 2026-08-28 19:01         ` Chao Liu via qemu development
  0 siblings, 0 replies; 30+ messages in thread
From: Chao Liu via qemu development @ 2026-08-28 19:01 UTC (permalink / raw)
  To: Daniel Henrique Barboza
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt

Hi Daniel,

On Fri, Aug 28, 2026 at 12:40:38PM +0800, Daniel Henrique Barboza wrote:
> 
> 
> On 8/28/2026 1:13 AM, Chao Liu wrote:
> > On Thu, Aug 27, 2026 at 07:26:01PM +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>
> > > ---
> > >   hw/riscv/fdt-common.c         |  96 ++++++++++++++++++++++++++++++++
> > >   hw/riscv/virt.c               | 101 ++++------------------------------
> > >   include/hw/riscv/fdt-common.h |  11 ++++
> > >   3 files changed, 119 insertions(+), 89 deletions(-)
> > > 
> > > diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
> > > index d815c5adff..76a783709d 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,98 @@ 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);
> > > +    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,
> > Should be:
> > 	   2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> > 
> > I found an MTIMER FDT issue in the virt machine FDT.
> > 
> > Command:
> > 
> > ```
> >    timeout 30s ./build/qemu-system-riscv64 \
> >      -machine virt,aia=aplic-imsic,aia-guests=5,aclint=on,dumpdtb=/tmp/virt.dtb \
> >      -smp 2 -display none -nodefaults
> > 
> >    dtc -I dtb -O dts /tmp/virt.dtb | grep -A4 mtimer@
> > ```
> > 
> > The generated FDT contains:
> > 
> >                  mtimer@2000000 {
> >                          interrupts-extended = <0x04 0x07 0x02 0x07>;
> >                          reg = <0x00 0x2000000 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
> >                          compatible = "riscv,aclint-mtimer";
> >                  };
> > 
> > without this patches:
> > 
> >                    mtimer@2000000 {
> >                            interrupts-extended = <0x04 0x07 0x02 0x07>;
> >                            reg = <0x00 0x2007ff8 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
> >                            compatible = "riscv,aclint-mtimer";
> >                    };
> > 
> > The first address should be 0x20007ff8.
> 
> That was intentional and I forgot to document it in the commit msg. The
> "No FDT changes made" I said doesn't apply here. My bad!
Thanks for clarifying. I also noticed this waring during my previous
review and testing.

> 
> If you use 'dtc' in the current 'virt' DT you'll get 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"
Yes, the warning is valid, and I can reproduce it as well.

> 
> 
> This happens because the unit address in the node name doesn't match the
> first address in 'reg'.  For mtimer@2000000, "reg" must be reg = <0x00 0x2000000 (...)>.
> For mtimer@2008000, reg = <0x00 2008000 (...)> and so on.
I agree that the address in the node name should match the first address
in `reg`, as described by the Devicetree Spec [1].

However, I think the value that needs to change is the node name, not
the first address in `reg`.

See ACLINT spec, an MITER device has two separate base addr: one for MTIME
and another for the MTIMECMP registers [2].

In the current QEMU implement, `addr` is the MTIMECMP base address, while
the MTIME register is located at:

	addr + RISCV_ACLINT_DEFAULT_METIME

For this example:

	MTIMECMP base = 0x2000000
	MITIME   base = 0x2007ff8

So the existing `reg` property correctly describes the two register
regions:

	reg = <0x00 0x2007ff8 0x00 0x08
	       0x00 0x2000000 0x00 0x7ff8>

> 
> 
> Now, does this change break aclint in 'virt'?  Because in that case we'll
> just keep the "dtc" warning and live with it.  Aside from the existing tests
> we have in QEMU I didn't do a deep dive in aclint.
Yes, I think using `addr` here would make the ACLINT description
incorrect. `addr` is the MTIMECMP base address, while MTIME is located
at `addr + RISCV_ACLINT_DEFAULT_MTIME`.

Please keep the first `reg` address as it was:

      qemu_fdt_setprop_sized_cells(fdt, name, "reg",
-          2, addr,
+          2, addr + RISCV_ACLINT_DEFAULT_MTIME,
           2, size - RISCV_ACLINT_DEFAULT_MTIME,
           2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
           2, RISCV_ACLINT_DEFAULT_MTIME);

Since this patch is mainly a code-duplication cleanup, I suggest
leaving the generated FDT unchanged here. The unit-address fix can be
sent as a separate follow-up patch:

- name = g_strdup_printf("/soc/mtimer@%" HWADDR_PRIx, addr);
+ name = g_strdup_printf("/soc/mtimer@%" HWADDR_PRIx,
+                        addr + RISCV_ACLINT_DEFAULT_MTIME);

--

LINK:

[1] Devicetree Specification, Section 2.2.1, "Node Names":
    https://devicetree-specification.readthedocs.io/en/stable/devicetree-basics.html#node-names

[2] RISC-V ACLINT Specification, "Machine-level Timer Device (MTIMER)",
    Section "Register Map":
    https://github.com/riscvarchive/riscv-aclint/blob/main/riscv-aclint.adoc


Thanks,
Chao
> 
> 
> Thanks,
> Daniel
> 
> > 
> > > +        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> > > +        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> > > +        2, RISCV_ACLINT_DEFAULT_MTIME);
> > 
> > [...]
> > 
> > > +    qemu_fdt_setprop(fdt, name, "interrupts-extended",
> > > -    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
> > > -        2, addr + RISCV_ACLINT_DEFAULT_MTIME,
> > I think this is the original code that was moved here.
> > 
> > Thanks,
> > Chao
> > > -        2, size - RISCV_ACLINT_DEFAULT_MTIME,
> > > -        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
> > > -        2, RISCV_ACLINT_DEFAULT_MTIME);
> > 
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint()
  2026-08-28 19:01         ` Chao Liu via qemu development
  (?)
@ 2026-08-28 19:52         ` Daniel Henrique Barboza
  -1 siblings, 0 replies; 30+ messages in thread
From: Daniel Henrique Barboza @ 2026-08-28 19:52 UTC (permalink / raw)
  To: Chao Liu
  Cc: qemu-devel, qemu-riscv, alistair.francis, liwei1518, zhiwei_liu,
	Philippe Mathieu-Daudé, Palmer Dabbelt



On 8/28/2026 4:01 PM, Chao Liu wrote:
> Hi Daniel,
> 
> On Fri, Aug 28, 2026 at 12:40:38PM +0800, Daniel Henrique Barboza wrote:
>>
>>
>> On 8/28/2026 1:13 AM, Chao Liu wrote:
>>> On Thu, Aug 27, 2026 at 07:26:01PM +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>
>>>> ---
>>>>    hw/riscv/fdt-common.c         |  96 ++++++++++++++++++++++++++++++++
>>>>    hw/riscv/virt.c               | 101 ++++------------------------------
>>>>    include/hw/riscv/fdt-common.h |  11 ++++
>>>>    3 files changed, 119 insertions(+), 89 deletions(-)
>>>>
>>>> diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c
>>>> index d815c5adff..76a783709d 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,98 @@ 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);
>>>> +    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,
>>> Should be:
>>> 	   2, addr + RISCV_ACLINT_DEFAULT_MTIME,
>>>
>>> I found an MTIMER FDT issue in the virt machine FDT.
>>>
>>> Command:
>>>
>>> ```
>>>     timeout 30s ./build/qemu-system-riscv64 \
>>>       -machine virt,aia=aplic-imsic,aia-guests=5,aclint=on,dumpdtb=/tmp/virt.dtb \
>>>       -smp 2 -display none -nodefaults
>>>
>>>     dtc -I dtb -O dts /tmp/virt.dtb | grep -A4 mtimer@
>>> ```
>>>
>>> The generated FDT contains:
>>>
>>>                   mtimer@2000000 {
>>>                           interrupts-extended = <0x04 0x07 0x02 0x07>;
>>>                           reg = <0x00 0x2000000 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
>>>                           compatible = "riscv,aclint-mtimer";
>>>                   };
>>>
>>> without this patches:
>>>
>>>                     mtimer@2000000 {
>>>                             interrupts-extended = <0x04 0x07 0x02 0x07>;
>>>                             reg = <0x00 0x2007ff8 0x00 0x08 0x00 0x2000000 0x00 0x7ff8>;
>>>                             compatible = "riscv,aclint-mtimer";
>>>                     };
>>>
>>> The first address should be 0x20007ff8.
>>
>> That was intentional and I forgot to document it in the commit msg. The
>> "No FDT changes made" I said doesn't apply here. My bad!
> Thanks for clarifying. I also noticed this waring during my previous
> review and testing.
> 
>>
>> If you use 'dtc' in the current 'virt' DT you'll get 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"
> Yes, the warning is valid, and I can reproduce it as well.
> 
>>
>>
>> This happens because the unit address in the node name doesn't match the
>> first address in 'reg'.  For mtimer@2000000, "reg" must be reg = <0x00 0x2000000 (...)>.
>> For mtimer@2008000, reg = <0x00 2008000 (...)> and so on.
> I agree that the address in the node name should match the first address
> in `reg`, as described by the Devicetree Spec [1].
> 
> However, I think the value that needs to change is the node name, not
> the first address in `reg`.
> 
> See ACLINT spec, an MITER device has two separate base addr: one for MTIME
> and another for the MTIMECMP registers [2].
> 
> In the current QEMU implement, `addr` is the MTIMECMP base address, while
> the MTIME register is located at:
> 
> 	addr + RISCV_ACLINT_DEFAULT_METIME
> 
> For this example:
> 
> 	MTIMECMP base = 0x2000000
> 	MITIME   base = 0x2007ff8
> 
> So the existing `reg` property correctly describes the two register
> regions:
> 
> 	reg = <0x00 0x2007ff8 0x00 0x08
> 	       0x00 0x2000000 0x00 0x7ff8>
> 
>>
>>
>> Now, does this change break aclint in 'virt'?  Because in that case we'll
>> just keep the "dtc" warning and live with it.  Aside from the existing tests
>> we have in QEMU I didn't do a deep dive in aclint.
> Yes, I think using `addr` here would make the ACLINT description
> incorrect. `addr` is the MTIMECMP base address, while MTIME is located
> at `addr + RISCV_ACLINT_DEFAULT_MTIME`.
> 
> Please keep the first `reg` address as it was:
> 
>        qemu_fdt_setprop_sized_cells(fdt, name, "reg",
> -          2, addr,
> +          2, addr + RISCV_ACLINT_DEFAULT_MTIME,
>             2, size - RISCV_ACLINT_DEFAULT_MTIME,
>             2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
>             2, RISCV_ACLINT_DEFAULT_MTIME);
> 
> Since this patch is mainly a code-duplication cleanup, I suggest
> leaving the generated FDT unchanged here. The unit-address fix can be
> sent as a separate follow-up patch:
> 
> - name = g_strdup_printf("/soc/mtimer@%" HWADDR_PRIx, addr);
> + name = g_strdup_printf("/soc/mtimer@%" HWADDR_PRIx,
> +                        addr + RISCV_ACLINT_DEFAULT_MTIME);

Oh, I think I get it.  The correct fix is changing the nodename to use
addr + RISCV_ACLINT_DEFAULT_MTIME.


I'll do as you said in v5. Thanks for clarifying,

Daniel

> 
> --
> 
> LINK:
> 
> [1] Devicetree Specification, Section 2.2.1, "Node Names":
>      https://devicetree-specification.readthedocs.io/en/stable/devicetree-basics.html#node-names
> 
> [2] RISC-V ACLINT Specification, "Machine-level Timer Device (MTIMER)",
>      Section "Register Map":
>      https://github.com/riscvarchive/riscv-aclint/blob/main/riscv-aclint.adoc
> 
> 
> Thanks,
> Chao
>>
>>
>> Thanks,
>> Daniel
>>
>>>
>>>> +        2, size - RISCV_ACLINT_DEFAULT_MTIME,
>>>> +        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
>>>> +        2, RISCV_ACLINT_DEFAULT_MTIME);
>>>
>>> [...]
>>>
>>>> +    qemu_fdt_setprop(fdt, name, "interrupts-extended",
>>>> -    qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg",
>>>> -        2, addr + RISCV_ACLINT_DEFAULT_MTIME,
>>> I think this is the original code that was moved here.
>>>
>>> Thanks,
>>> Chao
>>>> -        2, size - RISCV_ACLINT_DEFAULT_MTIME,
>>>> -        2, addr + RISCV_ACLINT_DEFAULT_MTIMECMP,
>>>> -        2, RISCV_ACLINT_DEFAULT_MTIME);
>>>
>>



^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2026-08-28 19:52 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27 22:25 [PATCH v4 00/14] hw/riscv: trivial code dup work (riscv-server-ref prep) Daniel Henrique Barboza
2026-08-27 22:25 ` [PATCH v4 01/14] hw/riscv/fdt-common: prepend helpers with "riscv_" Daniel Henrique Barboza
2026-08-28  2:54   ` Chao Liu via
2026-08-28  2:54     ` Chao Liu via qemu development
2026-08-28  7:16   ` Philippe Mathieu-Daudé
2026-08-27 22:25 ` [PATCH v4 02/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_flash() Daniel Henrique Barboza
2026-08-28  2:55   ` Chao Liu via qemu development
2026-08-28  2:55     ` Chao Liu via
2026-08-27 22:25 ` [PATCH v4 03/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_syscon() Daniel Henrique Barboza
2026-08-28  2:56   ` Chao Liu via qemu development
2026-08-28  2:56     ` Chao Liu via
2026-08-27 22:25 ` [PATCH v4 04/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_riscv_iommu_sys() Daniel Henrique Barboza
2026-08-28  2:57   ` Chao Liu via qemu development
2026-08-28  2:57     ` Chao Liu via
2026-08-27 22:25 ` [PATCH v4 05/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_pcie() Daniel Henrique Barboza
2026-08-27 22:25 ` [PATCH v4 06/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_imsic() Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 07/14] hw/riscv/fdt_common, virt.c: add riscv_create_fdt_socket_aplic() Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 08/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_socket_aclint() Daniel Henrique Barboza
2026-08-28  4:13   ` Chao Liu via
2026-08-28  4:13     ` Chao Liu via qemu development
2026-08-28 15:40     ` Daniel Henrique Barboza
2026-08-28 19:01       ` Chao Liu via
2026-08-28 19:01         ` Chao Liu via qemu development
2026-08-28 19:52         ` Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 09/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_uart() Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 10/14] hw/riscv/fdt-common, virt.c: add riscv_create_fdt_rtc() Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 11/14] hw/riscv/device-common, virt.c: add riscv_create_platform_bus() Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 12/14] hw/riscv/device-common, virt.c: add flash helpers Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 13/14] hw/riscv/device-common, virt.c: add riscv_gpex_pcie_init() Daniel Henrique Barboza
2026-08-27 22:26 ` [PATCH v4 14/14] hw/riscv/riscv-iommu-sys.c, virt.c: add riscv_create_iommu_sys() Daniel Henrique Barboza

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.