On 17/7/25 11:38, Djordje Todorovic wrote:
Add support for the Coherent Processing System for RISC-V.
This enables SMP support for RISC-V boards that require
cache-coherent multiprocessor systems.

Signed-off-by: Chao-ying Fu <c...@mips.com>
Signed-off-by: Djordje Todorovic <djordje.todoro...@htecgroup.com>
---
  hw/misc/Kconfig        |   5 ++
  hw/riscv/cps.c         | 197 +++++++++++++++++++++++++++++++++++++++++
  hw/riscv/meson.build   |   2 +
  include/hw/riscv/cps.h |  76 ++++++++++++++++
  4 files changed, 280 insertions(+)
  create mode 100644 hw/riscv/cps.c
  create mode 100644 include/hw/riscv/cps.h


+static void main_cpu_reset(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);

If you call in [*]:

       qemu_register_reset(main_cpu_reset, s->cpus[i]);

then here you can just do:

       CPUState *cs = opaque;

+
+    cpu_reset(cs);
+}
+
+static void riscv_cps_realize(DeviceState *dev, Error **errp)
+{
+    RISCVCPSState *s = RISCV_CPS(dev);
+    RISCVCPU *cpu;
+    int i;
+

Please check num_vp range.

+    /* Allocate CPU array */
+    s->cpus = g_new0(CPUState *, s->num_vp);
+
+    /* Set up cpu_index and mhartid for avaiable CPUs. */
+    int harts_in_cluster = s->num_hart * s->num_core;
+    int num_of_clusters = s->num_vp / harts_in_cluster;
+    for (i = 0; i < s->num_vp; i++) {
+        cpu = RISCV_CPU(object_new(s->cpu_type));
+
+        /* All VPs are halted on reset. Leave powering up to CPC. */
+        object_property_set_bool(OBJECT(cpu), "start-powered-off", true,
+                                 &error_abort);
+
+        if (!qdev_realize_and_unref(DEVICE(cpu), NULL, errp)) {
+            return;
+        }
+
+        /* Store CPU in array */
+        s->cpus[i] = CPU(cpu);
+
+        /* Set up mhartid */
+        int cluster_id = i / harts_in_cluster;
+        int hart_id = (i % harts_in_cluster) % s->num_hart;
+        int core_id = (i % harts_in_cluster) / s->num_hart;
+        int mhartid = (cluster_id << MHARTID_CLUSTER_SHIFT) +
+                      (core_id << MHARTID_CORE_SHIFT) +
+                      (hart_id << MHARTID_HART_SHIFT);
+        cpu->env.mhartid = mhartid;
+        qemu_register_reset(main_cpu_reset, cpu);

[*]

+    }
+
+    /* Cluster Power Controller */
+    object_initialize_child(OBJECT(dev), "cpc", &s->cpc, TYPE_RISCV_CPC);
+    object_property_set_uint(OBJECT(&s->cpc), "cluster-id", 0,
+                            &error_abort);
+    object_property_set_uint(OBJECT(&s->cpc), "num-vp", s->num_vp,
+                            &error_abort);
+    object_property_set_uint(OBJECT(&s->cpc), "num-hart", s->num_hart,
+                            &error_abort);
+    object_property_set_uint(OBJECT(&s->cpc), "num-core", s->num_core,
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->cpc), "vp-start-running", 1,
+                            &error_abort);

(1 is already the default)

+
+    /* Pass CPU array to CPC */
+    s->cpc.cpus = s->cpus;

Please do that using a link property.

+
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->cpc), errp)) {
+        return;
+    }
+
+    memory_region_add_subregion(&s->container, 0,
+                            sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 
0));
+
+    /* Global Configuration Registers */
+    object_initialize_child(OBJECT(dev), "gcr", &s->gcr, TYPE_RISCV_GCR);
+    object_property_set_uint(OBJECT(&s->gcr), "cluster-id", 0,
+                            &error_abort);
+    object_property_set_uint(OBJECT(&s->gcr), "num-vp", s->num_vp,
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->gcr), "gcr-rev", 0xa00,
+                            &error_abort);
+    object_property_set_int(OBJECT(&s->gcr), "gcr-base", s->gcr_base,
+                            &error_abort);
+    object_property_set_link(OBJECT(&s->gcr), "cpc", OBJECT(&s->cpc.mr),
+                             &error_abort);
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->gcr), errp)) {
+        return;
+    }
+
+    memory_region_add_subregion(&s->container, s->gcr_base,
+                            sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gcr), 
0));
+
+    for (i = 0; i < num_of_clusters; i++) {
+        uint64_t cm_base = GLOBAL_CM_BASE + (CM_SIZE * i);
+        uint32_t hartid_base = i << MHARTID_CLUSTER_SHIFT;
+        s->aplic = riscv_aplic_create(cm_base + AIA_PLIC_M_OFFSET,
+                                      AIA_PLIC_M_SIZE,
+                                      hartid_base, /* hartid_base */
+                                      MAX_HARTS, /* num_harts */
+                                      APLIC_NUM_SOURCES,
+                                      APLIC_NUM_PRIO_BITS,
+                                      false, true, NULL);
+        riscv_aplic_create(cm_base + AIA_PLIC_S_OFFSET,
+                           AIA_PLIC_S_SIZE,
+                           hartid_base, /* hartid_base */
+                           MAX_HARTS, /* num_harts */
+                           APLIC_NUM_SOURCES,
+                           APLIC_NUM_PRIO_BITS,
+                           false, false, s->aplic);
+        /* PLIC changes msi_nonbroken to ture. We revert the change. */
+        msi_nonbroken = false;
+        riscv_aclint_swi_create(cm_base + AIA_CLINT_OFFSET,
+                                hartid_base, MAX_HARTS, false);
+        riscv_aclint_mtimer_create(cm_base + AIA_CLINT_OFFSET +
+                                   RISCV_ACLINT_SWI_SIZE,
+                                   RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
+                                   hartid_base,
+                                   MAX_HARTS,
+                                   RISCV_ACLINT_DEFAULT_MTIMECMP,
+                                   RISCV_ACLINT_DEFAULT_MTIME,
+                                   RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false);
+    }
+}

Reply via email to