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 <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
---
  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);



Reply via email to