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 <cfu@mips.com>
Signed-off-by: Djordje Todorovic <djordje.todorovic@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
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index fe166e08bc..dac830d2f5 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -116,12 +116,17 @@ config RISCV_CPC
bool
default n
+config RISCV_CPS
+ bool
+ default n
+
config MIPS_BOSTON_AIA
bool
default y
depends on RISCV64
select RISCV_CMGCR
select RISCV_CPC
+ select RISCV_CPS
config MPS2_FPGAIO
bool
diff --git a/hw/riscv/cps.c b/hw/riscv/cps.c
new file mode 100644
index 0000000000..b6439a85d6
--- /dev/null
+++ b/hw/riscv/cps.c
@@ -0,0 +1,197 @@
+/*
+ * Coherent Processing System emulation.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * Copyright (c) 2025 MIPS
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "hw/riscv/cps.h"
+#include "hw/qdev-properties.h"
+#include "system/reset.h"
+#include "hw/intc/riscv_aclint.h"
+#include "hw/intc/riscv_aplic.h"
+#include "hw/intc/riscv_imsic.h"
+#include "hw/pci/msi.h"
+
+static void riscv_cps_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ RISCVCPSState *s = RISCV_CPS(obj);
+
+ /*
+ * Cover entire address space as there do not seem to be any
+ * constraints for the base address of CPC .
+ */
+ memory_region_init(&s->container, obj, "mips-cps-container", UINT64_MAX);
+ sysbus_init_mmio(sbd, &s->container);
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPUState *cs = CPU(cpu);
+
+ cpu_reset(cs);
+}
+
+static void riscv_cps_realize(DeviceState *dev, Error **errp)
+{
+ RISCVCPSState *s = RISCV_CPS(dev);
+ RISCVCPU *cpu;
+ int i;
+
+ /* 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);
+
+ /* Pass CPU array to CPC */
+ s->cpc.cpus = s->cpus;
+
+ 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);
+ }
+}
+
+static const Property riscv_cps_properties[] = {
+ DEFINE_PROP_UINT32("num-vp", RISCVCPSState, num_vp, 1),
+ DEFINE_PROP_UINT32("num-hart", RISCVCPSState, num_hart, 1),
+ DEFINE_PROP_UINT32("num-core", RISCVCPSState, num_core, 1),
+ DEFINE_PROP_UINT64("gcr-base", RISCVCPSState, gcr_base, GCR_BASE_ADDR),
+ DEFINE_PROP_STRING("cpu-type", RISCVCPSState, cpu_type),
+};
+
+static void riscv_cps_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = riscv_cps_realize;
+ device_class_set_props(dc, riscv_cps_properties);
+}
+
+static const TypeInfo riscv_cps_info = {
+ .name = TYPE_RISCV_CPS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RISCVCPSState),
+ .instance_init = riscv_cps_init,
+ .class_init = riscv_cps_class_init,
+};
+
+static void riscv_cps_register_types(void)
+{
+ type_register_static(&riscv_cps_info);
+}
+
+type_init(riscv_cps_register_types)
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index c22f3a7216..78caaf84a3 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -14,4 +14,6 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
+riscv_ss.add(when: 'CONFIG_RISCV_CPS', if_true: files('cps.c'))
+
hw_arch += {'riscv': riscv_ss}
diff --git a/include/hw/riscv/cps.h b/include/hw/riscv/cps.h
new file mode 100644
index 0000000000..4886a01ec9
--- /dev/null
+++ b/include/hw/riscv/cps.h
@@ -0,0 +1,76 @@
+/*
+ * Coherent Processing System emulation.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * Copyright (c) 2025 MIPS
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ */
+
+#ifndef RISCV_CPS_H
+#define RISCV_CPS_H
+
+#include "hw/sysbus.h"
+#include "hw/misc/riscv_cmgcr.h"
+#include "hw/misc/riscv_cpc.h"
+#include "target/riscv/cpu.h"
+#include "qom/object.h"
+
+#define TYPE_RISCV_CPS "riscv-cps"
+OBJECT_DECLARE_SIMPLE_TYPE(RISCVCPSState, RISCV_CPS)
+
+/* The model supports up to 64 harts. */
+#define MAX_HARTS 64
+
+/* The global CM base for the boston-aia model. */
+#define GLOBAL_CM_BASE 0x16100000
+/* The CM block is 512 KiB. */
+#define CM_SIZE (1 << 19)
+
+/* The mhartid bits has cluster at bit 16, core at bit 4, and hart at
+ bit 0. */
+#define MHARTID_CLUSTER_SHIFT 16
+#define MHARTID_CORE_SHIFT 4
+#define MHARTID_HART_SHIFT 0
+
+#define APLIC_NUM_SOURCES 0x35 /* Arbitray maximum number of interrupts. */
+#define APLIC_NUM_PRIO_BITS 3
+#define AIA_PLIC_M_OFFSET 0x40000
+#define AIA_PLIC_M_SIZE 0x8000
+#define AIA_PLIC_S_OFFSET 0x60000
+#define AIA_PLIC_S_SIZE 0x8000
+#define AIA_CLINT_OFFSET 0x50000
+
+typedef struct RISCVCPSState {
+ SysBusDevice parent_obj;
+
+ uint32_t num_vp;
+ uint32_t num_hart;
+ uint32_t num_core;
+ uint64_t gcr_base;
+ char *cpu_type;
+
+ MemoryRegion container;
+ RISCVGCRState gcr;
+ RISCVCPCState cpc;
+
+ DeviceState *aplic;
+ CPUState **cpus;
+} RISCVCPSState;
+
+#endif
--
2.34.1
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 <cfu@mips.com> > Signed-off-by: Djordje Todorovic <djordje.todorovic@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); > + } > +}
On 8. 8. 25. 18:26, Philippe Mathieu-Daudé wrote: > CAUTION: This email originated from outside of the organization. Do > not click links or open attachments unless you recognize the sender > and know the content is safe. > > > 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 <cfu@mips.com> >> Signed-off-by: Djordje Todorovic <djordje.todorovic@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); >> + } >> +} Thank you! I will address it within v7.
© 2016 - 2025 Red Hat, Inc.