[PATCH v5 05/18] hw/hexagon: group the CPUs in a cluster

Brian Cain <[email protected]> Wed, 5 Aug 2026 21:27:10 -0700
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
The CPUs are now grouped in a TYPE_CPU_CLUSTER.

Reviewed-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 include/hw/hexagon/hex-subsys.h | 12 +++++++++++-
 include/hw/hexagon/hexagon.h    |  1 +
 hw/hexagon/hex-subsys.c         | 30 +++++++++++++++++++++++++++++-
 hw/hexagon/hexagon_dsp.c        | 11 ++++++++++-
 hw/hexagon/virt.c               | 11 ++++++++++-
 hw/hexagon/Kconfig              |  1 +
 6 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/include/hw/hexagon/hex-subsys.h b/include/hw/hexagon/hex-subsys.h
index 087c105cfa4..6d0d5e1da86 100644
--- a/include/hw/hexagon/hex-subsys.h
+++ b/include/hw/hexagon/hex-subsys.h
@@ -15,7 +15,17 @@
 void hex_subsys_create(HexagonCommonMachineState *hms,
                        const struct hexagon_machine_config *m_cfg, Rev_t rev);
 
-/* Realize a CPU into the subsystem. */
+/*
+ * Parent a CPU into the subsystem's cluster and wire its links.  Call for
+ * every CPU before hex_subsys_realize_cluster(), then realize each CPU with
+ * hex_subsys_realize_cpu().
+ */
+void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu);
+
+/* Realize the CPU cluster, once all CPUs have been parented into it. */
+void hex_subsys_realize_cluster(HexagonCommonMachineState *hms);
+
+/* Realize a CPU previously parented via hex_subsys_add_cpu(). */
 void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu);
 
 #endif /* HW_HEXAGON_HEX_SUBSYS_H */
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 6edd93f478a..31669a829f8 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -157,6 +157,7 @@ struct HexagonCommonMachineState {
     MemoryRegion ram;
     MemoryRegion cfgtable_rom;
     MemoryRegion vtcm;
+    DeviceState *cluster;
     DeviceState *glob_regs;
     DeviceState *tlb;
 };
diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c
index ac7e29604eb..6fad6fe0a4d 100644
--- a/hw/hexagon/hex-subsys.c
+++ b/hw/hexagon/hex-subsys.c
@@ -10,6 +10,7 @@
 #include "hw/hexagon/hex-subsys.h"
 #include "hw/hexagon/hexagon_globalreg.h"
 #include "hw/hexagon/hexagon_tlb.h"
+#include "hw/cpu/cluster.h"
 #include "hw/core/loader.h"
 #include "hw/core/qdev-properties.h"
 #include "hw/core/qdev.h"
@@ -42,6 +43,16 @@ static DeviceState *tlb_create(HexagonCommonMachineState *hms,
     return tlb;
 }
 
+static DeviceState *cluster_create(HexagonCommonMachineState *hms)
+{
+    DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER);
+
+    object_property_add_child(OBJECT(hms), "cluster", OBJECT(cluster));
+    qdev_prop_set_uint32(cluster, "cluster-id", 0);
+
+    return cluster;
+}
+
 void hex_subsys_create(HexagonCommonMachineState *hms,
                        const struct hexagon_machine_config *m_cfg, Rev_t rev)
 {
@@ -69,15 +80,32 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
                                     &hms->vtcm);
     }
 
+    hms->cluster = cluster_create(hms);
     hms->glob_regs = globalreg_create(hms, m_cfg, rev);
     hms->tlb = tlb_create(hms, m_cfg);
 }
 
-void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
+void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
 {
+    object_property_add_child(OBJECT(hms->cluster), "cpu[*]", OBJECT(cpu));
     object_property_set_link(OBJECT(cpu), "global-regs",
                              OBJECT(hms->glob_regs), &error_fatal);
     object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb),
                              &error_fatal);
+}
+
+void hex_subsys_realize_cluster(HexagonCommonMachineState *hms)
+{
+    /*
+     * The cluster must be realized after its CPUs have been parented into it
+     * (see hex_subsys_add_cpu()) but before any CPU is itself realized, since
+     * qdev_realize_and_unref() on a CPU latches cluster_index into the TCG
+     * cflags at that point.
+     */
+    qdev_realize_and_unref(hms->cluster, NULL, &error_fatal);
+}
+
+void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
+{
     qdev_realize_and_unref(cpu, NULL, &error_fatal);
 }
diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c
index 25e8550fba2..1db5d681665 100644
--- a/hw/hexagon/hexagon_dsp.c
+++ b/hw/hexagon/hexagon_dsp.c
@@ -118,6 +118,8 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
 
     hex_subsys_create(hms, m_cfg, rev);
 
+    g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, machine->smp.cpus);
+
     for (int i = 0; i < machine->smp.cpus; i++) {
         HexagonCPU *cpu = HEXAGON_CPU(object_new(machine->cpu_type));
         qemu_register_reset(do_cpu_reset, cpu);
@@ -130,7 +132,14 @@ static void hexagon_common_init(MachineState *machine, Rev_t rev,
         if (i == 0) {
             hexagon_init_bootstrap(dms, cpu);
         }
-        hex_subsys_realize_cpu(hms, DEVICE(cpu));
+        hex_subsys_add_cpu(hms, DEVICE(cpu));
+        cpus[i] = cpu;
+    }
+
+    hex_subsys_realize_cluster(hms);
+
+    for (int i = 0; i < machine->smp.cpus; i++) {
+        hex_subsys_realize_cpu(hms, DEVICE(cpus[i]));
     }
 }
 
diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c
index b9e0bbb704c..dc1d5b6aa24 100644
--- a/hw/hexagon/virt.c
+++ b/hw/hexagon/virt.c
@@ -246,6 +246,8 @@ static void virt_init(MachineState *ms)
 
     fdt_add_hvx(vms, m_cfg);
 
+    g_autofree HexagonCPU **cpus = g_new(HexagonCPU *, ms->smp.cpus);
+
     for (int i = 0; i < ms->smp.cpus; i++) {
         HexagonCPU *cpu = HEXAGON_CPU(object_new(ms->cpu_type));
         qemu_register_reset(do_cpu_reset, cpu);
@@ -261,7 +263,14 @@ static void virt_init(MachineState *ms)
         }
         qdev_prop_set_uint32(DEVICE(cpu), "htid", i);
         qdev_prop_set_bit(DEVICE(cpu), "start-powered-off", (i != 0));
-        hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpu));
+        hex_subsys_add_cpu(&vms->parent_obj, DEVICE(cpu));
+        cpus[i] = cpu;
+    }
+
+    hex_subsys_realize_cluster(&vms->parent_obj);
+
+    for (int i = 0; i < ms->smp.cpus; i++) {
+        hex_subsys_realize_cpu(&vms->parent_obj, DEVICE(cpus[i]));
     }
 
     fdt_add_cpu_nodes(vms);
diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig
index 52065ab3b22..121c548bbb9 100644
--- a/hw/hexagon/Kconfig
+++ b/hw/hexagon/Kconfig
@@ -2,6 +2,7 @@ config HEX_DSP
     bool
     default y
     depends on HEXAGON
+    select CPU_CLUSTER
 
 config HEX_VIRT
     bool
-- 
2.34.1