All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/3] RISC-V ACLINT Support
@ 2021-06-12 16:06 ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The RISC-V Advanced Core Local Interruptor (ACLINT) is an improvement
over the SiFive CLINT but also maintains backward compatibility with
the SiFive CLINT.

Latest RISC-V ACLINT specification (will be frozen in a month) can be
found at:
https://github.com/riscv/riscv-aclint/blob/main/riscv-aclint.adoc

This series:
1) Replaces SiFive CLINT implementation with RISC-V ACLINT
2) Refactors RISC-V virt machine FDT generation
3) Adds optional full ACLINT support in QEMU RISC-V virt machine

This series can be found in the riscv_aclint_v1 branch at:
https://github.com/avpatel/qemu.git

To test series, we require OpenSBI and Linux with ACLINT support which
can be found in riscv_aclint_v1 branch at:
https://github.com/avpatel/opensbi.git
https://github.com/avpatel/linux.git

Anup Patel (3):
  hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  hw/riscv: virt: Re-factor FDT generation
  hw/riscv: virt: Add optional ACLINT support to virt machine

 hw/intc/Kconfig                |   2 +-
 hw/intc/meson.build            |   2 +-
 hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++
 hw/intc/sifive_clint.c         | 266 --------------
 hw/riscv/Kconfig               |  10 +-
 hw/riscv/microchip_pfsoc.c     |  12 +-
 hw/riscv/sifive_e.c            |  12 +-
 hw/riscv/sifive_u.c            |  14 +-
 hw/riscv/spike.c               |  15 +-
 hw/riscv/virt.c                | 635 ++++++++++++++++++++++-----------
 include/hw/intc/riscv_aclint.h |  73 ++++
 include/hw/intc/sifive_clint.h |  60 ----
 include/hw/riscv/virt.h        |   2 +
 13 files changed, 923 insertions(+), 554 deletions(-)
 create mode 100644 hw/intc/riscv_aclint.c
 delete mode 100644 hw/intc/sifive_clint.c
 create mode 100644 include/hw/intc/riscv_aclint.h
 delete mode 100644 include/hw/intc/sifive_clint.h

-- 
2.25.1



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

* [PATCH v1 0/3] RISC-V ACLINT Support
@ 2021-06-12 16:06 ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The RISC-V Advanced Core Local Interruptor (ACLINT) is an improvement
over the SiFive CLINT but also maintains backward compatibility with
the SiFive CLINT.

Latest RISC-V ACLINT specification (will be frozen in a month) can be
found at:
https://github.com/riscv/riscv-aclint/blob/main/riscv-aclint.adoc

This series:
1) Replaces SiFive CLINT implementation with RISC-V ACLINT
2) Refactors RISC-V virt machine FDT generation
3) Adds optional full ACLINT support in QEMU RISC-V virt machine

This series can be found in the riscv_aclint_v1 branch at:
https://github.com/avpatel/qemu.git

To test series, we require OpenSBI and Linux with ACLINT support which
can be found in riscv_aclint_v1 branch at:
https://github.com/avpatel/opensbi.git
https://github.com/avpatel/linux.git

Anup Patel (3):
  hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  hw/riscv: virt: Re-factor FDT generation
  hw/riscv: virt: Add optional ACLINT support to virt machine

 hw/intc/Kconfig                |   2 +-
 hw/intc/meson.build            |   2 +-
 hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++
 hw/intc/sifive_clint.c         | 266 --------------
 hw/riscv/Kconfig               |  10 +-
 hw/riscv/microchip_pfsoc.c     |  12 +-
 hw/riscv/sifive_e.c            |  12 +-
 hw/riscv/sifive_u.c            |  14 +-
 hw/riscv/spike.c               |  15 +-
 hw/riscv/virt.c                | 635 ++++++++++++++++++++++-----------
 include/hw/intc/riscv_aclint.h |  73 ++++
 include/hw/intc/sifive_clint.h |  60 ----
 include/hw/riscv/virt.h        |   2 +
 13 files changed, 923 insertions(+), 554 deletions(-)
 create mode 100644 hw/intc/riscv_aclint.c
 delete mode 100644 hw/intc/sifive_clint.c
 create mode 100644 include/hw/intc/riscv_aclint.h
 delete mode 100644 include/hw/intc/sifive_clint.h

-- 
2.25.1



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

* [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  2021-06-12 16:06 ` Anup Patel
@ 2021-06-12 16:06   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The RISC-V ACLINT is more modular and backward compatible with
original SiFive CLINT so instead of duplicating the orignal
SiFive CLINT implementation we upgrade the current SiFive CLINT
implementation to RISC-V ACLINT implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/intc/Kconfig                |   2 +-
 hw/intc/meson.build            |   2 +-
 hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
 hw/intc/sifive_clint.c         | 266 -----------------------
 hw/riscv/Kconfig               |  10 +-
 hw/riscv/microchip_pfsoc.c     |  12 +-
 hw/riscv/sifive_e.c            |  12 +-
 hw/riscv/sifive_u.c            |  14 +-
 hw/riscv/spike.c               |  15 +-
 hw/riscv/virt.c                |  15 +-
 include/hw/intc/riscv_aclint.h |  73 +++++++
 include/hw/intc/sifive_clint.h |  60 ------
 12 files changed, 494 insertions(+), 361 deletions(-)
 create mode 100644 hw/intc/riscv_aclint.c
 delete mode 100644 hw/intc/sifive_clint.c
 create mode 100644 include/hw/intc/riscv_aclint.h
 delete mode 100644 include/hw/intc/sifive_clint.h

diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index f4694088a4..78aed93c45 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -62,7 +62,7 @@ config RX_ICU
 config LOONGSON_LIOINTC
     bool
 
-config SIFIVE_CLINT
+config RISCV_ACLINT
     bool
 
 config SIFIVE_PLIC
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 1c299039f6..2482fcfaf8 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
 specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
 specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
 specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
-specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
+specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
 specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
 specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
 specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
new file mode 100644
index 0000000000..682f95cca7
--- /dev/null
+++ b/hw/intc/riscv_aclint.c
@@ -0,0 +1,374 @@
+/*
+ * RISC-V ACLINT (Advanced Core Local Interruptor)
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This provides real-time clock, timer and interprocessor interrupts.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "hw/sysbus.h"
+#include "target/riscv/cpu.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/riscv_aclint.h"
+#include "qemu/timer.h"
+
+static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
+{
+    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+        timebase_freq, NANOSECONDS_PER_SECOND);
+}
+
+/*
+ * Called when timecmp is written to update the QEMU timer or immediately
+ * trigger timer interrupt if mtimecmp <= current timer value.
+ */
+static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
+    uint32_t timebase_freq)
+{
+    uint64_t next;
+    uint64_t diff;
+
+    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
+
+    cpu->env.timecmp = value;
+    if (cpu->env.timecmp <= rtc_r) {
+        /* if we're setting an MTIMECMP value in the "past",
+           immediately raise the timer interrupt */
+        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
+        return;
+    }
+
+    /* otherwise, set up the future timer interrupt */
+    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
+    diff = cpu->env.timecmp - rtc_r;
+    /* back to ns (note args switched in muldiv64) */
+    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
+    timer_mod(cpu->env.timer, next);
+}
+
+/*
+ * Callback used when the timer set using timer_mod expires.
+ * Should raise the timer interrupt line
+ */
+static void riscv_aclint_mtimer_cb(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
+}
+
+/* CPU wants to read MTIMER register */
+static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
+    unsigned size)
+{
+    RISCVAclintMTimerState *mtimer = opaque;
+
+    if (addr < (mtimer->num_harts << 3)) {
+        size_t hartid = mtimer->hartid_base + (addr >> 3);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x7) == 0) {
+            /* timecmp_lo */
+            uint64_t timecmp = env->timecmp;
+            return timecmp & 0xFFFFFFFF;
+        } else if ((addr & 0x7) == 4) {
+            /* timecmp_hi */
+            uint64_t timecmp = env->timecmp;
+            return (timecmp >> 32) & 0xFFFFFFFF;
+        } else {
+            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
+            return 0;
+        }
+    } else if (addr == (mtimer->aperture_size - 8)) {
+        /* time_lo */
+        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
+    } else if (addr == (mtimer->aperture_size - 4)) {
+        /* time_hi */
+        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
+    }
+
+    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
+    return 0;
+}
+
+/* CPU wrote MTIMER register */
+static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
+    uint64_t value, unsigned size)
+{
+    RISCVAclintMTimerState *mtimer = opaque;
+
+    if (addr < (mtimer->num_harts << 3)) {
+        size_t hartid = mtimer->hartid_base + (addr >> 3);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x7) == 0) {
+            /* timecmp_lo */
+            uint64_t timecmp_hi = env->timecmp >> 32;
+            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
+                timecmp_hi << 32 | (value & 0xFFFFFFFF),
+                mtimer->timebase_freq);
+            return;
+        } else if ((addr & 0x7) == 4) {
+            /* timecmp_hi */
+            uint64_t timecmp_lo = env->timecmp;
+            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
+                value << 32 | (timecmp_lo & 0xFFFFFFFF),
+                mtimer->timebase_freq);
+        } else {
+            error_report("aclint-mtimer: invalid timecmp write: %08x",
+                         (uint32_t)addr);
+        }
+        return;
+    } else if (addr == (mtimer->aperture_size - 8)) {
+        /* time_lo */
+        error_report("aclint-mtimer: time_lo write not implemented");
+        return;
+    } else if (addr == (mtimer->aperture_size - 4)) {
+        /* time_hi */
+        error_report("aclint-mtimer: time_hi write not implemented");
+        return;
+    }
+
+    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
+}
+
+static const MemoryRegionOps riscv_aclint_mtimer_ops = {
+    .read = riscv_aclint_mtimer_read,
+    .write = riscv_aclint_mtimer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 8
+    }
+};
+
+static Property riscv_aclint_mtimer_properties[] = {
+    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
+        hartid_base, 0),
+    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
+    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
+        aperture_size, 0),
+    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
+        timebase_freq, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    RISCVCPU *cpu;
+    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
+                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+
+    /* Claim MTIP so that only MTIMER controls it. */
+    for (i = 0; i < s->num_harts; i++) {
+        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
+        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
+            error_report("MTIP already claimed");
+            exit(1);
+        }
+    }
+}
+
+static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = riscv_aclint_mtimer_realize;
+    device_class_set_props(dc, riscv_aclint_mtimer_properties);
+}
+
+static const TypeInfo riscv_aclint_mtimer_info = {
+    .name          = TYPE_RISCV_ACLINT_MTIMER,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RISCVAclintMTimerState),
+    .class_init    = riscv_aclint_mtimer_class_init,
+};
+
+/*
+ * Create ACLINT MTIMER device.
+ */
+DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
+    bool provide_rdtime)
+{
+    int i;
+    for (i = 0; i < num_harts; i++) {
+        CPUState *cpu = qemu_get_cpu(hartid_base + i);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            continue;
+        }
+        if (provide_rdtime) {
+            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
+        }
+        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                  &riscv_aclint_mtimer_cb, cpu);
+        env->timecmp = 0;
+    }
+
+    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
+    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
+    qdev_prop_set_uint32(dev, "num-harts", num_harts);
+    qdev_prop_set_uint32(dev, "aperture-size", size);
+    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
+    return dev;
+}
+
+/* CPU read [M|S]SWI register */
+static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
+    unsigned size)
+{
+    RISCVAclintSwiState *swi = opaque;
+
+    if (addr < (swi->num_harts << 2)) {
+        size_t hartid = swi->hartid_base + (addr >> 2);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-swi: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x3) == 0) {
+            return (env->mip & swi->sirq_mask) > 0;
+        } else {
+            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
+            return 0;
+        }
+    }
+
+    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
+    return 0;
+}
+
+/* CPU wrote [M|S]SWI register */
+static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
+        unsigned size)
+{
+    RISCVAclintSwiState *swi = opaque;
+
+    if (addr < (swi->num_harts << 2)) {
+        size_t hartid = swi->hartid_base + (addr >> 2);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-swi: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x3) == 0) {
+            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
+                                 BOOL_TO_MASK(value));
+        } else {
+            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
+                         (uint32_t)addr);
+        }
+        return;
+    }
+
+    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
+}
+
+static const MemoryRegionOps riscv_aclint_swi_ops = {
+    .read = riscv_aclint_swi_read,
+    .write = riscv_aclint_swi_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static Property riscv_aclint_swi_properties[] = {
+    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
+    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
+    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
+        aperture_size, 0),
+    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    RISCVCPU *cpu;
+    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
+                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+
+    /* Claim [M|S]SIP so that can SWI controls it. */
+    for (i = 0; i < s->num_harts; i++) {
+        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
+
+        /* We don't claim SSIP bit of mip CSR because this bit is
+         * writable by software as-per RISC-V privilege specification.
+         */
+        if ((s->sirq_mask != MIP_SSIP) &&
+            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
+            error_report("%s already claimed",
+                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
+            exit(1);
+        }
+    }
+}
+
+static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = riscv_aclint_swi_realize;
+    device_class_set_props(dc, riscv_aclint_swi_properties);
+}
+
+static const TypeInfo riscv_aclint_swi_info = {
+    .name          = TYPE_RISCV_ACLINT_SWI,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RISCVAclintSwiState),
+    .class_init    = riscv_aclint_swi_class_init,
+};
+
+/*
+ * Create ACLINT [M|S]SWI device.
+ */
+DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
+{
+    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
+    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
+    qdev_prop_set_uint32(dev, "num-harts", num_harts);
+    qdev_prop_set_uint32(dev, "aperture-size", size);
+    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
+    return dev;
+}
+
+static void riscv_aclint_register_types(void)
+{
+    type_register_static(&riscv_aclint_mtimer_info);
+    type_register_static(&riscv_aclint_swi_info);
+}
+
+type_init(riscv_aclint_register_types)
diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
deleted file mode 100644
index 0f41e5ea1c..0000000000
--- a/hw/intc/sifive_clint.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * SiFive CLINT (Core Local Interruptor)
- *
- * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This provides real-time clock, timer and interprocessor interrupts.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "hw/sysbus.h"
-#include "target/riscv/cpu.h"
-#include "hw/qdev-properties.h"
-#include "hw/intc/sifive_clint.h"
-#include "qemu/timer.h"
-
-static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
-{
-    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
-        timebase_freq, NANOSECONDS_PER_SECOND);
-}
-
-/*
- * Called when timecmp is written to update the QEMU timer or immediately
- * trigger timer interrupt if mtimecmp <= current timer value.
- */
-static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
-                                       uint32_t timebase_freq)
-{
-    uint64_t next;
-    uint64_t diff;
-
-    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
-
-    cpu->env.timecmp = value;
-    if (cpu->env.timecmp <= rtc_r) {
-        /* if we're setting an MTIMECMP value in the "past",
-           immediately raise the timer interrupt */
-        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
-        return;
-    }
-
-    /* otherwise, set up the future timer interrupt */
-    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
-    diff = cpu->env.timecmp - rtc_r;
-    /* back to ns (note args switched in muldiv64) */
-    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
-        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
-    timer_mod(cpu->env.timer, next);
-}
-
-/*
- * Callback used when the timer set using timer_mod expires.
- * Should raise the timer interrupt line
- */
-static void sifive_clint_timer_cb(void *opaque)
-{
-    RISCVCPU *cpu = opaque;
-    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
-}
-
-/* CPU wants to read rtc or timecmp register */
-static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
-{
-    SiFiveCLINTState *clint = opaque;
-    if (addr >= clint->sip_base &&
-        addr < clint->sip_base + (clint->num_harts << 2)) {
-        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x3) == 0) {
-            return (env->mip & MIP_MSIP) > 0;
-        } else {
-            error_report("clint: invalid read: %08x", (uint32_t)addr);
-            return 0;
-        }
-    } else if (addr >= clint->timecmp_base &&
-        addr < clint->timecmp_base + (clint->num_harts << 3)) {
-        size_t hartid = clint->hartid_base +
-            ((addr - clint->timecmp_base) >> 3);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x7) == 0) {
-            /* timecmp_lo */
-            uint64_t timecmp = env->timecmp;
-            return timecmp & 0xFFFFFFFF;
-        } else if ((addr & 0x7) == 4) {
-            /* timecmp_hi */
-            uint64_t timecmp = env->timecmp;
-            return (timecmp >> 32) & 0xFFFFFFFF;
-        } else {
-            error_report("clint: invalid read: %08x", (uint32_t)addr);
-            return 0;
-        }
-    } else if (addr == clint->time_base) {
-        /* time_lo */
-        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
-    } else if (addr == clint->time_base + 4) {
-        /* time_hi */
-        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
-    }
-
-    error_report("clint: invalid read: %08x", (uint32_t)addr);
-    return 0;
-}
-
-/* CPU wrote to rtc or timecmp register */
-static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
-        unsigned size)
-{
-    SiFiveCLINTState *clint = opaque;
-
-    if (addr >= clint->sip_base &&
-        addr < clint->sip_base + (clint->num_harts << 2)) {
-        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x3) == 0) {
-            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
-        } else {
-            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
-        }
-        return;
-    } else if (addr >= clint->timecmp_base &&
-        addr < clint->timecmp_base + (clint->num_harts << 3)) {
-        size_t hartid = clint->hartid_base +
-            ((addr - clint->timecmp_base) >> 3);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x7) == 0) {
-            /* timecmp_lo */
-            uint64_t timecmp_hi = env->timecmp >> 32;
-            sifive_clint_write_timecmp(RISCV_CPU(cpu),
-                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
-            return;
-        } else if ((addr & 0x7) == 4) {
-            /* timecmp_hi */
-            uint64_t timecmp_lo = env->timecmp;
-            sifive_clint_write_timecmp(RISCV_CPU(cpu),
-                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
-        } else {
-            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
-        }
-        return;
-    } else if (addr == clint->time_base) {
-        /* time_lo */
-        error_report("clint: time_lo write not implemented");
-        return;
-    } else if (addr == clint->time_base + 4) {
-        /* time_hi */
-        error_report("clint: time_hi write not implemented");
-        return;
-    }
-
-    error_report("clint: invalid write: %08x", (uint32_t)addr);
-}
-
-static const MemoryRegionOps sifive_clint_ops = {
-    .read = sifive_clint_read,
-    .write = sifive_clint_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 8
-    }
-};
-
-static Property sifive_clint_properties[] = {
-    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
-    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
-    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
-    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
-    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
-    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
-    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sifive_clint_realize(DeviceState *dev, Error **errp)
-{
-    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
-    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
-                          TYPE_SIFIVE_CLINT, s->aperture_size);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
-}
-
-static void sifive_clint_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    dc->realize = sifive_clint_realize;
-    device_class_set_props(dc, sifive_clint_properties);
-}
-
-static const TypeInfo sifive_clint_info = {
-    .name          = TYPE_SIFIVE_CLINT,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveCLINTState),
-    .class_init    = sifive_clint_class_init,
-};
-
-static void sifive_clint_register_types(void)
-{
-    type_register_static(&sifive_clint_info);
-}
-
-type_init(sifive_clint_register_types)
-
-
-/*
- * Create CLINT device.
- */
-DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
-    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
-    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
-    bool provide_rdtime)
-{
-    int i;
-    for (i = 0; i < num_harts; i++) {
-        CPUState *cpu = qemu_get_cpu(hartid_base + i);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            continue;
-        }
-        if (provide_rdtime) {
-            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
-        }
-        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
-                                  &sifive_clint_timer_cb, cpu);
-        env->timecmp = 0;
-    }
-
-    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
-    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
-    qdev_prop_set_uint32(dev, "num-harts", num_harts);
-    qdev_prop_set_uint32(dev, "sip-base", sip_base);
-    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
-    qdev_prop_set_uint32(dev, "time-base", time_base);
-    qdev_prop_set_uint32(dev, "aperture-size", size);
-    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
-    return dev;
-}
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 1de18cdcf1..939cd0ef40 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
     select MCHP_PFSOC_MMUART
     select MCHP_PFSOC_SYSREG
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_PDMA
     select SIFIVE_PLIC
     select UNIMP
@@ -29,7 +29,7 @@ config RISCV_VIRT
     select PCI_EXPRESS_GENERIC_BRIDGE
     select PFLASH_CFI01
     select SERIAL
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_PLIC
     select SIFIVE_TEST
     select VIRTIO_MMIO
@@ -38,7 +38,7 @@ config RISCV_VIRT
 config SIFIVE_E
     bool
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_GPIO
     select SIFIVE_PLIC
     select SIFIVE_UART
@@ -49,7 +49,7 @@ config SIFIVE_U
     bool
     select CADENCE
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_GPIO
     select SIFIVE_PDMA
     select SIFIVE_PLIC
@@ -65,5 +65,5 @@ config SPIKE
     bool
     select HTIF
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_PLIC
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index c4146b7a6b..e637e5c885 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -51,7 +51,7 @@
 #include "hw/riscv/boot.h"
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/microchip_pfsoc.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "sysemu/sysemu.h"
 
@@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
         memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
 
     /* CLINT */
-    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
-        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-        CLINT_TIMEBASE_FREQ, false);
+    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
+        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
+    riscv_aclint_mtimer_create(
+        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
+        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
+        RISCV_ACLINT_TIMEBASE_FREQ, false);
 
     /* L2 cache controller */
     create_unimplemented_device("microchip.pfsoc.l2cc",
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index f939bcf9ea..ea960a5f2e 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -42,7 +42,7 @@
 #include "hw/riscv/sifive_e.h"
 #include "hw/riscv/boot.h"
 #include "hw/char/sifive_uart.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_e_prci.h"
 #include "chardev/char.h"
@@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
         SIFIVE_E_PLIC_CONTEXT_BASE,
         SIFIVE_E_PLIC_CONTEXT_STRIDE,
         memmap[SIFIVE_E_DEV_PLIC].size);
-    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
-        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-        SIFIVE_CLINT_TIMEBASE_FREQ, false);
+    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
+        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
+    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
+            RISCV_ACLINT_SWI_SIZE,
+        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
+        RISCV_ACLINT_TIMEBASE_FREQ, false);
     create_unimplemented_device("riscv.sifive.e.aon",
         memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
     sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 7b59942369..e5fe681984 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -52,7 +52,7 @@
 #include "hw/riscv/sifive_u.h"
 #include "hw/riscv/boot.h"
 #include "hw/char/sifive_uart.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "chardev/char.h"
 #include "net/eth.h"
@@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-        SIFIVE_CLINT_TIMEBASE_FREQ);
+        RISCV_ACLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
 
@@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
         serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
     sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
         serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
-    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
-        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-        SIFIVE_CLINT_TIMEBASE_FREQ, false);
+    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
+        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
+    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
+            RISCV_ACLINT_SWI_SIZE,
+        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
+        RISCV_ACLINT_TIMEBASE_FREQ, false);
 
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
         return;
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index ec7cb2f707..10681fbf99 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -36,7 +36,7 @@
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
 #include "hw/char/riscv_htif.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "chardev/char.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/device_tree.h"
@@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-        SIFIVE_CLINT_TIMEBASE_FREQ);
+        RISCV_ACLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
@@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
         sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
 
         /* Core Local Interruptor (timer and IPI) for each socket */
-        sifive_clint_create(
+        riscv_aclint_swi_create(
             memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
-            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
-            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-            SIFIVE_CLINT_TIMEBASE_FREQ, false);
+            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
+        riscv_aclint_mtimer_create(
+            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
+                RISCV_ACLINT_SWI_SIZE,
+            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
+            RISCV_ACLINT_TIMEBASE_FREQ, false);
     }
 
     /* register system main memory (actual RAM) */
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index c0dc69ff33..5eb63f6efd 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -33,7 +33,7 @@
 #include "hw/riscv/virt.h"
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_test.h"
 #include "chardev/char.h"
@@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-                          SIFIVE_CLINT_TIMEBASE_FREQ);
+                          RISCV_ACLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
@@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
         sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
 
         /* Per-socket CLINT */
-        sifive_clint_create(
+        riscv_aclint_swi_create(
             memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
-            memmap[VIRT_CLINT].size, base_hartid, hart_count,
-            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-            SIFIVE_CLINT_TIMEBASE_FREQ, true);
+            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
+        riscv_aclint_mtimer_create(
+            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
+                RISCV_ACLINT_SWI_SIZE,
+            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
+            RISCV_ACLINT_TIMEBASE_FREQ, true);
 
         /* Per-socket PLIC hart topology configuration string */
         plic_hart_config_len =
diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
new file mode 100644
index 0000000000..471a5ffd0b
--- /dev/null
+++ b/include/hw/intc/riscv_aclint.h
@@ -0,0 +1,73 @@
+/*
+ * RISC-V ACLINT (Advanced Core Local Interruptor) interface
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_RISCV_ACLINT_H
+#define HW_RISCV_ACLINT_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
+
+#define RISCV_ACLINT_MTIMER(obj) \
+    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
+
+typedef struct RISCVAclintMTimerState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    uint32_t hartid_base;
+    uint32_t num_harts;
+    uint32_t aperture_size;
+    uint32_t timebase_freq;
+} RISCVAclintMTimerState;
+
+DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
+    bool provide_rdtime);
+
+#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
+
+#define RISCV_ACLINT_SWI(obj) \
+    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
+
+typedef struct RISCVAclintSwiState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    uint32_t hartid_base;
+    uint32_t num_harts;
+    uint32_t aperture_size;
+    uint32_t sirq_mask;
+} RISCVAclintSwiState;
+
+DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
+
+enum {
+    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
+    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
+    RISCV_ACLINT_SWI_SIZE = 0x4000
+};
+
+#endif
diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
deleted file mode 100644
index a30be0f3d6..0000000000
--- a/include/hw/intc/sifive_clint.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SiFive CLINT (Core Local Interruptor) interface
- *
- * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef HW_SIFIVE_CLINT_H
-#define HW_SIFIVE_CLINT_H
-
-#include "hw/sysbus.h"
-
-#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
-
-#define SIFIVE_CLINT(obj) \
-    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
-
-typedef struct SiFiveCLINTState {
-    /*< private >*/
-    SysBusDevice parent_obj;
-
-    /*< public >*/
-    MemoryRegion mmio;
-    uint32_t hartid_base;
-    uint32_t num_harts;
-    uint32_t sip_base;
-    uint32_t timecmp_base;
-    uint32_t time_base;
-    uint32_t aperture_size;
-    uint32_t timebase_freq;
-} SiFiveCLINTState;
-
-DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
-    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
-    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
-    bool provide_rdtime);
-
-enum {
-    SIFIVE_SIP_BASE     = 0x0,
-    SIFIVE_TIMECMP_BASE = 0x4000,
-    SIFIVE_TIME_BASE    = 0xBFF8
-};
-
-enum {
-    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
-};
-
-#endif
-- 
2.25.1



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

* [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
@ 2021-06-12 16:06   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The RISC-V ACLINT is more modular and backward compatible with
original SiFive CLINT so instead of duplicating the orignal
SiFive CLINT implementation we upgrade the current SiFive CLINT
implementation to RISC-V ACLINT implementation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/intc/Kconfig                |   2 +-
 hw/intc/meson.build            |   2 +-
 hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
 hw/intc/sifive_clint.c         | 266 -----------------------
 hw/riscv/Kconfig               |  10 +-
 hw/riscv/microchip_pfsoc.c     |  12 +-
 hw/riscv/sifive_e.c            |  12 +-
 hw/riscv/sifive_u.c            |  14 +-
 hw/riscv/spike.c               |  15 +-
 hw/riscv/virt.c                |  15 +-
 include/hw/intc/riscv_aclint.h |  73 +++++++
 include/hw/intc/sifive_clint.h |  60 ------
 12 files changed, 494 insertions(+), 361 deletions(-)
 create mode 100644 hw/intc/riscv_aclint.c
 delete mode 100644 hw/intc/sifive_clint.c
 create mode 100644 include/hw/intc/riscv_aclint.h
 delete mode 100644 include/hw/intc/sifive_clint.h

diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index f4694088a4..78aed93c45 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -62,7 +62,7 @@ config RX_ICU
 config LOONGSON_LIOINTC
     bool
 
-config SIFIVE_CLINT
+config RISCV_ACLINT
     bool
 
 config SIFIVE_PLIC
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 1c299039f6..2482fcfaf8 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
 specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
 specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
 specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
-specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
+specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
 specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
 specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
 specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
new file mode 100644
index 0000000000..682f95cca7
--- /dev/null
+++ b/hw/intc/riscv_aclint.c
@@ -0,0 +1,374 @@
+/*
+ * RISC-V ACLINT (Advanced Core Local Interruptor)
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This provides real-time clock, timer and interprocessor interrupts.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/module.h"
+#include "hw/sysbus.h"
+#include "target/riscv/cpu.h"
+#include "hw/qdev-properties.h"
+#include "hw/intc/riscv_aclint.h"
+#include "qemu/timer.h"
+
+static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
+{
+    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+        timebase_freq, NANOSECONDS_PER_SECOND);
+}
+
+/*
+ * Called when timecmp is written to update the QEMU timer or immediately
+ * trigger timer interrupt if mtimecmp <= current timer value.
+ */
+static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
+    uint32_t timebase_freq)
+{
+    uint64_t next;
+    uint64_t diff;
+
+    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
+
+    cpu->env.timecmp = value;
+    if (cpu->env.timecmp <= rtc_r) {
+        /* if we're setting an MTIMECMP value in the "past",
+           immediately raise the timer interrupt */
+        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
+        return;
+    }
+
+    /* otherwise, set up the future timer interrupt */
+    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
+    diff = cpu->env.timecmp - rtc_r;
+    /* back to ns (note args switched in muldiv64) */
+    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
+    timer_mod(cpu->env.timer, next);
+}
+
+/*
+ * Callback used when the timer set using timer_mod expires.
+ * Should raise the timer interrupt line
+ */
+static void riscv_aclint_mtimer_cb(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
+}
+
+/* CPU wants to read MTIMER register */
+static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
+    unsigned size)
+{
+    RISCVAclintMTimerState *mtimer = opaque;
+
+    if (addr < (mtimer->num_harts << 3)) {
+        size_t hartid = mtimer->hartid_base + (addr >> 3);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x7) == 0) {
+            /* timecmp_lo */
+            uint64_t timecmp = env->timecmp;
+            return timecmp & 0xFFFFFFFF;
+        } else if ((addr & 0x7) == 4) {
+            /* timecmp_hi */
+            uint64_t timecmp = env->timecmp;
+            return (timecmp >> 32) & 0xFFFFFFFF;
+        } else {
+            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
+            return 0;
+        }
+    } else if (addr == (mtimer->aperture_size - 8)) {
+        /* time_lo */
+        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
+    } else if (addr == (mtimer->aperture_size - 4)) {
+        /* time_hi */
+        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
+    }
+
+    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
+    return 0;
+}
+
+/* CPU wrote MTIMER register */
+static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
+    uint64_t value, unsigned size)
+{
+    RISCVAclintMTimerState *mtimer = opaque;
+
+    if (addr < (mtimer->num_harts << 3)) {
+        size_t hartid = mtimer->hartid_base + (addr >> 3);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x7) == 0) {
+            /* timecmp_lo */
+            uint64_t timecmp_hi = env->timecmp >> 32;
+            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
+                timecmp_hi << 32 | (value & 0xFFFFFFFF),
+                mtimer->timebase_freq);
+            return;
+        } else if ((addr & 0x7) == 4) {
+            /* timecmp_hi */
+            uint64_t timecmp_lo = env->timecmp;
+            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
+                value << 32 | (timecmp_lo & 0xFFFFFFFF),
+                mtimer->timebase_freq);
+        } else {
+            error_report("aclint-mtimer: invalid timecmp write: %08x",
+                         (uint32_t)addr);
+        }
+        return;
+    } else if (addr == (mtimer->aperture_size - 8)) {
+        /* time_lo */
+        error_report("aclint-mtimer: time_lo write not implemented");
+        return;
+    } else if (addr == (mtimer->aperture_size - 4)) {
+        /* time_hi */
+        error_report("aclint-mtimer: time_hi write not implemented");
+        return;
+    }
+
+    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
+}
+
+static const MemoryRegionOps riscv_aclint_mtimer_ops = {
+    .read = riscv_aclint_mtimer_read,
+    .write = riscv_aclint_mtimer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 8
+    }
+};
+
+static Property riscv_aclint_mtimer_properties[] = {
+    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
+        hartid_base, 0),
+    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
+    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
+        aperture_size, 0),
+    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
+        timebase_freq, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    RISCVCPU *cpu;
+    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
+                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+
+    /* Claim MTIP so that only MTIMER controls it. */
+    for (i = 0; i < s->num_harts; i++) {
+        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
+        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
+            error_report("MTIP already claimed");
+            exit(1);
+        }
+    }
+}
+
+static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = riscv_aclint_mtimer_realize;
+    device_class_set_props(dc, riscv_aclint_mtimer_properties);
+}
+
+static const TypeInfo riscv_aclint_mtimer_info = {
+    .name          = TYPE_RISCV_ACLINT_MTIMER,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RISCVAclintMTimerState),
+    .class_init    = riscv_aclint_mtimer_class_init,
+};
+
+/*
+ * Create ACLINT MTIMER device.
+ */
+DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
+    bool provide_rdtime)
+{
+    int i;
+    for (i = 0; i < num_harts; i++) {
+        CPUState *cpu = qemu_get_cpu(hartid_base + i);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            continue;
+        }
+        if (provide_rdtime) {
+            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
+        }
+        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                  &riscv_aclint_mtimer_cb, cpu);
+        env->timecmp = 0;
+    }
+
+    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
+    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
+    qdev_prop_set_uint32(dev, "num-harts", num_harts);
+    qdev_prop_set_uint32(dev, "aperture-size", size);
+    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
+    return dev;
+}
+
+/* CPU read [M|S]SWI register */
+static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
+    unsigned size)
+{
+    RISCVAclintSwiState *swi = opaque;
+
+    if (addr < (swi->num_harts << 2)) {
+        size_t hartid = swi->hartid_base + (addr >> 2);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-swi: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x3) == 0) {
+            return (env->mip & swi->sirq_mask) > 0;
+        } else {
+            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
+            return 0;
+        }
+    }
+
+    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
+    return 0;
+}
+
+/* CPU wrote [M|S]SWI register */
+static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
+        unsigned size)
+{
+    RISCVAclintSwiState *swi = opaque;
+
+    if (addr < (swi->num_harts << 2)) {
+        size_t hartid = swi->hartid_base + (addr >> 2);
+        CPUState *cpu = qemu_get_cpu(hartid);
+        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        if (!env) {
+            error_report("aclint-swi: invalid hartid: %zu", hartid);
+        } else if ((addr & 0x3) == 0) {
+            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
+                                 BOOL_TO_MASK(value));
+        } else {
+            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
+                         (uint32_t)addr);
+        }
+        return;
+    }
+
+    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
+}
+
+static const MemoryRegionOps riscv_aclint_swi_ops = {
+    .read = riscv_aclint_swi_read,
+    .write = riscv_aclint_swi_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static Property riscv_aclint_swi_properties[] = {
+    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
+    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
+    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
+        aperture_size, 0),
+    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    RISCVCPU *cpu;
+    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
+                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
+
+    /* Claim [M|S]SIP so that can SWI controls it. */
+    for (i = 0; i < s->num_harts; i++) {
+        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
+
+        /* We don't claim SSIP bit of mip CSR because this bit is
+         * writable by software as-per RISC-V privilege specification.
+         */
+        if ((s->sirq_mask != MIP_SSIP) &&
+            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
+            error_report("%s already claimed",
+                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
+            exit(1);
+        }
+    }
+}
+
+static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = riscv_aclint_swi_realize;
+    device_class_set_props(dc, riscv_aclint_swi_properties);
+}
+
+static const TypeInfo riscv_aclint_swi_info = {
+    .name          = TYPE_RISCV_ACLINT_SWI,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RISCVAclintSwiState),
+    .class_init    = riscv_aclint_swi_class_init,
+};
+
+/*
+ * Create ACLINT [M|S]SWI device.
+ */
+DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
+{
+    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
+    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
+    qdev_prop_set_uint32(dev, "num-harts", num_harts);
+    qdev_prop_set_uint32(dev, "aperture-size", size);
+    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
+    return dev;
+}
+
+static void riscv_aclint_register_types(void)
+{
+    type_register_static(&riscv_aclint_mtimer_info);
+    type_register_static(&riscv_aclint_swi_info);
+}
+
+type_init(riscv_aclint_register_types)
diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
deleted file mode 100644
index 0f41e5ea1c..0000000000
--- a/hw/intc/sifive_clint.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * SiFive CLINT (Core Local Interruptor)
- *
- * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This provides real-time clock, timer and interprocessor interrupts.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "hw/sysbus.h"
-#include "target/riscv/cpu.h"
-#include "hw/qdev-properties.h"
-#include "hw/intc/sifive_clint.h"
-#include "qemu/timer.h"
-
-static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
-{
-    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
-        timebase_freq, NANOSECONDS_PER_SECOND);
-}
-
-/*
- * Called when timecmp is written to update the QEMU timer or immediately
- * trigger timer interrupt if mtimecmp <= current timer value.
- */
-static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
-                                       uint32_t timebase_freq)
-{
-    uint64_t next;
-    uint64_t diff;
-
-    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
-
-    cpu->env.timecmp = value;
-    if (cpu->env.timecmp <= rtc_r) {
-        /* if we're setting an MTIMECMP value in the "past",
-           immediately raise the timer interrupt */
-        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
-        return;
-    }
-
-    /* otherwise, set up the future timer interrupt */
-    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
-    diff = cpu->env.timecmp - rtc_r;
-    /* back to ns (note args switched in muldiv64) */
-    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
-        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
-    timer_mod(cpu->env.timer, next);
-}
-
-/*
- * Callback used when the timer set using timer_mod expires.
- * Should raise the timer interrupt line
- */
-static void sifive_clint_timer_cb(void *opaque)
-{
-    RISCVCPU *cpu = opaque;
-    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
-}
-
-/* CPU wants to read rtc or timecmp register */
-static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
-{
-    SiFiveCLINTState *clint = opaque;
-    if (addr >= clint->sip_base &&
-        addr < clint->sip_base + (clint->num_harts << 2)) {
-        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x3) == 0) {
-            return (env->mip & MIP_MSIP) > 0;
-        } else {
-            error_report("clint: invalid read: %08x", (uint32_t)addr);
-            return 0;
-        }
-    } else if (addr >= clint->timecmp_base &&
-        addr < clint->timecmp_base + (clint->num_harts << 3)) {
-        size_t hartid = clint->hartid_base +
-            ((addr - clint->timecmp_base) >> 3);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x7) == 0) {
-            /* timecmp_lo */
-            uint64_t timecmp = env->timecmp;
-            return timecmp & 0xFFFFFFFF;
-        } else if ((addr & 0x7) == 4) {
-            /* timecmp_hi */
-            uint64_t timecmp = env->timecmp;
-            return (timecmp >> 32) & 0xFFFFFFFF;
-        } else {
-            error_report("clint: invalid read: %08x", (uint32_t)addr);
-            return 0;
-        }
-    } else if (addr == clint->time_base) {
-        /* time_lo */
-        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
-    } else if (addr == clint->time_base + 4) {
-        /* time_hi */
-        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
-    }
-
-    error_report("clint: invalid read: %08x", (uint32_t)addr);
-    return 0;
-}
-
-/* CPU wrote to rtc or timecmp register */
-static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
-        unsigned size)
-{
-    SiFiveCLINTState *clint = opaque;
-
-    if (addr >= clint->sip_base &&
-        addr < clint->sip_base + (clint->num_harts << 2)) {
-        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x3) == 0) {
-            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
-        } else {
-            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
-        }
-        return;
-    } else if (addr >= clint->timecmp_base &&
-        addr < clint->timecmp_base + (clint->num_harts << 3)) {
-        size_t hartid = clint->hartid_base +
-            ((addr - clint->timecmp_base) >> 3);
-        CPUState *cpu = qemu_get_cpu(hartid);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            error_report("clint: invalid timecmp hartid: %zu", hartid);
-        } else if ((addr & 0x7) == 0) {
-            /* timecmp_lo */
-            uint64_t timecmp_hi = env->timecmp >> 32;
-            sifive_clint_write_timecmp(RISCV_CPU(cpu),
-                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
-            return;
-        } else if ((addr & 0x7) == 4) {
-            /* timecmp_hi */
-            uint64_t timecmp_lo = env->timecmp;
-            sifive_clint_write_timecmp(RISCV_CPU(cpu),
-                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
-        } else {
-            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
-        }
-        return;
-    } else if (addr == clint->time_base) {
-        /* time_lo */
-        error_report("clint: time_lo write not implemented");
-        return;
-    } else if (addr == clint->time_base + 4) {
-        /* time_hi */
-        error_report("clint: time_hi write not implemented");
-        return;
-    }
-
-    error_report("clint: invalid write: %08x", (uint32_t)addr);
-}
-
-static const MemoryRegionOps sifive_clint_ops = {
-    .read = sifive_clint_read,
-    .write = sifive_clint_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 8
-    }
-};
-
-static Property sifive_clint_properties[] = {
-    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
-    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
-    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
-    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
-    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
-    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
-    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sifive_clint_realize(DeviceState *dev, Error **errp)
-{
-    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
-    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
-                          TYPE_SIFIVE_CLINT, s->aperture_size);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
-}
-
-static void sifive_clint_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    dc->realize = sifive_clint_realize;
-    device_class_set_props(dc, sifive_clint_properties);
-}
-
-static const TypeInfo sifive_clint_info = {
-    .name          = TYPE_SIFIVE_CLINT,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SiFiveCLINTState),
-    .class_init    = sifive_clint_class_init,
-};
-
-static void sifive_clint_register_types(void)
-{
-    type_register_static(&sifive_clint_info);
-}
-
-type_init(sifive_clint_register_types)
-
-
-/*
- * Create CLINT device.
- */
-DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
-    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
-    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
-    bool provide_rdtime)
-{
-    int i;
-    for (i = 0; i < num_harts; i++) {
-        CPUState *cpu = qemu_get_cpu(hartid_base + i);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
-        if (!env) {
-            continue;
-        }
-        if (provide_rdtime) {
-            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
-        }
-        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
-                                  &sifive_clint_timer_cb, cpu);
-        env->timecmp = 0;
-    }
-
-    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
-    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
-    qdev_prop_set_uint32(dev, "num-harts", num_harts);
-    qdev_prop_set_uint32(dev, "sip-base", sip_base);
-    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
-    qdev_prop_set_uint32(dev, "time-base", time_base);
-    qdev_prop_set_uint32(dev, "aperture-size", size);
-    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
-    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
-    return dev;
-}
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 1de18cdcf1..939cd0ef40 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
     select MCHP_PFSOC_MMUART
     select MCHP_PFSOC_SYSREG
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_PDMA
     select SIFIVE_PLIC
     select UNIMP
@@ -29,7 +29,7 @@ config RISCV_VIRT
     select PCI_EXPRESS_GENERIC_BRIDGE
     select PFLASH_CFI01
     select SERIAL
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_PLIC
     select SIFIVE_TEST
     select VIRTIO_MMIO
@@ -38,7 +38,7 @@ config RISCV_VIRT
 config SIFIVE_E
     bool
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_GPIO
     select SIFIVE_PLIC
     select SIFIVE_UART
@@ -49,7 +49,7 @@ config SIFIVE_U
     bool
     select CADENCE
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_GPIO
     select SIFIVE_PDMA
     select SIFIVE_PLIC
@@ -65,5 +65,5 @@ config SPIKE
     bool
     select HTIF
     select MSI_NONBROKEN
-    select SIFIVE_CLINT
+    select RISCV_ACLINT
     select SIFIVE_PLIC
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index c4146b7a6b..e637e5c885 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -51,7 +51,7 @@
 #include "hw/riscv/boot.h"
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/microchip_pfsoc.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "sysemu/sysemu.h"
 
@@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
         memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
 
     /* CLINT */
-    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
-        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-        CLINT_TIMEBASE_FREQ, false);
+    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
+        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
+    riscv_aclint_mtimer_create(
+        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
+        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
+        RISCV_ACLINT_TIMEBASE_FREQ, false);
 
     /* L2 cache controller */
     create_unimplemented_device("microchip.pfsoc.l2cc",
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index f939bcf9ea..ea960a5f2e 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -42,7 +42,7 @@
 #include "hw/riscv/sifive_e.h"
 #include "hw/riscv/boot.h"
 #include "hw/char/sifive_uart.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_e_prci.h"
 #include "chardev/char.h"
@@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
         SIFIVE_E_PLIC_CONTEXT_BASE,
         SIFIVE_E_PLIC_CONTEXT_STRIDE,
         memmap[SIFIVE_E_DEV_PLIC].size);
-    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
-        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-        SIFIVE_CLINT_TIMEBASE_FREQ, false);
+    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
+        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
+    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
+            RISCV_ACLINT_SWI_SIZE,
+        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
+        RISCV_ACLINT_TIMEBASE_FREQ, false);
     create_unimplemented_device("riscv.sifive.e.aon",
         memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
     sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 7b59942369..e5fe681984 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -52,7 +52,7 @@
 #include "hw/riscv/sifive_u.h"
 #include "hw/riscv/boot.h"
 #include "hw/char/sifive_uart.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "chardev/char.h"
 #include "net/eth.h"
@@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-        SIFIVE_CLINT_TIMEBASE_FREQ);
+        RISCV_ACLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
 
@@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
         serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
     sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
         serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
-    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
-        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
-        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-        SIFIVE_CLINT_TIMEBASE_FREQ, false);
+    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
+        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
+    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
+            RISCV_ACLINT_SWI_SIZE,
+        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
+        RISCV_ACLINT_TIMEBASE_FREQ, false);
 
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
         return;
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index ec7cb2f707..10681fbf99 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -36,7 +36,7 @@
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
 #include "hw/char/riscv_htif.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "chardev/char.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/device_tree.h"
@@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-        SIFIVE_CLINT_TIMEBASE_FREQ);
+        RISCV_ACLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
@@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
         sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
 
         /* Core Local Interruptor (timer and IPI) for each socket */
-        sifive_clint_create(
+        riscv_aclint_swi_create(
             memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
-            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
-            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-            SIFIVE_CLINT_TIMEBASE_FREQ, false);
+            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
+        riscv_aclint_mtimer_create(
+            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
+                RISCV_ACLINT_SWI_SIZE,
+            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
+            RISCV_ACLINT_TIMEBASE_FREQ, false);
     }
 
     /* register system main memory (actual RAM) */
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index c0dc69ff33..5eb63f6efd 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -33,7 +33,7 @@
 #include "hw/riscv/virt.h"
 #include "hw/riscv/boot.h"
 #include "hw/riscv/numa.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
 #include "hw/intc/sifive_plic.h"
 #include "hw/misc/sifive_test.h"
 #include "chardev/char.h"
@@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
 
     qemu_fdt_add_subnode(fdt, "/cpus");
     qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
-                          SIFIVE_CLINT_TIMEBASE_FREQ);
+                          RISCV_ACLINT_TIMEBASE_FREQ);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
     qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
@@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
         sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
 
         /* Per-socket CLINT */
-        sifive_clint_create(
+        riscv_aclint_swi_create(
             memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
-            memmap[VIRT_CLINT].size, base_hartid, hart_count,
-            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
-            SIFIVE_CLINT_TIMEBASE_FREQ, true);
+            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
+        riscv_aclint_mtimer_create(
+            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
+                RISCV_ACLINT_SWI_SIZE,
+            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
+            RISCV_ACLINT_TIMEBASE_FREQ, true);
 
         /* Per-socket PLIC hart topology configuration string */
         plic_hart_config_len =
diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
new file mode 100644
index 0000000000..471a5ffd0b
--- /dev/null
+++ b/include/hw/intc/riscv_aclint.h
@@ -0,0 +1,73 @@
+/*
+ * RISC-V ACLINT (Advanced Core Local Interruptor) interface
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017 SiFive, Inc.
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_RISCV_ACLINT_H
+#define HW_RISCV_ACLINT_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
+
+#define RISCV_ACLINT_MTIMER(obj) \
+    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
+
+typedef struct RISCVAclintMTimerState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    uint32_t hartid_base;
+    uint32_t num_harts;
+    uint32_t aperture_size;
+    uint32_t timebase_freq;
+} RISCVAclintMTimerState;
+
+DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
+    bool provide_rdtime);
+
+#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
+
+#define RISCV_ACLINT_SWI(obj) \
+    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
+
+typedef struct RISCVAclintSwiState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    uint32_t hartid_base;
+    uint32_t num_harts;
+    uint32_t aperture_size;
+    uint32_t sirq_mask;
+} RISCVAclintSwiState;
+
+DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
+    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
+
+enum {
+    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
+    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
+    RISCV_ACLINT_SWI_SIZE = 0x4000
+};
+
+#endif
diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
deleted file mode 100644
index a30be0f3d6..0000000000
--- a/include/hw/intc/sifive_clint.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SiFive CLINT (Core Local Interruptor) interface
- *
- * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
- * Copyright (c) 2017 SiFive, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2 or later, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef HW_SIFIVE_CLINT_H
-#define HW_SIFIVE_CLINT_H
-
-#include "hw/sysbus.h"
-
-#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
-
-#define SIFIVE_CLINT(obj) \
-    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
-
-typedef struct SiFiveCLINTState {
-    /*< private >*/
-    SysBusDevice parent_obj;
-
-    /*< public >*/
-    MemoryRegion mmio;
-    uint32_t hartid_base;
-    uint32_t num_harts;
-    uint32_t sip_base;
-    uint32_t timecmp_base;
-    uint32_t time_base;
-    uint32_t aperture_size;
-    uint32_t timebase_freq;
-} SiFiveCLINTState;
-
-DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
-    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
-    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
-    bool provide_rdtime);
-
-enum {
-    SIFIVE_SIP_BASE     = 0x0,
-    SIFIVE_TIMECMP_BASE = 0x4000,
-    SIFIVE_TIME_BASE    = 0xBFF8
-};
-
-enum {
-    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
-};
-
-#endif
-- 
2.25.1



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

* [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation
  2021-06-12 16:06 ` Anup Patel
@ 2021-06-12 16:06   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We re-factor and break the FDT generation into smaller functions
so that it is easier to modify FDT generation for different
configurations of virt machine.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/riscv/virt.c | 514 ++++++++++++++++++++++++++++++------------------
 1 file changed, 320 insertions(+), 194 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 5eb63f6efd..977d699753 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -178,206 +178,253 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
                            0x1800, 0, 0, 0x7);
 }
 
-static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
-                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
+static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
+                                   char *clust_name, uint32_t *phandle,
+                                   bool is_32_bit, uint32_t *intc_phandles)
 {
-    void *fdt;
-    int i, cpu, socket;
+    int cpu;
+    uint32_t cpu_phandle;
     MachineState *mc = MACHINE(s);
+    char *name, *cpu_name, *core_name, *intc_name;
+
+    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
+        cpu_phandle = (*phandle)++;
+
+        cpu_name = g_strdup_printf("/cpus/cpu@%d",
+            s->soc[socket].hartid_base + cpu);
+        qemu_fdt_add_subnode(mc->fdt, cpu_name);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type",
+            (is_32_bit) ? "riscv,sv32" : "riscv,sv48");
+        name = riscv_isa_string(&s->soc[socket].harts[cpu]);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name);
+        g_free(name);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv");
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay");
+        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg",
+            s->soc[socket].hartid_base + cpu);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu");
+        riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket);
+        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle);
+
+        intc_phandles[cpu] = (*phandle)++;
+
+        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
+        qemu_fdt_add_subnode(mc->fdt, intc_name);
+        qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
+            intc_phandles[cpu]);
+        qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
+            "riscv,cpu-intc");
+        qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
+        qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
+
+        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
+        qemu_fdt_add_subnode(mc->fdt, core_name);
+        qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle);
+
+        g_free(core_name);
+        g_free(intc_name);
+        g_free(cpu_name);
+    }
+}
+
+static void create_fdt_socket_memory(RISCVVirtState *s,
+                                     const MemMapEntry *memmap, int socket)
+{
+    char *mem_name;
     uint64_t addr, size;
-    uint32_t *clint_cells, *plic_cells;
-    unsigned long clint_addr, plic_addr;
-    uint32_t plic_phandle[MAX_NODES];
-    uint32_t cpu_phandle, intc_phandle, test_phandle;
-    uint32_t phandle = 1, plic_mmio_phandle = 1;
-    uint32_t plic_pcie_phandle = 1, plic_virtio_phandle = 1;
-    char *mem_name, *cpu_name, *core_name, *intc_name;
-    char *name, *clint_name, *plic_name, *clust_name;
-    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
-    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
+    MachineState *mc = MACHINE(s);
 
-    if (mc->dtb) {
-        fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
-        if (!fdt) {
-            error_report("load_device_tree() failed");
-            exit(1);
-        }
-        goto update_bootargs;
-    } else {
-        fdt = mc->fdt = create_device_tree(&s->fdt_size);
-        if (!fdt) {
-            error_report("create_device_tree() failed");
-            exit(1);
-        }
+    addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
+    size = riscv_socket_mem_size(mc, socket);
+    mem_name = g_strdup_printf("/memory@%lx", (long)addr);
+    qemu_fdt_add_subnode(mc->fdt, mem_name);
+    qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg",
+        addr >> 32, addr, size >> 32, size);
+    qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory");
+    riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket);
+    g_free(mem_name);
+}
+
+static void create_fdt_socket_clint(RISCVVirtState *s,
+                                    const MemMapEntry *memmap, int socket,
+                                    uint32_t *intc_phandles)
+{
+    int cpu;
+    char *clint_name;
+    uint32_t *clint_cells;
+    unsigned long clint_addr;
+    MachineState *mc = MACHINE(s);
+
+    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
+
+    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
+        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
     }
 
-    qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
-    qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
-    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+    clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
+    clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
+    qemu_fdt_add_subnode(mc->fdt, clint_name);
+    qemu_fdt_setprop_string(mc->fdt, clint_name, "compatible",
+        "riscv,clint0");
+    qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg",
+        0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
+    qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended",
+        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
+    riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket);
+    g_free(clint_name);
+
+    g_free(clint_cells);
+}
+
+static void create_fdt_socket_plic(RISCVVirtState *s,
+                                   const MemMapEntry *memmap, int socket,
+                                   uint32_t *phandle, uint32_t *intc_phandles,
+                                   uint32_t *plic_phandles)
+{
+    int cpu;
+    char *plic_name;
+    uint32_t *plic_cells;
+    unsigned long plic_addr;
+    MachineState *mc = MACHINE(s);
 
-    qemu_fdt_add_subnode(fdt, "/soc");
-    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
-    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
-    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+    plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
 
-    qemu_fdt_add_subnode(fdt, "/cpus");
-    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
+    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+        plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
+        plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+        plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
+    }
+
+    plic_phandles[socket] = (*phandle)++;
+    plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
+    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
+    qemu_fdt_add_subnode(mc->fdt, plic_name);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name,
+        "#address-cells", FDT_PLIC_ADDR_CELLS);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name,
+        "#interrupt-cells", FDT_PLIC_INT_CELLS);
+    qemu_fdt_setprop_string(mc->fdt, plic_name, "compatible", "riscv,plic0");
+    qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended",
+        plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
+    qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
+        0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
+    riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
+        plic_phandles[socket]);
+    g_free(plic_name);
+
+    g_free(plic_cells);
+}
+
+static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
+                               bool is_32_bit, uint32_t *phandle,
+                               uint32_t *irq_mmio_phandle,
+                               uint32_t *irq_pcie_phandle,
+                               uint32_t *irq_virtio_phandle)
+{
+    int socket;
+    char *clust_name;
+    uint32_t *intc_phandles;
+    MachineState *mc = MACHINE(s);
+    uint32_t xplic_phandles[MAX_NODES];
+
+    qemu_fdt_add_subnode(mc->fdt, "/cpus");
+    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency",
                           RISCV_ACLINT_TIMEBASE_FREQ);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
-    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0);
+    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map");
 
     for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) {
         clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
-        qemu_fdt_add_subnode(fdt, clust_name);
+        qemu_fdt_add_subnode(mc->fdt, clust_name);
 
-        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
-        clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
+        intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts);
 
-        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
-            cpu_phandle = phandle++;
+        create_fdt_socket_cpus(s, socket, clust_name, phandle,
+            is_32_bit, intc_phandles);
 
-            cpu_name = g_strdup_printf("/cpus/cpu@%d",
-                s->soc[socket].hartid_base + cpu);
-            qemu_fdt_add_subnode(fdt, cpu_name);
-            if (is_32_bit) {
-                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
-            } else {
-                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
-            }
-            name = riscv_isa_string(&s->soc[socket].harts[cpu]);
-            qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
-            g_free(name);
-            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
-            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
-            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
-                s->soc[socket].hartid_base + cpu);
-            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
-            riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket);
-            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
-
-            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
-            qemu_fdt_add_subnode(fdt, intc_name);
-            intc_phandle = phandle++;
-            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
-            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
-                "riscv,cpu-intc");
-            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
-            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
-
-            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
-            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
-            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-
-            plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
-            plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
-            plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
-            plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
-
-            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
-            qemu_fdt_add_subnode(fdt, core_name);
-            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
-
-            g_free(core_name);
-            g_free(intc_name);
-            g_free(cpu_name);
-        }
+        create_fdt_socket_memory(s, memmap, socket);
 
-        addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
-        size = riscv_socket_mem_size(mc, socket);
-        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
-        qemu_fdt_add_subnode(fdt, mem_name);
-        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
-            addr >> 32, addr, size >> 32, size);
-        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
-        riscv_socket_fdt_write_id(mc, fdt, mem_name, socket);
-        g_free(mem_name);
-
-        clint_addr = memmap[VIRT_CLINT].base +
-            (memmap[VIRT_CLINT].size * socket);
-        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
-        qemu_fdt_add_subnode(fdt, clint_name);
-        qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
-        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
-            0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
-        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
-            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
-        riscv_socket_fdt_write_id(mc, fdt, clint_name, socket);
-        g_free(clint_name);
-
-        plic_phandle[socket] = phandle++;
-        plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
-        plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
-        qemu_fdt_add_subnode(fdt, plic_name);
-        qemu_fdt_setprop_cell(fdt, plic_name,
-            "#address-cells", FDT_PLIC_ADDR_CELLS);
-        qemu_fdt_setprop_cell(fdt, plic_name,
-            "#interrupt-cells", FDT_PLIC_INT_CELLS);
-        qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
-        qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
-        qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
-            plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
-        qemu_fdt_setprop_cells(fdt, plic_name, "reg",
-            0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
-        qemu_fdt_setprop_cell(fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
-        riscv_socket_fdt_write_id(mc, fdt, plic_name, socket);
-        qemu_fdt_setprop_cell(fdt, plic_name, "phandle", plic_phandle[socket]);
-        g_free(plic_name);
-
-        g_free(clint_cells);
-        g_free(plic_cells);
+        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
+
+        create_fdt_socket_plic(s, memmap, socket, phandle,
+            intc_phandles, xplic_phandles);
+
+        g_free(intc_phandles);
         g_free(clust_name);
     }
 
     for (socket = 0; socket < riscv_socket_count(mc); socket++) {
         if (socket == 0) {
-            plic_mmio_phandle = plic_phandle[socket];
-            plic_virtio_phandle = plic_phandle[socket];
-            plic_pcie_phandle = plic_phandle[socket];
+            *irq_mmio_phandle = xplic_phandles[socket];
+            *irq_virtio_phandle = xplic_phandles[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
         }
         if (socket == 1) {
-            plic_virtio_phandle = plic_phandle[socket];
-            plic_pcie_phandle = plic_phandle[socket];
+            *irq_virtio_phandle = xplic_phandles[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
         }
         if (socket == 2) {
-            plic_pcie_phandle = plic_phandle[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
         }
     }
 
-    riscv_socket_fdt_write_distance_matrix(mc, fdt);
+    riscv_socket_fdt_write_distance_matrix(mc, mc->fdt);
+}
+
+static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
+                              uint32_t irq_virtio_phandle)
+{
+    int i;
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     for (i = 0; i < VIRTIO_COUNT; i++) {
         name = g_strdup_printf("/soc/virtio_mmio@%lx",
             (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
-        qemu_fdt_add_subnode(fdt, name);
-        qemu_fdt_setprop_string(fdt, name, "compatible", "virtio,mmio");
-        qemu_fdt_setprop_cells(fdt, name, "reg",
+        qemu_fdt_add_subnode(mc->fdt, name);
+        qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio");
+        qemu_fdt_setprop_cells(mc->fdt, name, "reg",
             0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
             0x0, memmap[VIRT_VIRTIO].size);
-        qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
-            plic_virtio_phandle);
-        qemu_fdt_setprop_cell(fdt, name, "interrupts", VIRTIO_IRQ + i);
+        qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
+            irq_virtio_phandle);
+        qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i);
         g_free(name);
     }
+}
+
+static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
+                            uint32_t irq_pcie_phandle)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     name = g_strdup_printf("/soc/pci@%lx",
         (long) memmap[VIRT_PCIE_ECAM].base);
-    qemu_fdt_add_subnode(fdt, name);
-    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,
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells",
+        FDT_PCI_ADDR_CELLS);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells",
+        FDT_PCI_INT_CELLS);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
+        "pci-host-ecam-generic");
+    qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci");
+    qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0);
+    qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0,
         memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
-    qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
-    qemu_fdt_setprop_cells(fdt, name, "reg", 0,
+    qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0);
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0,
         memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
-    qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
+    qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges",
         1, FDT_PCI_RANGE_IOPORT, 2, 0,
         2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
         1, FDT_PCI_RANGE_MMIO,
@@ -387,63 +434,93 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
         2, virt_high_pcie_memmap.base,
         2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
 
-    create_pcie_irq_map(fdt, name, plic_pcie_phandle);
+    create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle);
     g_free(name);
+}
+
+static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
+                             uint32_t *phandle)
+{
+    char *name;
+    uint32_t test_phandle;
+    MachineState *mc = MACHINE(s);
 
-    test_phandle = phandle++;
+    test_phandle = (*phandle)++;
     name = g_strdup_printf("/soc/test@%lx",
         (long)memmap[VIRT_TEST].base);
-    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_add_subnode(mc->fdt, name);
     {
         const char compat[] = "sifive,test1\0sifive,test0\0syscon";
-        qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
+        qemu_fdt_setprop(mc->fdt, name, "compatible", compat, sizeof(compat));
     }
-    qemu_fdt_setprop_cells(fdt, name, "reg",
-        0x0, memmap[VIRT_TEST].base,
-        0x0, memmap[VIRT_TEST].size);
-    qemu_fdt_setprop_cell(fdt, name, "phandle", test_phandle);
-    test_phandle = qemu_fdt_get_phandle(fdt, name);
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
+    qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle);
+    test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
     g_free(name);
 
     name = g_strdup_printf("/soc/reboot");
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
-    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
-    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_RESET);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
+    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
     g_free(name);
 
     name = g_strdup_printf("/soc/poweroff");
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
-    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
-    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_PASS);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
+    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS);
     g_free(name);
+}
+
+static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
+                            uint32_t irq_mmio_phandle)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
-    qemu_fdt_setprop_cells(fdt, name, "reg",
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
         0x0, memmap[VIRT_UART0].base,
         0x0, memmap[VIRT_UART0].size);
-    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
-    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "interrupts", UART0_IRQ);
+    qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
 
-    qemu_fdt_add_subnode(fdt, "/chosen");
-    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
+    qemu_fdt_add_subnode(mc->fdt, "/chosen");
+    qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
     g_free(name);
+}
+
+static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
+                           uint32_t irq_mmio_phandle)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
-    qemu_fdt_setprop_cells(fdt, name, "reg",
-        0x0, memmap[VIRT_RTC].base,
-        0x0, memmap[VIRT_RTC].size);
-    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
+        "google,goldfish-rtc");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
+        irq_mmio_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
     g_free(name);
+}
+
+static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
+    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
+    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
 
     name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
     qemu_fdt_add_subnode(mc->fdt, name);
@@ -453,10 +530,59 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
                                  2, flashbase + flashsize, 2, flashsize);
     qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
     g_free(name);
+}
+
+static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
+                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
+{
+    MachineState *mc = MACHINE(s);
+    uint32_t phandle = 1, irq_mmio_phandle = 1;
+    uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
+
+    if (mc->dtb) {
+        mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
+        if (!mc->fdt) {
+            error_report("load_device_tree() failed");
+            exit(1);
+        }
+        goto update_bootargs;
+    } else {
+        mc->fdt = create_device_tree(&s->fdt_size);
+        if (!mc->fdt) {
+            error_report("create_device_tree() failed");
+            exit(1);
+        }
+    }
+
+    qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu");
+    qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio");
+    qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2);
+
+    qemu_fdt_add_subnode(mc->fdt, "/soc");
+    qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0);
+    qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus");
+    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2);
+
+    create_fdt_sockets(s, memmap, is_32_bit, &phandle,
+        &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle);
+
+    create_fdt_virtio(s, memmap, irq_virtio_phandle);
+
+    create_fdt_pcie(s, memmap, irq_pcie_phandle);
+
+    create_fdt_reset(s, memmap, &phandle);
+
+    create_fdt_uart(s, memmap, irq_mmio_phandle);
+
+    create_fdt_rtc(s, memmap, irq_mmio_phandle);
+
+    create_fdt_flash(s, memmap);
 
 update_bootargs:
     if (cmdline) {
-        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+        qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
     }
 }
 
-- 
2.25.1



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

* [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation
@ 2021-06-12 16:06   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We re-factor and break the FDT generation into smaller functions
so that it is easier to modify FDT generation for different
configurations of virt machine.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/riscv/virt.c | 514 ++++++++++++++++++++++++++++++------------------
 1 file changed, 320 insertions(+), 194 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 5eb63f6efd..977d699753 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -178,206 +178,253 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
                            0x1800, 0, 0, 0x7);
 }
 
-static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
-                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
+static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
+                                   char *clust_name, uint32_t *phandle,
+                                   bool is_32_bit, uint32_t *intc_phandles)
 {
-    void *fdt;
-    int i, cpu, socket;
+    int cpu;
+    uint32_t cpu_phandle;
     MachineState *mc = MACHINE(s);
+    char *name, *cpu_name, *core_name, *intc_name;
+
+    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
+        cpu_phandle = (*phandle)++;
+
+        cpu_name = g_strdup_printf("/cpus/cpu@%d",
+            s->soc[socket].hartid_base + cpu);
+        qemu_fdt_add_subnode(mc->fdt, cpu_name);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type",
+            (is_32_bit) ? "riscv,sv32" : "riscv,sv48");
+        name = riscv_isa_string(&s->soc[socket].harts[cpu]);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name);
+        g_free(name);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv");
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay");
+        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg",
+            s->soc[socket].hartid_base + cpu);
+        qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu");
+        riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket);
+        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle);
+
+        intc_phandles[cpu] = (*phandle)++;
+
+        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
+        qemu_fdt_add_subnode(mc->fdt, intc_name);
+        qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
+            intc_phandles[cpu]);
+        qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
+            "riscv,cpu-intc");
+        qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
+        qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
+
+        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
+        qemu_fdt_add_subnode(mc->fdt, core_name);
+        qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle);
+
+        g_free(core_name);
+        g_free(intc_name);
+        g_free(cpu_name);
+    }
+}
+
+static void create_fdt_socket_memory(RISCVVirtState *s,
+                                     const MemMapEntry *memmap, int socket)
+{
+    char *mem_name;
     uint64_t addr, size;
-    uint32_t *clint_cells, *plic_cells;
-    unsigned long clint_addr, plic_addr;
-    uint32_t plic_phandle[MAX_NODES];
-    uint32_t cpu_phandle, intc_phandle, test_phandle;
-    uint32_t phandle = 1, plic_mmio_phandle = 1;
-    uint32_t plic_pcie_phandle = 1, plic_virtio_phandle = 1;
-    char *mem_name, *cpu_name, *core_name, *intc_name;
-    char *name, *clint_name, *plic_name, *clust_name;
-    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
-    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
+    MachineState *mc = MACHINE(s);
 
-    if (mc->dtb) {
-        fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
-        if (!fdt) {
-            error_report("load_device_tree() failed");
-            exit(1);
-        }
-        goto update_bootargs;
-    } else {
-        fdt = mc->fdt = create_device_tree(&s->fdt_size);
-        if (!fdt) {
-            error_report("create_device_tree() failed");
-            exit(1);
-        }
+    addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
+    size = riscv_socket_mem_size(mc, socket);
+    mem_name = g_strdup_printf("/memory@%lx", (long)addr);
+    qemu_fdt_add_subnode(mc->fdt, mem_name);
+    qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg",
+        addr >> 32, addr, size >> 32, size);
+    qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory");
+    riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket);
+    g_free(mem_name);
+}
+
+static void create_fdt_socket_clint(RISCVVirtState *s,
+                                    const MemMapEntry *memmap, int socket,
+                                    uint32_t *intc_phandles)
+{
+    int cpu;
+    char *clint_name;
+    uint32_t *clint_cells;
+    unsigned long clint_addr;
+    MachineState *mc = MACHINE(s);
+
+    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
+
+    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
+        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
     }
 
-    qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
-    qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
-    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
+    clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
+    clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
+    qemu_fdt_add_subnode(mc->fdt, clint_name);
+    qemu_fdt_setprop_string(mc->fdt, clint_name, "compatible",
+        "riscv,clint0");
+    qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg",
+        0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
+    qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended",
+        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
+    riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket);
+    g_free(clint_name);
+
+    g_free(clint_cells);
+}
+
+static void create_fdt_socket_plic(RISCVVirtState *s,
+                                   const MemMapEntry *memmap, int socket,
+                                   uint32_t *phandle, uint32_t *intc_phandles,
+                                   uint32_t *plic_phandles)
+{
+    int cpu;
+    char *plic_name;
+    uint32_t *plic_cells;
+    unsigned long plic_addr;
+    MachineState *mc = MACHINE(s);
 
-    qemu_fdt_add_subnode(fdt, "/soc");
-    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
-    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
-    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
-    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
+    plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
 
-    qemu_fdt_add_subnode(fdt, "/cpus");
-    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
+    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
+        plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
+        plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
+        plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
+        plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
+    }
+
+    plic_phandles[socket] = (*phandle)++;
+    plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
+    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
+    qemu_fdt_add_subnode(mc->fdt, plic_name);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name,
+        "#address-cells", FDT_PLIC_ADDR_CELLS);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name,
+        "#interrupt-cells", FDT_PLIC_INT_CELLS);
+    qemu_fdt_setprop_string(mc->fdt, plic_name, "compatible", "riscv,plic0");
+    qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended",
+        plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
+    qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
+        0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
+    riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
+    qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
+        plic_phandles[socket]);
+    g_free(plic_name);
+
+    g_free(plic_cells);
+}
+
+static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
+                               bool is_32_bit, uint32_t *phandle,
+                               uint32_t *irq_mmio_phandle,
+                               uint32_t *irq_pcie_phandle,
+                               uint32_t *irq_virtio_phandle)
+{
+    int socket;
+    char *clust_name;
+    uint32_t *intc_phandles;
+    MachineState *mc = MACHINE(s);
+    uint32_t xplic_phandles[MAX_NODES];
+
+    qemu_fdt_add_subnode(mc->fdt, "/cpus");
+    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency",
                           RISCV_ACLINT_TIMEBASE_FREQ);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
-    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
-    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0);
+    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map");
 
     for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) {
         clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
-        qemu_fdt_add_subnode(fdt, clust_name);
+        qemu_fdt_add_subnode(mc->fdt, clust_name);
 
-        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
-        clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
+        intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts);
 
-        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
-            cpu_phandle = phandle++;
+        create_fdt_socket_cpus(s, socket, clust_name, phandle,
+            is_32_bit, intc_phandles);
 
-            cpu_name = g_strdup_printf("/cpus/cpu@%d",
-                s->soc[socket].hartid_base + cpu);
-            qemu_fdt_add_subnode(fdt, cpu_name);
-            if (is_32_bit) {
-                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
-            } else {
-                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
-            }
-            name = riscv_isa_string(&s->soc[socket].harts[cpu]);
-            qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
-            g_free(name);
-            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
-            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
-            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
-                s->soc[socket].hartid_base + cpu);
-            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
-            riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket);
-            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
-
-            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
-            qemu_fdt_add_subnode(fdt, intc_name);
-            intc_phandle = phandle++;
-            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
-            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
-                "riscv,cpu-intc");
-            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
-            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
-
-            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
-            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
-            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
-            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
-
-            plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
-            plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
-            plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
-            plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
-
-            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
-            qemu_fdt_add_subnode(fdt, core_name);
-            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
-
-            g_free(core_name);
-            g_free(intc_name);
-            g_free(cpu_name);
-        }
+        create_fdt_socket_memory(s, memmap, socket);
 
-        addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
-        size = riscv_socket_mem_size(mc, socket);
-        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
-        qemu_fdt_add_subnode(fdt, mem_name);
-        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
-            addr >> 32, addr, size >> 32, size);
-        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
-        riscv_socket_fdt_write_id(mc, fdt, mem_name, socket);
-        g_free(mem_name);
-
-        clint_addr = memmap[VIRT_CLINT].base +
-            (memmap[VIRT_CLINT].size * socket);
-        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
-        qemu_fdt_add_subnode(fdt, clint_name);
-        qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
-        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
-            0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
-        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
-            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
-        riscv_socket_fdt_write_id(mc, fdt, clint_name, socket);
-        g_free(clint_name);
-
-        plic_phandle[socket] = phandle++;
-        plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
-        plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
-        qemu_fdt_add_subnode(fdt, plic_name);
-        qemu_fdt_setprop_cell(fdt, plic_name,
-            "#address-cells", FDT_PLIC_ADDR_CELLS);
-        qemu_fdt_setprop_cell(fdt, plic_name,
-            "#interrupt-cells", FDT_PLIC_INT_CELLS);
-        qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
-        qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
-        qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
-            plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
-        qemu_fdt_setprop_cells(fdt, plic_name, "reg",
-            0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
-        qemu_fdt_setprop_cell(fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
-        riscv_socket_fdt_write_id(mc, fdt, plic_name, socket);
-        qemu_fdt_setprop_cell(fdt, plic_name, "phandle", plic_phandle[socket]);
-        g_free(plic_name);
-
-        g_free(clint_cells);
-        g_free(plic_cells);
+        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
+
+        create_fdt_socket_plic(s, memmap, socket, phandle,
+            intc_phandles, xplic_phandles);
+
+        g_free(intc_phandles);
         g_free(clust_name);
     }
 
     for (socket = 0; socket < riscv_socket_count(mc); socket++) {
         if (socket == 0) {
-            plic_mmio_phandle = plic_phandle[socket];
-            plic_virtio_phandle = plic_phandle[socket];
-            plic_pcie_phandle = plic_phandle[socket];
+            *irq_mmio_phandle = xplic_phandles[socket];
+            *irq_virtio_phandle = xplic_phandles[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
         }
         if (socket == 1) {
-            plic_virtio_phandle = plic_phandle[socket];
-            plic_pcie_phandle = plic_phandle[socket];
+            *irq_virtio_phandle = xplic_phandles[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
         }
         if (socket == 2) {
-            plic_pcie_phandle = plic_phandle[socket];
+            *irq_pcie_phandle = xplic_phandles[socket];
         }
     }
 
-    riscv_socket_fdt_write_distance_matrix(mc, fdt);
+    riscv_socket_fdt_write_distance_matrix(mc, mc->fdt);
+}
+
+static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
+                              uint32_t irq_virtio_phandle)
+{
+    int i;
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     for (i = 0; i < VIRTIO_COUNT; i++) {
         name = g_strdup_printf("/soc/virtio_mmio@%lx",
             (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
-        qemu_fdt_add_subnode(fdt, name);
-        qemu_fdt_setprop_string(fdt, name, "compatible", "virtio,mmio");
-        qemu_fdt_setprop_cells(fdt, name, "reg",
+        qemu_fdt_add_subnode(mc->fdt, name);
+        qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio");
+        qemu_fdt_setprop_cells(mc->fdt, name, "reg",
             0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
             0x0, memmap[VIRT_VIRTIO].size);
-        qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
-            plic_virtio_phandle);
-        qemu_fdt_setprop_cell(fdt, name, "interrupts", VIRTIO_IRQ + i);
+        qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
+            irq_virtio_phandle);
+        qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i);
         g_free(name);
     }
+}
+
+static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
+                            uint32_t irq_pcie_phandle)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     name = g_strdup_printf("/soc/pci@%lx",
         (long) memmap[VIRT_PCIE_ECAM].base);
-    qemu_fdt_add_subnode(fdt, name);
-    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,
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells",
+        FDT_PCI_ADDR_CELLS);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells",
+        FDT_PCI_INT_CELLS);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
+        "pci-host-ecam-generic");
+    qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci");
+    qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0);
+    qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0,
         memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
-    qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
-    qemu_fdt_setprop_cells(fdt, name, "reg", 0,
+    qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0);
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0,
         memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
-    qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
+    qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges",
         1, FDT_PCI_RANGE_IOPORT, 2, 0,
         2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
         1, FDT_PCI_RANGE_MMIO,
@@ -387,63 +434,93 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
         2, virt_high_pcie_memmap.base,
         2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
 
-    create_pcie_irq_map(fdt, name, plic_pcie_phandle);
+    create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle);
     g_free(name);
+}
+
+static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
+                             uint32_t *phandle)
+{
+    char *name;
+    uint32_t test_phandle;
+    MachineState *mc = MACHINE(s);
 
-    test_phandle = phandle++;
+    test_phandle = (*phandle)++;
     name = g_strdup_printf("/soc/test@%lx",
         (long)memmap[VIRT_TEST].base);
-    qemu_fdt_add_subnode(fdt, name);
+    qemu_fdt_add_subnode(mc->fdt, name);
     {
         const char compat[] = "sifive,test1\0sifive,test0\0syscon";
-        qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
+        qemu_fdt_setprop(mc->fdt, name, "compatible", compat, sizeof(compat));
     }
-    qemu_fdt_setprop_cells(fdt, name, "reg",
-        0x0, memmap[VIRT_TEST].base,
-        0x0, memmap[VIRT_TEST].size);
-    qemu_fdt_setprop_cell(fdt, name, "phandle", test_phandle);
-    test_phandle = qemu_fdt_get_phandle(fdt, name);
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
+    qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle);
+    test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
     g_free(name);
 
     name = g_strdup_printf("/soc/reboot");
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
-    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
-    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_RESET);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
+    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
     g_free(name);
 
     name = g_strdup_printf("/soc/poweroff");
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
-    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
-    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_PASS);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
+    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS);
     g_free(name);
+}
+
+static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
+                            uint32_t irq_mmio_phandle)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
-    qemu_fdt_setprop_cells(fdt, name, "reg",
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
         0x0, memmap[VIRT_UART0].base,
         0x0, memmap[VIRT_UART0].size);
-    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
-    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "interrupts", UART0_IRQ);
+    qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
 
-    qemu_fdt_add_subnode(fdt, "/chosen");
-    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
+    qemu_fdt_add_subnode(mc->fdt, "/chosen");
+    qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
     g_free(name);
+}
+
+static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
+                           uint32_t irq_mmio_phandle)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
 
     name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
-    qemu_fdt_add_subnode(fdt, name);
-    qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
-    qemu_fdt_setprop_cells(fdt, name, "reg",
-        0x0, memmap[VIRT_RTC].base,
-        0x0, memmap[VIRT_RTC].size);
-    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
-    qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
+        "google,goldfish-rtc");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
+        irq_mmio_phandle);
+    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
     g_free(name);
+}
+
+static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
+{
+    char *name;
+    MachineState *mc = MACHINE(s);
+    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
+    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
 
     name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
     qemu_fdt_add_subnode(mc->fdt, name);
@@ -453,10 +530,59 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
                                  2, flashbase + flashsize, 2, flashsize);
     qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
     g_free(name);
+}
+
+static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
+                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
+{
+    MachineState *mc = MACHINE(s);
+    uint32_t phandle = 1, irq_mmio_phandle = 1;
+    uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
+
+    if (mc->dtb) {
+        mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
+        if (!mc->fdt) {
+            error_report("load_device_tree() failed");
+            exit(1);
+        }
+        goto update_bootargs;
+    } else {
+        mc->fdt = create_device_tree(&s->fdt_size);
+        if (!mc->fdt) {
+            error_report("create_device_tree() failed");
+            exit(1);
+        }
+    }
+
+    qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu");
+    qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio");
+    qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2);
+
+    qemu_fdt_add_subnode(mc->fdt, "/soc");
+    qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0);
+    qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus");
+    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2);
+    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2);
+
+    create_fdt_sockets(s, memmap, is_32_bit, &phandle,
+        &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle);
+
+    create_fdt_virtio(s, memmap, irq_virtio_phandle);
+
+    create_fdt_pcie(s, memmap, irq_pcie_phandle);
+
+    create_fdt_reset(s, memmap, &phandle);
+
+    create_fdt_uart(s, memmap, irq_mmio_phandle);
+
+    create_fdt_rtc(s, memmap, irq_mmio_phandle);
+
+    create_fdt_flash(s, memmap);
 
 update_bootargs:
     if (cmdline) {
-        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
+        qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
     }
 }
 
-- 
2.25.1



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

* [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-06-12 16:06 ` Anup Patel
@ 2021-06-12 16:06   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We extend virt machine to emulate ACLINT devices only when "aclint=on"
parameter is passed along with machine name in QEMU command-line.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
 include/hw/riscv/virt.h |   2 +
 2 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 977d699753..a35f66af13 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
     [VIRT_TEST] =        {   0x100000,        0x1000 },
     [VIRT_RTC] =         {   0x101000,        0x1000 },
     [VIRT_CLINT] =       {  0x2000000,       0x10000 },
+    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
     [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
     [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
     [VIRT_UART0] =       { 0x10000000,         0x100 },
@@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
     g_free(clint_cells);
 }
 
+static void create_fdt_socket_aclint(RISCVVirtState *s,
+                                     const MemMapEntry *memmap, int socket,
+                                     uint32_t *intc_phandles)
+{
+    int cpu;
+    char *name;
+    unsigned long addr;
+    uint32_t aclint_cells_size;
+    uint32_t *aclint_mswi_cells;
+    uint32_t *aclint_sswi_cells;
+    uint32_t *aclint_mtimer_cells;
+    MachineState *mc = 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;
+
+    addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
+    name = g_strdup_printf("/soc/mswi@%lx", addr);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE);
+    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
+        aclint_mswi_cells, aclint_cells_size);
+    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
+    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
+    g_free(name);
+
+    addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
+        (memmap[VIRT_CLINT].size * socket);
+    name = g_strdup_printf("/soc/mtimer@%lx", addr);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
+        "riscv,aclint-mtimer");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, addr, 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE);
+    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
+        aclint_mtimer_cells, aclint_cells_size);
+    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
+    g_free(name);
+
+    addr = memmap[VIRT_ACLINT_SSWI].base +
+        (memmap[VIRT_ACLINT_SSWI].size * socket);
+    name = g_strdup_printf("/soc/sswi@%lx", addr);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
+    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
+        aclint_sswi_cells, aclint_cells_size);
+    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
+    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
+    g_free(name);
+
+    g_free(aclint_mswi_cells);
+    g_free(aclint_mtimer_cells);
+    g_free(aclint_sswi_cells);
+}
+
 static void create_fdt_socket_plic(RISCVVirtState *s,
                                    const MemMapEntry *memmap, int socket,
                                    uint32_t *phandle, uint32_t *intc_phandles,
@@ -352,7 +425,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
 
         create_fdt_socket_memory(s, memmap, socket);
 
-        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
+        if (s->have_aclint) {
+            create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
+        } else {
+            create_fdt_socket_clint(s, memmap, socket, intc_phandles);
+        }
 
         create_fdt_socket_plic(s, memmap, socket, phandle,
             intc_phandles, xplic_phandles);
@@ -722,6 +799,15 @@ static void virt_machine_init(MachineState *machine)
             RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
             RISCV_ACLINT_TIMEBASE_FREQ, true);
 
+        /* Per-socket ACLINT SSWI */
+        if (s->have_aclint) {
+            riscv_aclint_swi_create(
+                memmap[VIRT_ACLINT_SSWI].base +
+                    i * memmap[VIRT_ACLINT_SSWI].size,
+                memmap[VIRT_ACLINT_SSWI].size,
+                base_hartid, hart_count, true);
+        }
+
         /* Per-socket PLIC hart topology configuration string */
         plic_hart_config_len =
             (strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
@@ -898,6 +984,22 @@ static void virt_machine_instance_init(Object *obj)
 {
 }
 
+static bool virt_get_aclint(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
+
+    return s->have_aclint;
+}
+
+static void virt_set_aclint(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
+
+    s->have_aclint = value;
+}
+
 static void virt_machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -913,6 +1015,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
     mc->numa_mem_supported = true;
 
     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+
+    object_class_property_add_bool(oc, "aclint", virt_get_aclint,
+                                   virt_set_aclint);
+    object_class_property_set_description(oc, "aclint",
+                                          "Set on/off to enable/disable "
+                                          "emulating ACLINT devices");
 }
 
 static const TypeInfo virt_machine_typeinfo = {
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 349fee1f89..d9105c1886 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -43,6 +43,7 @@ struct RISCVVirtState {
     FWCfgState *fw_cfg;
 
     int fdt_size;
+    bool have_aclint;
 };
 
 enum {
@@ -51,6 +52,7 @@ enum {
     VIRT_TEST,
     VIRT_RTC,
     VIRT_CLINT,
+    VIRT_ACLINT_SSWI,
     VIRT_PLIC,
     VIRT_UART0,
     VIRT_VIRTIO,
-- 
2.25.1



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

* [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-06-12 16:06   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-12 16:06 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We extend virt machine to emulate ACLINT devices only when "aclint=on"
parameter is passed along with machine name in QEMU command-line.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
 include/hw/riscv/virt.h |   2 +
 2 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 977d699753..a35f66af13 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
     [VIRT_TEST] =        {   0x100000,        0x1000 },
     [VIRT_RTC] =         {   0x101000,        0x1000 },
     [VIRT_CLINT] =       {  0x2000000,       0x10000 },
+    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
     [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
     [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
     [VIRT_UART0] =       { 0x10000000,         0x100 },
@@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
     g_free(clint_cells);
 }
 
+static void create_fdt_socket_aclint(RISCVVirtState *s,
+                                     const MemMapEntry *memmap, int socket,
+                                     uint32_t *intc_phandles)
+{
+    int cpu;
+    char *name;
+    unsigned long addr;
+    uint32_t aclint_cells_size;
+    uint32_t *aclint_mswi_cells;
+    uint32_t *aclint_sswi_cells;
+    uint32_t *aclint_mtimer_cells;
+    MachineState *mc = 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;
+
+    addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
+    name = g_strdup_printf("/soc/mswi@%lx", addr);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE);
+    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
+        aclint_mswi_cells, aclint_cells_size);
+    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
+    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
+    g_free(name);
+
+    addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
+        (memmap[VIRT_CLINT].size * socket);
+    name = g_strdup_printf("/soc/mtimer@%lx", addr);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
+        "riscv,aclint-mtimer");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, addr, 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE);
+    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
+        aclint_mtimer_cells, aclint_cells_size);
+    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
+    g_free(name);
+
+    addr = memmap[VIRT_ACLINT_SSWI].base +
+        (memmap[VIRT_ACLINT_SSWI].size * socket);
+    name = g_strdup_printf("/soc/sswi@%lx", addr);
+    qemu_fdt_add_subnode(mc->fdt, name);
+    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi");
+    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
+        0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
+    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
+        aclint_sswi_cells, aclint_cells_size);
+    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
+    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
+    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
+    g_free(name);
+
+    g_free(aclint_mswi_cells);
+    g_free(aclint_mtimer_cells);
+    g_free(aclint_sswi_cells);
+}
+
 static void create_fdt_socket_plic(RISCVVirtState *s,
                                    const MemMapEntry *memmap, int socket,
                                    uint32_t *phandle, uint32_t *intc_phandles,
@@ -352,7 +425,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
 
         create_fdt_socket_memory(s, memmap, socket);
 
-        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
+        if (s->have_aclint) {
+            create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
+        } else {
+            create_fdt_socket_clint(s, memmap, socket, intc_phandles);
+        }
 
         create_fdt_socket_plic(s, memmap, socket, phandle,
             intc_phandles, xplic_phandles);
@@ -722,6 +799,15 @@ static void virt_machine_init(MachineState *machine)
             RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
             RISCV_ACLINT_TIMEBASE_FREQ, true);
 
+        /* Per-socket ACLINT SSWI */
+        if (s->have_aclint) {
+            riscv_aclint_swi_create(
+                memmap[VIRT_ACLINT_SSWI].base +
+                    i * memmap[VIRT_ACLINT_SSWI].size,
+                memmap[VIRT_ACLINT_SSWI].size,
+                base_hartid, hart_count, true);
+        }
+
         /* Per-socket PLIC hart topology configuration string */
         plic_hart_config_len =
             (strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
@@ -898,6 +984,22 @@ static void virt_machine_instance_init(Object *obj)
 {
 }
 
+static bool virt_get_aclint(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
+
+    return s->have_aclint;
+}
+
+static void virt_set_aclint(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
+
+    s->have_aclint = value;
+}
+
 static void virt_machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -913,6 +1015,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
     mc->numa_mem_supported = true;
 
     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
+
+    object_class_property_add_bool(oc, "aclint", virt_get_aclint,
+                                   virt_set_aclint);
+    object_class_property_set_description(oc, "aclint",
+                                          "Set on/off to enable/disable "
+                                          "emulating ACLINT devices");
 }
 
 static const TypeInfo virt_machine_typeinfo = {
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 349fee1f89..d9105c1886 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -43,6 +43,7 @@ struct RISCVVirtState {
     FWCfgState *fw_cfg;
 
     int fdt_size;
+    bool have_aclint;
 };
 
 enum {
@@ -51,6 +52,7 @@ enum {
     VIRT_TEST,
     VIRT_RTC,
     VIRT_CLINT,
+    VIRT_ACLINT_SSWI,
     VIRT_PLIC,
     VIRT_UART0,
     VIRT_VIRTIO,
-- 
2.25.1



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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  2021-06-12 16:06   ` Anup Patel
@ 2021-06-14 12:22     ` Bin Meng
  -1 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-06-14 12:22 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sun, Jun 13, 2021 at 12:08 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> The RISC-V ACLINT is more modular and backward compatible with
> original SiFive CLINT so instead of duplicating the orignal
> SiFive CLINT implementation we upgrade the current SiFive CLINT
> implementation to RISC-V ACLINT implementation.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/intc/Kconfig                |   2 +-
>  hw/intc/meson.build            |   2 +-
>  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
>  hw/intc/sifive_clint.c         | 266 -----------------------
>  hw/riscv/Kconfig               |  10 +-
>  hw/riscv/microchip_pfsoc.c     |  12 +-
>  hw/riscv/sifive_e.c            |  12 +-
>  hw/riscv/sifive_u.c            |  14 +-
>  hw/riscv/spike.c               |  15 +-
>  hw/riscv/virt.c                |  15 +-
>  include/hw/intc/riscv_aclint.h |  73 +++++++
>  include/hw/intc/sifive_clint.h |  60 ------
>  12 files changed, 494 insertions(+), 361 deletions(-)
>  create mode 100644 hw/intc/riscv_aclint.c
>  delete mode 100644 hw/intc/sifive_clint.c
>  create mode 100644 include/hw/intc/riscv_aclint.h
>  delete mode 100644 include/hw/intc/sifive_clint.h
>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index f4694088a4..78aed93c45 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,7 +62,7 @@ config RX_ICU
>  config LOONGSON_LIOINTC
>      bool
>
> -config SIFIVE_CLINT
> +config RISCV_ACLINT
>      bool
>
>  config SIFIVE_PLIC
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 1c299039f6..2482fcfaf8 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
>  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
>  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
>  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
>  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> new file mode 100644
> index 0000000000..682f95cca7
> --- /dev/null
> +++ b/hw/intc/riscv_aclint.c
> @@ -0,0 +1,374 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor)
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This provides real-time clock, timer and interprocessor interrupts.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "qemu/module.h"
> +#include "hw/sysbus.h"
> +#include "target/riscv/cpu.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/intc/riscv_aclint.h"
> +#include "qemu/timer.h"
> +
> +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> +{
> +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +        timebase_freq, NANOSECONDS_PER_SECOND);
> +}
> +
> +/*
> + * Called when timecmp is written to update the QEMU timer or immediately
> + * trigger timer interrupt if mtimecmp <= current timer value.
> + */
> +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> +    uint32_t timebase_freq)
> +{
> +    uint64_t next;
> +    uint64_t diff;
> +
> +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> +
> +    cpu->env.timecmp = value;
> +    if (cpu->env.timecmp <= rtc_r) {
> +        /* if we're setting an MTIMECMP value in the "past",
> +           immediately raise the timer interrupt */

nits: please use correct multi-line comment format

> +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +        return;
> +    }
> +
> +    /* otherwise, set up the future timer interrupt */
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> +    diff = cpu->env.timecmp - rtc_r;
> +    /* back to ns (note args switched in muldiv64) */
> +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> +    timer_mod(cpu->env.timer, next);
> +}
> +
> +/*
> + * Callback used when the timer set using timer_mod expires.
> + * Should raise the timer interrupt line
> + */
> +static void riscv_aclint_mtimer_cb(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +}
> +
> +/* CPU wants to read MTIMER register */

nits: CPU read MTIMER register (for consistency with other RW routines)

> +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp = env->timecmp;
> +            return timecmp & 0xFFFFFFFF;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp = env->timecmp;
> +            return (timecmp >> 32) & 0xFFFFFFFF;
> +        } else {
> +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +            return 0;
> +        }
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> +    }
> +
> +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote MTIMER register */

nits: write

> +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> +    uint64_t value, unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp_hi = env->timecmp >> 32;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +            return;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp_lo = env->timecmp;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +        } else {
> +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> +                         (uint32_t)addr);
> +        }
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        error_report("aclint-mtimer: time_lo write not implemented");
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        error_report("aclint-mtimer: time_hi write not implemented");
> +        return;
> +    }
> +
> +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> +    .read = riscv_aclint_mtimer_read,
> +    .write = riscv_aclint_mtimer_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8
> +    }
> +};
> +
> +static Property riscv_aclint_mtimer_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> +        hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),

I guess we can set the default value to 4095 according to the spec?

> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> +        aperture_size, 0),

I don't think this parameter is needed given the spec clearly defines its size.

> +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> +        timebase_freq, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim MTIP so that only MTIMER controls it. */

nits: please remove the ending .

> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> +            error_report("MTIP already claimed");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_mtimer_realize;
> +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_mtimer_info = {
> +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintMTimerState),
> +    .class_init    = riscv_aclint_mtimer_class_init,
> +};
> +
> +/*
> + * Create ACLINT MTIMER device.
> + */
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime)
> +{
> +    int i;
> +    for (i = 0; i < num_harts; i++) {
> +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            continue;
> +        }
> +        if (provide_rdtime) {
> +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> +        }
> +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                  &riscv_aclint_mtimer_cb, cpu);
> +        env->timecmp = 0;
> +    }
> +
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +/* CPU read [M|S]SWI register */
> +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            return (env->mip & swi->sirq_mask) > 0;
> +        } else {
> +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +            return 0;
> +        }
> +    }
> +
> +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote [M|S]SWI register */

write

> +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> +        unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> +                                 BOOL_TO_MASK(value));
> +        } else {
> +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> +                         (uint32_t)addr);
> +        }
> +        return;
> +    }
> +
> +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_swi_ops = {
> +    .read = riscv_aclint_swi_read,
> +    .write = riscv_aclint_swi_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4
> +    }
> +};
> +
> +static Property riscv_aclint_swi_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),

ditto

> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> +        aperture_size, 0),

ditto

> +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),

Could be more intuitive if we describe it as:

DEFINE_PROP_BOOL("sswi", RISCVAclintSwiState, sswi, false)

so we don't bother user to pass the mask of the MIP register

> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim [M|S]SIP so that can SWI controls it. */
> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +
> +        /* We don't claim SSIP bit of mip CSR because this bit is
> +         * writable by software as-per RISC-V privilege specification.
> +         */

nits: please use correct multi-line comment format

> +        if ((s->sirq_mask != MIP_SSIP) &&
> +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> +            error_report("%s already claimed",
> +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_swi_realize;
> +    device_class_set_props(dc, riscv_aclint_swi_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_swi_info = {
> +    .name          = TYPE_RISCV_ACLINT_SWI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintSwiState),
> +    .class_init    = riscv_aclint_swi_class_init,
> +};
> +
> +/*
> + * Create ACLINT [M|S]SWI device.
> + */
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> +{
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +static void riscv_aclint_register_types(void)
> +{
> +    type_register_static(&riscv_aclint_mtimer_info);
> +    type_register_static(&riscv_aclint_swi_info);
> +}
> +
> +type_init(riscv_aclint_register_types)
> diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> deleted file mode 100644
> index 0f41e5ea1c..0000000000
> --- a/hw/intc/sifive_clint.c
> +++ /dev/null
> @@ -1,266 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor)
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This provides real-time clock, timer and interprocessor interrupts.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "qemu/osdep.h"
> -#include "qapi/error.h"
> -#include "qemu/error-report.h"
> -#include "qemu/module.h"
> -#include "hw/sysbus.h"
> -#include "target/riscv/cpu.h"
> -#include "hw/qdev-properties.h"
> -#include "hw/intc/sifive_clint.h"
> -#include "qemu/timer.h"
> -
> -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> -{
> -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> -        timebase_freq, NANOSECONDS_PER_SECOND);
> -}
> -
> -/*
> - * Called when timecmp is written to update the QEMU timer or immediately
> - * trigger timer interrupt if mtimecmp <= current timer value.
> - */
> -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> -                                       uint32_t timebase_freq)
> -{
> -    uint64_t next;
> -    uint64_t diff;
> -
> -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> -
> -    cpu->env.timecmp = value;
> -    if (cpu->env.timecmp <= rtc_r) {
> -        /* if we're setting an MTIMECMP value in the "past",
> -           immediately raise the timer interrupt */
> -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -        return;
> -    }
> -
> -    /* otherwise, set up the future timer interrupt */
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> -    diff = cpu->env.timecmp - rtc_r;
> -    /* back to ns (note args switched in muldiv64) */
> -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> -    timer_mod(cpu->env.timer, next);
> -}
> -
> -/*
> - * Callback used when the timer set using timer_mod expires.
> - * Should raise the timer interrupt line
> - */
> -static void sifive_clint_timer_cb(void *opaque)
> -{
> -    RISCVCPU *cpu = opaque;
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -}
> -
> -/* CPU wants to read rtc or timecmp register */
> -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            return (env->mip & MIP_MSIP) > 0;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp = env->timecmp;
> -            return timecmp & 0xFFFFFFFF;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp = env->timecmp;
> -            return (timecmp >> 32) & 0xFFFFFFFF;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> -    }
> -
> -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> -    return 0;
> -}
> -
> -/* CPU wrote to rtc or timecmp register */
> -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> -        unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> -        } else {
> -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp_hi = env->timecmp >> 32;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> -            return;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp_lo = env->timecmp;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> -        } else {
> -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        error_report("clint: time_lo write not implemented");
> -        return;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        error_report("clint: time_hi write not implemented");
> -        return;
> -    }
> -
> -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> -}
> -
> -static const MemoryRegionOps sifive_clint_ops = {
> -    .read = sifive_clint_read,
> -    .write = sifive_clint_write,
> -    .endianness = DEVICE_LITTLE_ENDIAN,
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 8
> -    }
> -};
> -
> -static Property sifive_clint_properties[] = {
> -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> -    DEFINE_PROP_END_OF_LIST(),
> -};
> -
> -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> -{
> -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> -}
> -
> -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    dc->realize = sifive_clint_realize;
> -    device_class_set_props(dc, sifive_clint_properties);
> -}
> -
> -static const TypeInfo sifive_clint_info = {
> -    .name          = TYPE_SIFIVE_CLINT,
> -    .parent        = TYPE_SYS_BUS_DEVICE,
> -    .instance_size = sizeof(SiFiveCLINTState),
> -    .class_init    = sifive_clint_class_init,
> -};
> -
> -static void sifive_clint_register_types(void)
> -{
> -    type_register_static(&sifive_clint_info);
> -}
> -
> -type_init(sifive_clint_register_types)
> -
> -
> -/*
> - * Create CLINT device.
> - */
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime)
> -{
> -    int i;
> -    for (i = 0; i < num_harts; i++) {
> -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            continue;
> -        }
> -        if (provide_rdtime) {
> -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> -        }
> -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> -                                  &sifive_clint_timer_cb, cpu);
> -        env->timecmp = 0;
> -    }
> -
> -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> -    qdev_prop_set_uint32(dev, "time-base", time_base);
> -    qdev_prop_set_uint32(dev, "aperture-size", size);
> -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> -    return dev;
> -}
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 1de18cdcf1..939cd0ef40 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
>      select MCHP_PFSOC_MMUART
>      select MCHP_PFSOC_SYSREG
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
>      select UNIMP
> @@ -29,7 +29,7 @@ config RISCV_VIRT
>      select PCI_EXPRESS_GENERIC_BRIDGE
>      select PFLASH_CFI01
>      select SERIAL
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT

nits: please insert this by following the alphabetical order

>      select SIFIVE_PLIC
>      select SIFIVE_TEST
>      select VIRTIO_MMIO
> @@ -38,7 +38,7 @@ config RISCV_VIRT
>  config SIFIVE_E
>      bool
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PLIC
>      select SIFIVE_UART
> @@ -49,7 +49,7 @@ config SIFIVE_U
>      bool
>      select CADENCE
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
> @@ -65,5 +65,5 @@ config SPIKE
>      bool
>      select HTIF
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PLIC
> diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> index c4146b7a6b..e637e5c885 100644
> --- a/hw/riscv/microchip_pfsoc.c
> +++ b/hw/riscv/microchip_pfsoc.c
> @@ -51,7 +51,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/riscv_hart.h"
>  #include "hw/riscv/microchip_pfsoc.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "sysemu/sysemu.h"
>
> @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
>          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
>
>      /* CLINT */
> -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(
> +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      /* L2 cache controller */
>      create_unimplemented_device("microchip.pfsoc.l2cc",
> diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> index f939bcf9ea..ea960a5f2e 100644
> --- a/hw/riscv/sifive_e.c
> +++ b/hw/riscv/sifive_e.c
> @@ -42,7 +42,7 @@
>  #include "hw/riscv/sifive_e.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_e_prci.h"
>  #include "chardev/char.h"
> @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
>          SIFIVE_E_PLIC_CONTEXT_BASE,
>          SIFIVE_E_PLIC_CONTEXT_STRIDE,
>          memmap[SIFIVE_E_DEV_PLIC].size);
> -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>      create_unimplemented_device("riscv.sifive.e.aon",
>          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
>      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> index 7b59942369..e5fe681984 100644
> --- a/hw/riscv/sifive_u.c
> +++ b/hw/riscv/sifive_u.c
> @@ -52,7 +52,7 @@
>  #include "hw/riscv/sifive_u.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "chardev/char.h"
>  #include "net/eth.h"
> @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>
> @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
>          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
>      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
>          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
>          return;
> diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> index ec7cb2f707..10681fbf99 100644
> --- a/hw/riscv/spike.c
> +++ b/hw/riscv/spike.c
> @@ -36,7 +36,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
>  #include "hw/char/riscv_htif.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "chardev/char.h"
>  #include "sysemu/arch_init.h"
>  #include "sysemu/device_tree.h"
> @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Core Local Interruptor (timer and IPI) for each socket */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, false);
>      }
>
>      /* register system main memory (actual RAM) */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c0dc69ff33..5eb63f6efd 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -33,7 +33,7 @@
>  #include "hw/riscv/virt.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_test.h"
>  #include "chardev/char.h"
> @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> +                          RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Per-socket CLINT */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, true);
>
>          /* Per-socket PLIC hart topology configuration string */
>          plic_hart_config_len =
> diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> new file mode 100644
> index 0000000000..471a5ffd0b
> --- /dev/null
> +++ b/include/hw/intc/riscv_aclint.h
> @@ -0,0 +1,73 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_RISCV_ACLINT_H
> +#define HW_RISCV_ACLINT_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> +
> +#define RISCV_ACLINT_MTIMER(obj) \
> +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> +
> +typedef struct RISCVAclintMTimerState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t timebase_freq;
> +} RISCVAclintMTimerState;
> +
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime);
> +
> +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> +
> +#define RISCV_ACLINT_SWI(obj) \
> +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> +
> +typedef struct RISCVAclintSwiState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t sirq_mask;
> +} RISCVAclintSwiState;
> +
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> +
> +enum {
> +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> +    RISCV_ACLINT_SWI_SIZE = 0x4000
> +};
> +
> +#endif
> diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> deleted file mode 100644
> index a30be0f3d6..0000000000
> --- a/include/hw/intc/sifive_clint.h
> +++ /dev/null
> @@ -1,60 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor) interface
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef HW_SIFIVE_CLINT_H
> -#define HW_SIFIVE_CLINT_H
> -
> -#include "hw/sysbus.h"
> -
> -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> -
> -#define SIFIVE_CLINT(obj) \
> -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> -
> -typedef struct SiFiveCLINTState {
> -    /*< private >*/
> -    SysBusDevice parent_obj;
> -
> -    /*< public >*/
> -    MemoryRegion mmio;
> -    uint32_t hartid_base;
> -    uint32_t num_harts;
> -    uint32_t sip_base;
> -    uint32_t timecmp_base;
> -    uint32_t time_base;
> -    uint32_t aperture_size;
> -    uint32_t timebase_freq;
> -} SiFiveCLINTState;
> -
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime);
> -
> -enum {
> -    SIFIVE_SIP_BASE     = 0x0,
> -    SIFIVE_TIMECMP_BASE = 0x4000,
> -    SIFIVE_TIME_BASE    = 0xBFF8
> -};
> -
> -enum {
> -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> -};
> -
> -#endif

Regards,
Bin


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
@ 2021-06-14 12:22     ` Bin Meng
  0 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-06-14 12:22 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sun, Jun 13, 2021 at 12:08 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> The RISC-V ACLINT is more modular and backward compatible with
> original SiFive CLINT so instead of duplicating the orignal
> SiFive CLINT implementation we upgrade the current SiFive CLINT
> implementation to RISC-V ACLINT implementation.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/intc/Kconfig                |   2 +-
>  hw/intc/meson.build            |   2 +-
>  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
>  hw/intc/sifive_clint.c         | 266 -----------------------
>  hw/riscv/Kconfig               |  10 +-
>  hw/riscv/microchip_pfsoc.c     |  12 +-
>  hw/riscv/sifive_e.c            |  12 +-
>  hw/riscv/sifive_u.c            |  14 +-
>  hw/riscv/spike.c               |  15 +-
>  hw/riscv/virt.c                |  15 +-
>  include/hw/intc/riscv_aclint.h |  73 +++++++
>  include/hw/intc/sifive_clint.h |  60 ------
>  12 files changed, 494 insertions(+), 361 deletions(-)
>  create mode 100644 hw/intc/riscv_aclint.c
>  delete mode 100644 hw/intc/sifive_clint.c
>  create mode 100644 include/hw/intc/riscv_aclint.h
>  delete mode 100644 include/hw/intc/sifive_clint.h
>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index f4694088a4..78aed93c45 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,7 +62,7 @@ config RX_ICU
>  config LOONGSON_LIOINTC
>      bool
>
> -config SIFIVE_CLINT
> +config RISCV_ACLINT
>      bool
>
>  config SIFIVE_PLIC
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 1c299039f6..2482fcfaf8 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
>  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
>  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
>  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
>  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> new file mode 100644
> index 0000000000..682f95cca7
> --- /dev/null
> +++ b/hw/intc/riscv_aclint.c
> @@ -0,0 +1,374 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor)
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This provides real-time clock, timer and interprocessor interrupts.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "qemu/module.h"
> +#include "hw/sysbus.h"
> +#include "target/riscv/cpu.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/intc/riscv_aclint.h"
> +#include "qemu/timer.h"
> +
> +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> +{
> +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +        timebase_freq, NANOSECONDS_PER_SECOND);
> +}
> +
> +/*
> + * Called when timecmp is written to update the QEMU timer or immediately
> + * trigger timer interrupt if mtimecmp <= current timer value.
> + */
> +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> +    uint32_t timebase_freq)
> +{
> +    uint64_t next;
> +    uint64_t diff;
> +
> +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> +
> +    cpu->env.timecmp = value;
> +    if (cpu->env.timecmp <= rtc_r) {
> +        /* if we're setting an MTIMECMP value in the "past",
> +           immediately raise the timer interrupt */

nits: please use correct multi-line comment format

> +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +        return;
> +    }
> +
> +    /* otherwise, set up the future timer interrupt */
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> +    diff = cpu->env.timecmp - rtc_r;
> +    /* back to ns (note args switched in muldiv64) */
> +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> +    timer_mod(cpu->env.timer, next);
> +}
> +
> +/*
> + * Callback used when the timer set using timer_mod expires.
> + * Should raise the timer interrupt line
> + */
> +static void riscv_aclint_mtimer_cb(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +}
> +
> +/* CPU wants to read MTIMER register */

nits: CPU read MTIMER register (for consistency with other RW routines)

> +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp = env->timecmp;
> +            return timecmp & 0xFFFFFFFF;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp = env->timecmp;
> +            return (timecmp >> 32) & 0xFFFFFFFF;
> +        } else {
> +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +            return 0;
> +        }
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> +    }
> +
> +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote MTIMER register */

nits: write

> +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> +    uint64_t value, unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp_hi = env->timecmp >> 32;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +            return;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp_lo = env->timecmp;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +        } else {
> +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> +                         (uint32_t)addr);
> +        }
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        error_report("aclint-mtimer: time_lo write not implemented");
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        error_report("aclint-mtimer: time_hi write not implemented");
> +        return;
> +    }
> +
> +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> +    .read = riscv_aclint_mtimer_read,
> +    .write = riscv_aclint_mtimer_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8
> +    }
> +};
> +
> +static Property riscv_aclint_mtimer_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> +        hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),

I guess we can set the default value to 4095 according to the spec?

> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> +        aperture_size, 0),

I don't think this parameter is needed given the spec clearly defines its size.

> +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> +        timebase_freq, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim MTIP so that only MTIMER controls it. */

nits: please remove the ending .

> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> +            error_report("MTIP already claimed");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_mtimer_realize;
> +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_mtimer_info = {
> +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintMTimerState),
> +    .class_init    = riscv_aclint_mtimer_class_init,
> +};
> +
> +/*
> + * Create ACLINT MTIMER device.
> + */
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime)
> +{
> +    int i;
> +    for (i = 0; i < num_harts; i++) {
> +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            continue;
> +        }
> +        if (provide_rdtime) {
> +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> +        }
> +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                  &riscv_aclint_mtimer_cb, cpu);
> +        env->timecmp = 0;
> +    }
> +
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +/* CPU read [M|S]SWI register */
> +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            return (env->mip & swi->sirq_mask) > 0;
> +        } else {
> +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +            return 0;
> +        }
> +    }
> +
> +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote [M|S]SWI register */

write

> +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> +        unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> +                                 BOOL_TO_MASK(value));
> +        } else {
> +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> +                         (uint32_t)addr);
> +        }
> +        return;
> +    }
> +
> +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_swi_ops = {
> +    .read = riscv_aclint_swi_read,
> +    .write = riscv_aclint_swi_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4
> +    }
> +};
> +
> +static Property riscv_aclint_swi_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),

ditto

> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> +        aperture_size, 0),

ditto

> +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),

Could be more intuitive if we describe it as:

DEFINE_PROP_BOOL("sswi", RISCVAclintSwiState, sswi, false)

so we don't bother user to pass the mask of the MIP register

> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim [M|S]SIP so that can SWI controls it. */
> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +
> +        /* We don't claim SSIP bit of mip CSR because this bit is
> +         * writable by software as-per RISC-V privilege specification.
> +         */

nits: please use correct multi-line comment format

> +        if ((s->sirq_mask != MIP_SSIP) &&
> +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> +            error_report("%s already claimed",
> +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_swi_realize;
> +    device_class_set_props(dc, riscv_aclint_swi_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_swi_info = {
> +    .name          = TYPE_RISCV_ACLINT_SWI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintSwiState),
> +    .class_init    = riscv_aclint_swi_class_init,
> +};
> +
> +/*
> + * Create ACLINT [M|S]SWI device.
> + */
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> +{
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +static void riscv_aclint_register_types(void)
> +{
> +    type_register_static(&riscv_aclint_mtimer_info);
> +    type_register_static(&riscv_aclint_swi_info);
> +}
> +
> +type_init(riscv_aclint_register_types)
> diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> deleted file mode 100644
> index 0f41e5ea1c..0000000000
> --- a/hw/intc/sifive_clint.c
> +++ /dev/null
> @@ -1,266 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor)
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This provides real-time clock, timer and interprocessor interrupts.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "qemu/osdep.h"
> -#include "qapi/error.h"
> -#include "qemu/error-report.h"
> -#include "qemu/module.h"
> -#include "hw/sysbus.h"
> -#include "target/riscv/cpu.h"
> -#include "hw/qdev-properties.h"
> -#include "hw/intc/sifive_clint.h"
> -#include "qemu/timer.h"
> -
> -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> -{
> -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> -        timebase_freq, NANOSECONDS_PER_SECOND);
> -}
> -
> -/*
> - * Called when timecmp is written to update the QEMU timer or immediately
> - * trigger timer interrupt if mtimecmp <= current timer value.
> - */
> -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> -                                       uint32_t timebase_freq)
> -{
> -    uint64_t next;
> -    uint64_t diff;
> -
> -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> -
> -    cpu->env.timecmp = value;
> -    if (cpu->env.timecmp <= rtc_r) {
> -        /* if we're setting an MTIMECMP value in the "past",
> -           immediately raise the timer interrupt */
> -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -        return;
> -    }
> -
> -    /* otherwise, set up the future timer interrupt */
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> -    diff = cpu->env.timecmp - rtc_r;
> -    /* back to ns (note args switched in muldiv64) */
> -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> -    timer_mod(cpu->env.timer, next);
> -}
> -
> -/*
> - * Callback used when the timer set using timer_mod expires.
> - * Should raise the timer interrupt line
> - */
> -static void sifive_clint_timer_cb(void *opaque)
> -{
> -    RISCVCPU *cpu = opaque;
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -}
> -
> -/* CPU wants to read rtc or timecmp register */
> -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            return (env->mip & MIP_MSIP) > 0;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp = env->timecmp;
> -            return timecmp & 0xFFFFFFFF;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp = env->timecmp;
> -            return (timecmp >> 32) & 0xFFFFFFFF;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> -    }
> -
> -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> -    return 0;
> -}
> -
> -/* CPU wrote to rtc or timecmp register */
> -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> -        unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> -        } else {
> -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp_hi = env->timecmp >> 32;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> -            return;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp_lo = env->timecmp;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> -        } else {
> -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        error_report("clint: time_lo write not implemented");
> -        return;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        error_report("clint: time_hi write not implemented");
> -        return;
> -    }
> -
> -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> -}
> -
> -static const MemoryRegionOps sifive_clint_ops = {
> -    .read = sifive_clint_read,
> -    .write = sifive_clint_write,
> -    .endianness = DEVICE_LITTLE_ENDIAN,
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 8
> -    }
> -};
> -
> -static Property sifive_clint_properties[] = {
> -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> -    DEFINE_PROP_END_OF_LIST(),
> -};
> -
> -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> -{
> -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> -}
> -
> -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    dc->realize = sifive_clint_realize;
> -    device_class_set_props(dc, sifive_clint_properties);
> -}
> -
> -static const TypeInfo sifive_clint_info = {
> -    .name          = TYPE_SIFIVE_CLINT,
> -    .parent        = TYPE_SYS_BUS_DEVICE,
> -    .instance_size = sizeof(SiFiveCLINTState),
> -    .class_init    = sifive_clint_class_init,
> -};
> -
> -static void sifive_clint_register_types(void)
> -{
> -    type_register_static(&sifive_clint_info);
> -}
> -
> -type_init(sifive_clint_register_types)
> -
> -
> -/*
> - * Create CLINT device.
> - */
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime)
> -{
> -    int i;
> -    for (i = 0; i < num_harts; i++) {
> -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            continue;
> -        }
> -        if (provide_rdtime) {
> -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> -        }
> -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> -                                  &sifive_clint_timer_cb, cpu);
> -        env->timecmp = 0;
> -    }
> -
> -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> -    qdev_prop_set_uint32(dev, "time-base", time_base);
> -    qdev_prop_set_uint32(dev, "aperture-size", size);
> -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> -    return dev;
> -}
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 1de18cdcf1..939cd0ef40 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
>      select MCHP_PFSOC_MMUART
>      select MCHP_PFSOC_SYSREG
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
>      select UNIMP
> @@ -29,7 +29,7 @@ config RISCV_VIRT
>      select PCI_EXPRESS_GENERIC_BRIDGE
>      select PFLASH_CFI01
>      select SERIAL
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT

nits: please insert this by following the alphabetical order

>      select SIFIVE_PLIC
>      select SIFIVE_TEST
>      select VIRTIO_MMIO
> @@ -38,7 +38,7 @@ config RISCV_VIRT
>  config SIFIVE_E
>      bool
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PLIC
>      select SIFIVE_UART
> @@ -49,7 +49,7 @@ config SIFIVE_U
>      bool
>      select CADENCE
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
> @@ -65,5 +65,5 @@ config SPIKE
>      bool
>      select HTIF
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PLIC
> diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> index c4146b7a6b..e637e5c885 100644
> --- a/hw/riscv/microchip_pfsoc.c
> +++ b/hw/riscv/microchip_pfsoc.c
> @@ -51,7 +51,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/riscv_hart.h"
>  #include "hw/riscv/microchip_pfsoc.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "sysemu/sysemu.h"
>
> @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
>          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
>
>      /* CLINT */
> -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(
> +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      /* L2 cache controller */
>      create_unimplemented_device("microchip.pfsoc.l2cc",
> diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> index f939bcf9ea..ea960a5f2e 100644
> --- a/hw/riscv/sifive_e.c
> +++ b/hw/riscv/sifive_e.c
> @@ -42,7 +42,7 @@
>  #include "hw/riscv/sifive_e.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_e_prci.h"
>  #include "chardev/char.h"
> @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
>          SIFIVE_E_PLIC_CONTEXT_BASE,
>          SIFIVE_E_PLIC_CONTEXT_STRIDE,
>          memmap[SIFIVE_E_DEV_PLIC].size);
> -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>      create_unimplemented_device("riscv.sifive.e.aon",
>          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
>      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> index 7b59942369..e5fe681984 100644
> --- a/hw/riscv/sifive_u.c
> +++ b/hw/riscv/sifive_u.c
> @@ -52,7 +52,7 @@
>  #include "hw/riscv/sifive_u.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "chardev/char.h"
>  #include "net/eth.h"
> @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>
> @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
>          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
>      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
>          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
>          return;
> diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> index ec7cb2f707..10681fbf99 100644
> --- a/hw/riscv/spike.c
> +++ b/hw/riscv/spike.c
> @@ -36,7 +36,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
>  #include "hw/char/riscv_htif.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "chardev/char.h"
>  #include "sysemu/arch_init.h"
>  #include "sysemu/device_tree.h"
> @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Core Local Interruptor (timer and IPI) for each socket */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, false);
>      }
>
>      /* register system main memory (actual RAM) */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c0dc69ff33..5eb63f6efd 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -33,7 +33,7 @@
>  #include "hw/riscv/virt.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_test.h"
>  #include "chardev/char.h"
> @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> +                          RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Per-socket CLINT */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, true);
>
>          /* Per-socket PLIC hart topology configuration string */
>          plic_hart_config_len =
> diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> new file mode 100644
> index 0000000000..471a5ffd0b
> --- /dev/null
> +++ b/include/hw/intc/riscv_aclint.h
> @@ -0,0 +1,73 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_RISCV_ACLINT_H
> +#define HW_RISCV_ACLINT_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> +
> +#define RISCV_ACLINT_MTIMER(obj) \
> +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> +
> +typedef struct RISCVAclintMTimerState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t timebase_freq;
> +} RISCVAclintMTimerState;
> +
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime);
> +
> +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> +
> +#define RISCV_ACLINT_SWI(obj) \
> +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> +
> +typedef struct RISCVAclintSwiState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t sirq_mask;
> +} RISCVAclintSwiState;
> +
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> +
> +enum {
> +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> +    RISCV_ACLINT_SWI_SIZE = 0x4000
> +};
> +
> +#endif
> diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> deleted file mode 100644
> index a30be0f3d6..0000000000
> --- a/include/hw/intc/sifive_clint.h
> +++ /dev/null
> @@ -1,60 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor) interface
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef HW_SIFIVE_CLINT_H
> -#define HW_SIFIVE_CLINT_H
> -
> -#include "hw/sysbus.h"
> -
> -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> -
> -#define SIFIVE_CLINT(obj) \
> -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> -
> -typedef struct SiFiveCLINTState {
> -    /*< private >*/
> -    SysBusDevice parent_obj;
> -
> -    /*< public >*/
> -    MemoryRegion mmio;
> -    uint32_t hartid_base;
> -    uint32_t num_harts;
> -    uint32_t sip_base;
> -    uint32_t timecmp_base;
> -    uint32_t time_base;
> -    uint32_t aperture_size;
> -    uint32_t timebase_freq;
> -} SiFiveCLINTState;
> -
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime);
> -
> -enum {
> -    SIFIVE_SIP_BASE     = 0x0,
> -    SIFIVE_TIMECMP_BASE = 0x4000,
> -    SIFIVE_TIME_BASE    = 0xBFF8
> -};
> -
> -enum {
> -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> -};
> -
> -#endif

Regards,
Bin


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

* Re: [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation
  2021-06-12 16:06   ` Anup Patel
@ 2021-06-14 12:22     ` Bin Meng
  -1 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-06-14 12:22 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sun, Jun 13, 2021 at 12:12 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We re-factor and break the FDT generation into smaller functions
> so that it is easier to modify FDT generation for different
> configurations of virt machine.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/riscv/virt.c | 514 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 320 insertions(+), 194 deletions(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 5eb63f6efd..977d699753 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -178,206 +178,253 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
>                             0x1800, 0, 0, 0x7);
>  }
>
> -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> -                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> +static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
> +                                   char *clust_name, uint32_t *phandle,
> +                                   bool is_32_bit, uint32_t *intc_phandles)
>  {
> -    void *fdt;
> -    int i, cpu, socket;
> +    int cpu;
> +    uint32_t cpu_phandle;
>      MachineState *mc = MACHINE(s);
> +    char *name, *cpu_name, *core_name, *intc_name;
> +
> +    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> +        cpu_phandle = (*phandle)++;
> +
> +        cpu_name = g_strdup_printf("/cpus/cpu@%d",
> +            s->soc[socket].hartid_base + cpu);
> +        qemu_fdt_add_subnode(mc->fdt, cpu_name);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type",
> +            (is_32_bit) ? "riscv,sv32" : "riscv,sv48");
> +        name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name);
> +        g_free(name);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv");
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay");
> +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg",
> +            s->soc[socket].hartid_base + cpu);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu");
> +        riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket);
> +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle);
> +
> +        intc_phandles[cpu] = (*phandle)++;
> +
> +        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> +        qemu_fdt_add_subnode(mc->fdt, intc_name);
> +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
> +            intc_phandles[cpu]);
> +        qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
> +            "riscv,cpu-intc");
> +        qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
> +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
> +
> +        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> +        qemu_fdt_add_subnode(mc->fdt, core_name);
> +        qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle);
> +
> +        g_free(core_name);
> +        g_free(intc_name);
> +        g_free(cpu_name);
> +    }
> +}
> +
> +static void create_fdt_socket_memory(RISCVVirtState *s,
> +                                     const MemMapEntry *memmap, int socket)
> +{
> +    char *mem_name;
>      uint64_t addr, size;
> -    uint32_t *clint_cells, *plic_cells;
> -    unsigned long clint_addr, plic_addr;
> -    uint32_t plic_phandle[MAX_NODES];
> -    uint32_t cpu_phandle, intc_phandle, test_phandle;
> -    uint32_t phandle = 1, plic_mmio_phandle = 1;
> -    uint32_t plic_pcie_phandle = 1, plic_virtio_phandle = 1;
> -    char *mem_name, *cpu_name, *core_name, *intc_name;
> -    char *name, *clint_name, *plic_name, *clust_name;
> -    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> -    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
> +    MachineState *mc = MACHINE(s);
>
> -    if (mc->dtb) {
> -        fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> -        if (!fdt) {
> -            error_report("load_device_tree() failed");
> -            exit(1);
> -        }
> -        goto update_bootargs;
> -    } else {
> -        fdt = mc->fdt = create_device_tree(&s->fdt_size);
> -        if (!fdt) {
> -            error_report("create_device_tree() failed");
> -            exit(1);
> -        }
> +    addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> +    size = riscv_socket_mem_size(mc, socket);
> +    mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> +    qemu_fdt_add_subnode(mc->fdt, mem_name);
> +    qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg",
> +        addr >> 32, addr, size >> 32, size);
> +    qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory");
> +    riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket);
> +    g_free(mem_name);
> +}
> +
> +static void create_fdt_socket_clint(RISCVVirtState *s,
> +                                    const MemMapEntry *memmap, int socket,
> +                                    uint32_t *intc_phandles)
> +{
> +    int cpu;
> +    char *clint_name;
> +    uint32_t *clint_cells;
> +    unsigned long clint_addr;
> +    MachineState *mc = MACHINE(s);
> +
> +    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> +
> +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> +        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> +        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> +        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> +        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
>      }
>
> -    qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
> -    qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
> -    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
> -    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
> +    clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> +    clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> +    qemu_fdt_add_subnode(mc->fdt, clint_name);
> +    qemu_fdt_setprop_string(mc->fdt, clint_name, "compatible",
> +        "riscv,clint0");

This patch seems to be based on some old commit, as the latest QEMU
head has the following commit that supports the official clint
compatible name via:

commit b387236bff95 ("hw/riscv: Support the official CLINT DT bindings")

> +    qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg",
> +        0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> +    qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended",
> +        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket);
> +    g_free(clint_name);
> +
> +    g_free(clint_cells);
> +}
> +
> +static void create_fdt_socket_plic(RISCVVirtState *s,
> +                                   const MemMapEntry *memmap, int socket,
> +                                   uint32_t *phandle, uint32_t *intc_phandles,
> +                                   uint32_t *plic_phandles)
> +{
> +    int cpu;
> +    char *plic_name;
> +    uint32_t *plic_cells;
> +    unsigned long plic_addr;
> +    MachineState *mc = MACHINE(s);
>
> -    qemu_fdt_add_subnode(fdt, "/soc");
> -    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
> -    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
> -    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
> -    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
> +    plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
>
> -    qemu_fdt_add_subnode(fdt, "/cpus");
> -    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> +        plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> +        plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> +        plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> +        plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> +    }
> +
> +    plic_phandles[socket] = (*phandle)++;
> +    plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> +    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> +    qemu_fdt_add_subnode(mc->fdt, plic_name);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> +        "#address-cells", FDT_PLIC_ADDR_CELLS);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> +        "#interrupt-cells", FDT_PLIC_INT_CELLS);
> +    qemu_fdt_setprop_string(mc->fdt, plic_name, "compatible", "riscv,plic0");
> +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0);
> +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended",
> +        plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> +    qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
> +        0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
> +        plic_phandles[socket]);
> +    g_free(plic_name);
> +
> +    g_free(plic_cells);
> +}
> +
> +static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
> +                               bool is_32_bit, uint32_t *phandle,
> +                               uint32_t *irq_mmio_phandle,
> +                               uint32_t *irq_pcie_phandle,
> +                               uint32_t *irq_virtio_phandle)
> +{
> +    int socket;
> +    char *clust_name;
> +    uint32_t *intc_phandles;
> +    MachineState *mc = MACHINE(s);
> +    uint32_t xplic_phandles[MAX_NODES];
> +
> +    qemu_fdt_add_subnode(mc->fdt, "/cpus");
> +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency",
>                            RISCV_ACLINT_TIMEBASE_FREQ);
> -    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> -    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> -    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0);
> +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1);
> +    qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map");
>
>      for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) {
>          clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
> -        qemu_fdt_add_subnode(fdt, clust_name);
> +        qemu_fdt_add_subnode(mc->fdt, clust_name);
>
> -        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> -        clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> +        intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts);
>
> -        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> -            cpu_phandle = phandle++;
> +        create_fdt_socket_cpus(s, socket, clust_name, phandle,
> +            is_32_bit, intc_phandles);
>
> -            cpu_name = g_strdup_printf("/cpus/cpu@%d",
> -                s->soc[socket].hartid_base + cpu);
> -            qemu_fdt_add_subnode(fdt, cpu_name);
> -            if (is_32_bit) {
> -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
> -            } else {
> -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
> -            }
> -            name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> -            qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
> -            g_free(name);
> -            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
> -            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
> -            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
> -                s->soc[socket].hartid_base + cpu);
> -            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
> -            riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket);
> -            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
> -
> -            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> -            qemu_fdt_add_subnode(fdt, intc_name);
> -            intc_phandle = phandle++;
> -            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
> -            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> -                "riscv,cpu-intc");
> -            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
> -            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
> -
> -            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> -            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> -            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> -            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
> -
> -            plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> -            plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> -            plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> -            plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> -
> -            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> -            qemu_fdt_add_subnode(fdt, core_name);
> -            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
> -
> -            g_free(core_name);
> -            g_free(intc_name);
> -            g_free(cpu_name);
> -        }
> +        create_fdt_socket_memory(s, memmap, socket);
>
> -        addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> -        size = riscv_socket_mem_size(mc, socket);
> -        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> -        qemu_fdt_add_subnode(fdt, mem_name);
> -        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
> -            addr >> 32, addr, size >> 32, size);
> -        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
> -        riscv_socket_fdt_write_id(mc, fdt, mem_name, socket);
> -        g_free(mem_name);
> -
> -        clint_addr = memmap[VIRT_CLINT].base +
> -            (memmap[VIRT_CLINT].size * socket);
> -        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> -        qemu_fdt_add_subnode(fdt, clint_name);
> -        qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
> -        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
> -            0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> -        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
> -            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> -        riscv_socket_fdt_write_id(mc, fdt, clint_name, socket);
> -        g_free(clint_name);
> -
> -        plic_phandle[socket] = phandle++;
> -        plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> -        plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> -        qemu_fdt_add_subnode(fdt, plic_name);
> -        qemu_fdt_setprop_cell(fdt, plic_name,
> -            "#address-cells", FDT_PLIC_ADDR_CELLS);
> -        qemu_fdt_setprop_cell(fdt, plic_name,
> -            "#interrupt-cells", FDT_PLIC_INT_CELLS);
> -        qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
> -        qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
> -        qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
> -            plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> -        qemu_fdt_setprop_cells(fdt, plic_name, "reg",
> -            0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> -        qemu_fdt_setprop_cell(fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> -        riscv_socket_fdt_write_id(mc, fdt, plic_name, socket);
> -        qemu_fdt_setprop_cell(fdt, plic_name, "phandle", plic_phandle[socket]);
> -        g_free(plic_name);
> -
> -        g_free(clint_cells);
> -        g_free(plic_cells);
> +        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> +
> +        create_fdt_socket_plic(s, memmap, socket, phandle,
> +            intc_phandles, xplic_phandles);
> +
> +        g_free(intc_phandles);
>          g_free(clust_name);
>      }
>
>      for (socket = 0; socket < riscv_socket_count(mc); socket++) {
>          if (socket == 0) {
> -            plic_mmio_phandle = plic_phandle[socket];
> -            plic_virtio_phandle = plic_phandle[socket];
> -            plic_pcie_phandle = plic_phandle[socket];
> +            *irq_mmio_phandle = xplic_phandles[socket];
> +            *irq_virtio_phandle = xplic_phandles[socket];
> +            *irq_pcie_phandle = xplic_phandles[socket];
>          }
>          if (socket == 1) {
> -            plic_virtio_phandle = plic_phandle[socket];
> -            plic_pcie_phandle = plic_phandle[socket];
> +            *irq_virtio_phandle = xplic_phandles[socket];
> +            *irq_pcie_phandle = xplic_phandles[socket];
>          }
>          if (socket == 2) {
> -            plic_pcie_phandle = plic_phandle[socket];
> +            *irq_pcie_phandle = xplic_phandles[socket];
>          }
>      }
>
> -    riscv_socket_fdt_write_distance_matrix(mc, fdt);
> +    riscv_socket_fdt_write_distance_matrix(mc, mc->fdt);
> +}
> +
> +static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
> +                              uint32_t irq_virtio_phandle)
> +{
> +    int i;
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      for (i = 0; i < VIRTIO_COUNT; i++) {
>          name = g_strdup_printf("/soc/virtio_mmio@%lx",
>              (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
> -        qemu_fdt_add_subnode(fdt, name);
> -        qemu_fdt_setprop_string(fdt, name, "compatible", "virtio,mmio");
> -        qemu_fdt_setprop_cells(fdt, name, "reg",
> +        qemu_fdt_add_subnode(mc->fdt, name);
> +        qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio");
> +        qemu_fdt_setprop_cells(mc->fdt, name, "reg",
>              0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
>              0x0, memmap[VIRT_VIRTIO].size);
> -        qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
> -            plic_virtio_phandle);
> -        qemu_fdt_setprop_cell(fdt, name, "interrupts", VIRTIO_IRQ + i);
> +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> +            irq_virtio_phandle);
> +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i);
>          g_free(name);
>      }
> +}
> +
> +static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
> +                            uint32_t irq_pcie_phandle)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      name = g_strdup_printf("/soc/pci@%lx",
>          (long) memmap[VIRT_PCIE_ECAM].base);
> -    qemu_fdt_add_subnode(fdt, name);
> -    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,
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells",
> +        FDT_PCI_ADDR_CELLS);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells",
> +        FDT_PCI_INT_CELLS);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> +        "pci-host-ecam-generic");
> +    qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci");
> +    qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0);
> +    qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0,
>          memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> -    qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> -    qemu_fdt_setprop_cells(fdt, name, "reg", 0,
> +    qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0);
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0,
>          memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
> -    qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> +    qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges",
>          1, FDT_PCI_RANGE_IOPORT, 2, 0,
>          2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
>          1, FDT_PCI_RANGE_MMIO,
> @@ -387,63 +434,93 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>          2, virt_high_pcie_memmap.base,
>          2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
>
> -    create_pcie_irq_map(fdt, name, plic_pcie_phandle);
> +    create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle);
>      g_free(name);
> +}
> +
> +static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
> +                             uint32_t *phandle)
> +{
> +    char *name;
> +    uint32_t test_phandle;
> +    MachineState *mc = MACHINE(s);
>
> -    test_phandle = phandle++;
> +    test_phandle = (*phandle)++;
>      name = g_strdup_printf("/soc/test@%lx",
>          (long)memmap[VIRT_TEST].base);
> -    qemu_fdt_add_subnode(fdt, name);
> +    qemu_fdt_add_subnode(mc->fdt, name);
>      {
>          const char compat[] = "sifive,test1\0sifive,test0\0syscon";
> -        qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
> +        qemu_fdt_setprop(mc->fdt, name, "compatible", compat, sizeof(compat));
>      }
> -    qemu_fdt_setprop_cells(fdt, name, "reg",
> -        0x0, memmap[VIRT_TEST].base,
> -        0x0, memmap[VIRT_TEST].size);
> -    qemu_fdt_setprop_cell(fdt, name, "phandle", test_phandle);
> -    test_phandle = qemu_fdt_get_phandle(fdt, name);
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle);
> +    test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
>      g_free(name);
>
>      name = g_strdup_printf("/soc/reboot");
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
> -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_RESET);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
> +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
>      g_free(name);
>
>      name = g_strdup_printf("/soc/poweroff");
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
> -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_PASS);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
> +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS);
>      g_free(name);
> +}
> +
> +static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
> +                            uint32_t irq_mmio_phandle)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> -    qemu_fdt_setprop_cells(fdt, name, "reg",
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
>          0x0, memmap[VIRT_UART0].base,
>          0x0, memmap[VIRT_UART0].size);
> -    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupts", UART0_IRQ);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
>
> -    qemu_fdt_add_subnode(fdt, "/chosen");
> -    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
> +    qemu_fdt_add_subnode(mc->fdt, "/chosen");
> +    qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
>      g_free(name);
> +}
> +
> +static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
> +                           uint32_t irq_mmio_phandle)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
> -    qemu_fdt_setprop_cells(fdt, name, "reg",
> -        0x0, memmap[VIRT_RTC].base,
> -        0x0, memmap[VIRT_RTC].size);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> +        "google,goldfish-rtc");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> +        irq_mmio_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
>      g_free(name);
> +}
> +
> +static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
> +    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> +    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
>
>      name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
>      qemu_fdt_add_subnode(mc->fdt, name);
> @@ -453,10 +530,59 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>                                   2, flashbase + flashsize, 2, flashsize);
>      qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
>      g_free(name);
> +}
> +
> +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> +                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> +{
> +    MachineState *mc = MACHINE(s);
> +    uint32_t phandle = 1, irq_mmio_phandle = 1;
> +    uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
> +
> +    if (mc->dtb) {
> +        mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> +        if (!mc->fdt) {
> +            error_report("load_device_tree() failed");
> +            exit(1);
> +        }
> +        goto update_bootargs;
> +    } else {
> +        mc->fdt = create_device_tree(&s->fdt_size);
> +        if (!mc->fdt) {
> +            error_report("create_device_tree() failed");
> +            exit(1);
> +        }
> +    }
> +
> +    qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu");
> +    qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio");
> +    qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2);
> +    qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2);
> +
> +    qemu_fdt_add_subnode(mc->fdt, "/soc");
> +    qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0);
> +    qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus");
> +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2);
> +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2);
> +
> +    create_fdt_sockets(s, memmap, is_32_bit, &phandle,
> +        &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle);
> +
> +    create_fdt_virtio(s, memmap, irq_virtio_phandle);
> +
> +    create_fdt_pcie(s, memmap, irq_pcie_phandle);
> +
> +    create_fdt_reset(s, memmap, &phandle);
> +
> +    create_fdt_uart(s, memmap, irq_mmio_phandle);
> +
> +    create_fdt_rtc(s, memmap, irq_mmio_phandle);
> +
> +    create_fdt_flash(s, memmap);
>
>  update_bootargs:
>      if (cmdline) {
> -        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
> +        qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
>      }
>  }

Regards,
Bin


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

* Re: [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation
@ 2021-06-14 12:22     ` Bin Meng
  0 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-06-14 12:22 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sun, Jun 13, 2021 at 12:12 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We re-factor and break the FDT generation into smaller functions
> so that it is easier to modify FDT generation for different
> configurations of virt machine.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/riscv/virt.c | 514 ++++++++++++++++++++++++++++++------------------
>  1 file changed, 320 insertions(+), 194 deletions(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 5eb63f6efd..977d699753 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -178,206 +178,253 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
>                             0x1800, 0, 0, 0x7);
>  }
>
> -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> -                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> +static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
> +                                   char *clust_name, uint32_t *phandle,
> +                                   bool is_32_bit, uint32_t *intc_phandles)
>  {
> -    void *fdt;
> -    int i, cpu, socket;
> +    int cpu;
> +    uint32_t cpu_phandle;
>      MachineState *mc = MACHINE(s);
> +    char *name, *cpu_name, *core_name, *intc_name;
> +
> +    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> +        cpu_phandle = (*phandle)++;
> +
> +        cpu_name = g_strdup_printf("/cpus/cpu@%d",
> +            s->soc[socket].hartid_base + cpu);
> +        qemu_fdt_add_subnode(mc->fdt, cpu_name);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type",
> +            (is_32_bit) ? "riscv,sv32" : "riscv,sv48");
> +        name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name);
> +        g_free(name);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv");
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay");
> +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg",
> +            s->soc[socket].hartid_base + cpu);
> +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu");
> +        riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket);
> +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle);
> +
> +        intc_phandles[cpu] = (*phandle)++;
> +
> +        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> +        qemu_fdt_add_subnode(mc->fdt, intc_name);
> +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
> +            intc_phandles[cpu]);
> +        qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
> +            "riscv,cpu-intc");
> +        qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
> +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
> +
> +        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> +        qemu_fdt_add_subnode(mc->fdt, core_name);
> +        qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle);
> +
> +        g_free(core_name);
> +        g_free(intc_name);
> +        g_free(cpu_name);
> +    }
> +}
> +
> +static void create_fdt_socket_memory(RISCVVirtState *s,
> +                                     const MemMapEntry *memmap, int socket)
> +{
> +    char *mem_name;
>      uint64_t addr, size;
> -    uint32_t *clint_cells, *plic_cells;
> -    unsigned long clint_addr, plic_addr;
> -    uint32_t plic_phandle[MAX_NODES];
> -    uint32_t cpu_phandle, intc_phandle, test_phandle;
> -    uint32_t phandle = 1, plic_mmio_phandle = 1;
> -    uint32_t plic_pcie_phandle = 1, plic_virtio_phandle = 1;
> -    char *mem_name, *cpu_name, *core_name, *intc_name;
> -    char *name, *clint_name, *plic_name, *clust_name;
> -    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> -    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
> +    MachineState *mc = MACHINE(s);
>
> -    if (mc->dtb) {
> -        fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> -        if (!fdt) {
> -            error_report("load_device_tree() failed");
> -            exit(1);
> -        }
> -        goto update_bootargs;
> -    } else {
> -        fdt = mc->fdt = create_device_tree(&s->fdt_size);
> -        if (!fdt) {
> -            error_report("create_device_tree() failed");
> -            exit(1);
> -        }
> +    addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> +    size = riscv_socket_mem_size(mc, socket);
> +    mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> +    qemu_fdt_add_subnode(mc->fdt, mem_name);
> +    qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg",
> +        addr >> 32, addr, size >> 32, size);
> +    qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory");
> +    riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket);
> +    g_free(mem_name);
> +}
> +
> +static void create_fdt_socket_clint(RISCVVirtState *s,
> +                                    const MemMapEntry *memmap, int socket,
> +                                    uint32_t *intc_phandles)
> +{
> +    int cpu;
> +    char *clint_name;
> +    uint32_t *clint_cells;
> +    unsigned long clint_addr;
> +    MachineState *mc = MACHINE(s);
> +
> +    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> +
> +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> +        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> +        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> +        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> +        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
>      }
>
> -    qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
> -    qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
> -    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
> -    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
> +    clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> +    clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> +    qemu_fdt_add_subnode(mc->fdt, clint_name);
> +    qemu_fdt_setprop_string(mc->fdt, clint_name, "compatible",
> +        "riscv,clint0");

This patch seems to be based on some old commit, as the latest QEMU
head has the following commit that supports the official clint
compatible name via:

commit b387236bff95 ("hw/riscv: Support the official CLINT DT bindings")

> +    qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg",
> +        0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> +    qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended",
> +        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket);
> +    g_free(clint_name);
> +
> +    g_free(clint_cells);
> +}
> +
> +static void create_fdt_socket_plic(RISCVVirtState *s,
> +                                   const MemMapEntry *memmap, int socket,
> +                                   uint32_t *phandle, uint32_t *intc_phandles,
> +                                   uint32_t *plic_phandles)
> +{
> +    int cpu;
> +    char *plic_name;
> +    uint32_t *plic_cells;
> +    unsigned long plic_addr;
> +    MachineState *mc = MACHINE(s);
>
> -    qemu_fdt_add_subnode(fdt, "/soc");
> -    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
> -    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
> -    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
> -    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
> +    plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
>
> -    qemu_fdt_add_subnode(fdt, "/cpus");
> -    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> +        plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> +        plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> +        plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> +        plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> +    }
> +
> +    plic_phandles[socket] = (*phandle)++;
> +    plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> +    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> +    qemu_fdt_add_subnode(mc->fdt, plic_name);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> +        "#address-cells", FDT_PLIC_ADDR_CELLS);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> +        "#interrupt-cells", FDT_PLIC_INT_CELLS);
> +    qemu_fdt_setprop_string(mc->fdt, plic_name, "compatible", "riscv,plic0");
> +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0);
> +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended",
> +        plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> +    qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
> +        0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
> +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
> +        plic_phandles[socket]);
> +    g_free(plic_name);
> +
> +    g_free(plic_cells);
> +}
> +
> +static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
> +                               bool is_32_bit, uint32_t *phandle,
> +                               uint32_t *irq_mmio_phandle,
> +                               uint32_t *irq_pcie_phandle,
> +                               uint32_t *irq_virtio_phandle)
> +{
> +    int socket;
> +    char *clust_name;
> +    uint32_t *intc_phandles;
> +    MachineState *mc = MACHINE(s);
> +    uint32_t xplic_phandles[MAX_NODES];
> +
> +    qemu_fdt_add_subnode(mc->fdt, "/cpus");
> +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency",
>                            RISCV_ACLINT_TIMEBASE_FREQ);
> -    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> -    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> -    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0);
> +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1);
> +    qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map");
>
>      for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) {
>          clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
> -        qemu_fdt_add_subnode(fdt, clust_name);
> +        qemu_fdt_add_subnode(mc->fdt, clust_name);
>
> -        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> -        clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> +        intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts);
>
> -        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> -            cpu_phandle = phandle++;
> +        create_fdt_socket_cpus(s, socket, clust_name, phandle,
> +            is_32_bit, intc_phandles);
>
> -            cpu_name = g_strdup_printf("/cpus/cpu@%d",
> -                s->soc[socket].hartid_base + cpu);
> -            qemu_fdt_add_subnode(fdt, cpu_name);
> -            if (is_32_bit) {
> -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
> -            } else {
> -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
> -            }
> -            name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> -            qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
> -            g_free(name);
> -            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
> -            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
> -            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
> -                s->soc[socket].hartid_base + cpu);
> -            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
> -            riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket);
> -            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
> -
> -            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> -            qemu_fdt_add_subnode(fdt, intc_name);
> -            intc_phandle = phandle++;
> -            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
> -            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> -                "riscv,cpu-intc");
> -            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
> -            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
> -
> -            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> -            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> -            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> -            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
> -
> -            plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> -            plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> -            plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> -            plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> -
> -            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> -            qemu_fdt_add_subnode(fdt, core_name);
> -            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
> -
> -            g_free(core_name);
> -            g_free(intc_name);
> -            g_free(cpu_name);
> -        }
> +        create_fdt_socket_memory(s, memmap, socket);
>
> -        addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> -        size = riscv_socket_mem_size(mc, socket);
> -        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> -        qemu_fdt_add_subnode(fdt, mem_name);
> -        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
> -            addr >> 32, addr, size >> 32, size);
> -        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
> -        riscv_socket_fdt_write_id(mc, fdt, mem_name, socket);
> -        g_free(mem_name);
> -
> -        clint_addr = memmap[VIRT_CLINT].base +
> -            (memmap[VIRT_CLINT].size * socket);
> -        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> -        qemu_fdt_add_subnode(fdt, clint_name);
> -        qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
> -        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
> -            0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> -        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
> -            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> -        riscv_socket_fdt_write_id(mc, fdt, clint_name, socket);
> -        g_free(clint_name);
> -
> -        plic_phandle[socket] = phandle++;
> -        plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> -        plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> -        qemu_fdt_add_subnode(fdt, plic_name);
> -        qemu_fdt_setprop_cell(fdt, plic_name,
> -            "#address-cells", FDT_PLIC_ADDR_CELLS);
> -        qemu_fdt_setprop_cell(fdt, plic_name,
> -            "#interrupt-cells", FDT_PLIC_INT_CELLS);
> -        qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
> -        qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
> -        qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
> -            plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> -        qemu_fdt_setprop_cells(fdt, plic_name, "reg",
> -            0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> -        qemu_fdt_setprop_cell(fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> -        riscv_socket_fdt_write_id(mc, fdt, plic_name, socket);
> -        qemu_fdt_setprop_cell(fdt, plic_name, "phandle", plic_phandle[socket]);
> -        g_free(plic_name);
> -
> -        g_free(clint_cells);
> -        g_free(plic_cells);
> +        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> +
> +        create_fdt_socket_plic(s, memmap, socket, phandle,
> +            intc_phandles, xplic_phandles);
> +
> +        g_free(intc_phandles);
>          g_free(clust_name);
>      }
>
>      for (socket = 0; socket < riscv_socket_count(mc); socket++) {
>          if (socket == 0) {
> -            plic_mmio_phandle = plic_phandle[socket];
> -            plic_virtio_phandle = plic_phandle[socket];
> -            plic_pcie_phandle = plic_phandle[socket];
> +            *irq_mmio_phandle = xplic_phandles[socket];
> +            *irq_virtio_phandle = xplic_phandles[socket];
> +            *irq_pcie_phandle = xplic_phandles[socket];
>          }
>          if (socket == 1) {
> -            plic_virtio_phandle = plic_phandle[socket];
> -            plic_pcie_phandle = plic_phandle[socket];
> +            *irq_virtio_phandle = xplic_phandles[socket];
> +            *irq_pcie_phandle = xplic_phandles[socket];
>          }
>          if (socket == 2) {
> -            plic_pcie_phandle = plic_phandle[socket];
> +            *irq_pcie_phandle = xplic_phandles[socket];
>          }
>      }
>
> -    riscv_socket_fdt_write_distance_matrix(mc, fdt);
> +    riscv_socket_fdt_write_distance_matrix(mc, mc->fdt);
> +}
> +
> +static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
> +                              uint32_t irq_virtio_phandle)
> +{
> +    int i;
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      for (i = 0; i < VIRTIO_COUNT; i++) {
>          name = g_strdup_printf("/soc/virtio_mmio@%lx",
>              (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
> -        qemu_fdt_add_subnode(fdt, name);
> -        qemu_fdt_setprop_string(fdt, name, "compatible", "virtio,mmio");
> -        qemu_fdt_setprop_cells(fdt, name, "reg",
> +        qemu_fdt_add_subnode(mc->fdt, name);
> +        qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio");
> +        qemu_fdt_setprop_cells(mc->fdt, name, "reg",
>              0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
>              0x0, memmap[VIRT_VIRTIO].size);
> -        qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
> -            plic_virtio_phandle);
> -        qemu_fdt_setprop_cell(fdt, name, "interrupts", VIRTIO_IRQ + i);
> +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> +            irq_virtio_phandle);
> +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i);
>          g_free(name);
>      }
> +}
> +
> +static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
> +                            uint32_t irq_pcie_phandle)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      name = g_strdup_printf("/soc/pci@%lx",
>          (long) memmap[VIRT_PCIE_ECAM].base);
> -    qemu_fdt_add_subnode(fdt, name);
> -    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,
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells",
> +        FDT_PCI_ADDR_CELLS);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells",
> +        FDT_PCI_INT_CELLS);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> +        "pci-host-ecam-generic");
> +    qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci");
> +    qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0);
> +    qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0,
>          memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> -    qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> -    qemu_fdt_setprop_cells(fdt, name, "reg", 0,
> +    qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0);
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0,
>          memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
> -    qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> +    qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges",
>          1, FDT_PCI_RANGE_IOPORT, 2, 0,
>          2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
>          1, FDT_PCI_RANGE_MMIO,
> @@ -387,63 +434,93 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>          2, virt_high_pcie_memmap.base,
>          2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
>
> -    create_pcie_irq_map(fdt, name, plic_pcie_phandle);
> +    create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle);
>      g_free(name);
> +}
> +
> +static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
> +                             uint32_t *phandle)
> +{
> +    char *name;
> +    uint32_t test_phandle;
> +    MachineState *mc = MACHINE(s);
>
> -    test_phandle = phandle++;
> +    test_phandle = (*phandle)++;
>      name = g_strdup_printf("/soc/test@%lx",
>          (long)memmap[VIRT_TEST].base);
> -    qemu_fdt_add_subnode(fdt, name);
> +    qemu_fdt_add_subnode(mc->fdt, name);
>      {
>          const char compat[] = "sifive,test1\0sifive,test0\0syscon";
> -        qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
> +        qemu_fdt_setprop(mc->fdt, name, "compatible", compat, sizeof(compat));
>      }
> -    qemu_fdt_setprop_cells(fdt, name, "reg",
> -        0x0, memmap[VIRT_TEST].base,
> -        0x0, memmap[VIRT_TEST].size);
> -    qemu_fdt_setprop_cell(fdt, name, "phandle", test_phandle);
> -    test_phandle = qemu_fdt_get_phandle(fdt, name);
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle);
> +    test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
>      g_free(name);
>
>      name = g_strdup_printf("/soc/reboot");
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
> -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_RESET);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
> +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
>      g_free(name);
>
>      name = g_strdup_printf("/soc/poweroff");
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
> -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_PASS);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
> +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS);
>      g_free(name);
> +}
> +
> +static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
> +                            uint32_t irq_mmio_phandle)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> -    qemu_fdt_setprop_cells(fdt, name, "reg",
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
>          0x0, memmap[VIRT_UART0].base,
>          0x0, memmap[VIRT_UART0].size);
> -    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupts", UART0_IRQ);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
>
> -    qemu_fdt_add_subnode(fdt, "/chosen");
> -    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
> +    qemu_fdt_add_subnode(mc->fdt, "/chosen");
> +    qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
>      g_free(name);
> +}
> +
> +static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
> +                           uint32_t irq_mmio_phandle)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
>
>      name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
> -    qemu_fdt_add_subnode(fdt, name);
> -    qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
> -    qemu_fdt_setprop_cells(fdt, name, "reg",
> -        0x0, memmap[VIRT_RTC].base,
> -        0x0, memmap[VIRT_RTC].size);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> -    qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> +        "google,goldfish-rtc");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> +        irq_mmio_phandle);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
>      g_free(name);
> +}
> +
> +static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
> +{
> +    char *name;
> +    MachineState *mc = MACHINE(s);
> +    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> +    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
>
>      name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
>      qemu_fdt_add_subnode(mc->fdt, name);
> @@ -453,10 +530,59 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>                                   2, flashbase + flashsize, 2, flashsize);
>      qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
>      g_free(name);
> +}
> +
> +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> +                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> +{
> +    MachineState *mc = MACHINE(s);
> +    uint32_t phandle = 1, irq_mmio_phandle = 1;
> +    uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
> +
> +    if (mc->dtb) {
> +        mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> +        if (!mc->fdt) {
> +            error_report("load_device_tree() failed");
> +            exit(1);
> +        }
> +        goto update_bootargs;
> +    } else {
> +        mc->fdt = create_device_tree(&s->fdt_size);
> +        if (!mc->fdt) {
> +            error_report("create_device_tree() failed");
> +            exit(1);
> +        }
> +    }
> +
> +    qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu");
> +    qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio");
> +    qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2);
> +    qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2);
> +
> +    qemu_fdt_add_subnode(mc->fdt, "/soc");
> +    qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0);
> +    qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus");
> +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2);
> +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2);
> +
> +    create_fdt_sockets(s, memmap, is_32_bit, &phandle,
> +        &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle);
> +
> +    create_fdt_virtio(s, memmap, irq_virtio_phandle);
> +
> +    create_fdt_pcie(s, memmap, irq_pcie_phandle);
> +
> +    create_fdt_reset(s, memmap, &phandle);
> +
> +    create_fdt_uart(s, memmap, irq_mmio_phandle);
> +
> +    create_fdt_rtc(s, memmap, irq_mmio_phandle);
> +
> +    create_fdt_flash(s, memmap);
>
>  update_bootargs:
>      if (cmdline) {
> -        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
> +        qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
>      }
>  }

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-06-12 16:06   ` Anup Patel
@ 2021-06-14 12:22     ` Bin Meng
  -1 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-06-14 12:22 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We extend virt machine to emulate ACLINT devices only when "aclint=on"
> parameter is passed along with machine name in QEMU command-line.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
>  include/hw/riscv/virt.h |   2 +
>  2 files changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 977d699753..a35f66af13 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
>      [VIRT_TEST] =        {   0x100000,        0x1000 },
>      [VIRT_RTC] =         {   0x101000,        0x1000 },
>      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },

How about we reuse the same register space to support both CLINT and
ACLINT? This saves some register space for future extension.

>      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
>      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
>      [VIRT_UART0] =       { 0x10000000,         0x100 },
> @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
>      g_free(clint_cells);
>  }
>
> +static void create_fdt_socket_aclint(RISCVVirtState *s,
> +                                     const MemMapEntry *memmap, int socket,
> +                                     uint32_t *intc_phandles)
> +{
> +    int cpu;
> +    char *name;
> +    unsigned long addr;
> +    uint32_t aclint_cells_size;
> +    uint32_t *aclint_mswi_cells;
> +    uint32_t *aclint_sswi_cells;
> +    uint32_t *aclint_mtimer_cells;
> +    MachineState *mc = 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;
> +
> +    addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> +    name = g_strdup_printf("/soc/mswi@%lx", addr);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> +        aclint_mswi_cells, aclint_cells_size);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> +    g_free(name);
> +
> +    addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> +        (memmap[VIRT_CLINT].size * socket);
> +    name = g_strdup_printf("/soc/mtimer@%lx", addr);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> +        "riscv,aclint-mtimer");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, addr, 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> +        aclint_mtimer_cells, aclint_cells_size);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> +    g_free(name);
> +
> +    addr = memmap[VIRT_ACLINT_SSWI].base +
> +        (memmap[VIRT_ACLINT_SSWI].size * socket);
> +    name = g_strdup_printf("/soc/sswi@%lx", addr);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> +        aclint_sswi_cells, aclint_cells_size);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> +    g_free(name);
> +
> +    g_free(aclint_mswi_cells);
> +    g_free(aclint_mtimer_cells);
> +    g_free(aclint_sswi_cells);
> +}
> +
>  static void create_fdt_socket_plic(RISCVVirtState *s,
>                                     const MemMapEntry *memmap, int socket,
>                                     uint32_t *phandle, uint32_t *intc_phandles,
> @@ -352,7 +425,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
>
>          create_fdt_socket_memory(s, memmap, socket);
>
> -        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> +        if (s->have_aclint) {
> +            create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
> +        } else {
> +            create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> +        }
>
>          create_fdt_socket_plic(s, memmap, socket, phandle,
>              intc_phandles, xplic_phandles);
> @@ -722,6 +799,15 @@ static void virt_machine_init(MachineState *machine)
>              RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
>              RISCV_ACLINT_TIMEBASE_FREQ, true);
>
> +        /* Per-socket ACLINT SSWI */
> +        if (s->have_aclint) {
> +            riscv_aclint_swi_create(
> +                memmap[VIRT_ACLINT_SSWI].base +
> +                    i * memmap[VIRT_ACLINT_SSWI].size,
> +                memmap[VIRT_ACLINT_SSWI].size,
> +                base_hartid, hart_count, true);
> +        }
> +
>          /* Per-socket PLIC hart topology configuration string */
>          plic_hart_config_len =
>              (strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
> @@ -898,6 +984,22 @@ static void virt_machine_instance_init(Object *obj)
>  {
>  }
>
> +static bool virt_get_aclint(Object *obj, Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> +
> +    return s->have_aclint;
> +}
> +
> +static void virt_set_aclint(Object *obj, bool value, Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> +
> +    s->have_aclint = value;
> +}
> +
>  static void virt_machine_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> @@ -913,6 +1015,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
>      mc->numa_mem_supported = true;
>
>      machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
> +
> +    object_class_property_add_bool(oc, "aclint", virt_get_aclint,
> +                                   virt_set_aclint);
> +    object_class_property_set_description(oc, "aclint",
> +                                          "Set on/off to enable/disable "
> +                                          "emulating ACLINT devices");
>  }
>
>  static const TypeInfo virt_machine_typeinfo = {
> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> index 349fee1f89..d9105c1886 100644
> --- a/include/hw/riscv/virt.h
> +++ b/include/hw/riscv/virt.h
> @@ -43,6 +43,7 @@ struct RISCVVirtState {
>      FWCfgState *fw_cfg;
>
>      int fdt_size;
> +    bool have_aclint;
>  };
>
>  enum {
> @@ -51,6 +52,7 @@ enum {
>      VIRT_TEST,
>      VIRT_RTC,
>      VIRT_CLINT,
> +    VIRT_ACLINT_SSWI,
>      VIRT_PLIC,
>      VIRT_UART0,
>      VIRT_VIRTIO,

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-06-14 12:22     ` Bin Meng
  0 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-06-14 12:22 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We extend virt machine to emulate ACLINT devices only when "aclint=on"
> parameter is passed along with machine name in QEMU command-line.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
>  include/hw/riscv/virt.h |   2 +
>  2 files changed, 111 insertions(+), 1 deletion(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index 977d699753..a35f66af13 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
>      [VIRT_TEST] =        {   0x100000,        0x1000 },
>      [VIRT_RTC] =         {   0x101000,        0x1000 },
>      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },

How about we reuse the same register space to support both CLINT and
ACLINT? This saves some register space for future extension.

>      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
>      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
>      [VIRT_UART0] =       { 0x10000000,         0x100 },
> @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
>      g_free(clint_cells);
>  }
>
> +static void create_fdt_socket_aclint(RISCVVirtState *s,
> +                                     const MemMapEntry *memmap, int socket,
> +                                     uint32_t *intc_phandles)
> +{
> +    int cpu;
> +    char *name;
> +    unsigned long addr;
> +    uint32_t aclint_cells_size;
> +    uint32_t *aclint_mswi_cells;
> +    uint32_t *aclint_sswi_cells;
> +    uint32_t *aclint_mtimer_cells;
> +    MachineState *mc = 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;
> +
> +    addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> +    name = g_strdup_printf("/soc/mswi@%lx", addr);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> +        aclint_mswi_cells, aclint_cells_size);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> +    g_free(name);
> +
> +    addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> +        (memmap[VIRT_CLINT].size * socket);
> +    name = g_strdup_printf("/soc/mtimer@%lx", addr);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> +        "riscv,aclint-mtimer");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, addr, 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> +        aclint_mtimer_cells, aclint_cells_size);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> +    g_free(name);
> +
> +    addr = memmap[VIRT_ACLINT_SSWI].base +
> +        (memmap[VIRT_ACLINT_SSWI].size * socket);
> +    name = g_strdup_printf("/soc/sswi@%lx", addr);
> +    qemu_fdt_add_subnode(mc->fdt, name);
> +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi");
> +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> +        0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> +        aclint_sswi_cells, aclint_cells_size);
> +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> +    g_free(name);
> +
> +    g_free(aclint_mswi_cells);
> +    g_free(aclint_mtimer_cells);
> +    g_free(aclint_sswi_cells);
> +}
> +
>  static void create_fdt_socket_plic(RISCVVirtState *s,
>                                     const MemMapEntry *memmap, int socket,
>                                     uint32_t *phandle, uint32_t *intc_phandles,
> @@ -352,7 +425,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
>
>          create_fdt_socket_memory(s, memmap, socket);
>
> -        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> +        if (s->have_aclint) {
> +            create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
> +        } else {
> +            create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> +        }
>
>          create_fdt_socket_plic(s, memmap, socket, phandle,
>              intc_phandles, xplic_phandles);
> @@ -722,6 +799,15 @@ static void virt_machine_init(MachineState *machine)
>              RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
>              RISCV_ACLINT_TIMEBASE_FREQ, true);
>
> +        /* Per-socket ACLINT SSWI */
> +        if (s->have_aclint) {
> +            riscv_aclint_swi_create(
> +                memmap[VIRT_ACLINT_SSWI].base +
> +                    i * memmap[VIRT_ACLINT_SSWI].size,
> +                memmap[VIRT_ACLINT_SSWI].size,
> +                base_hartid, hart_count, true);
> +        }
> +
>          /* Per-socket PLIC hart topology configuration string */
>          plic_hart_config_len =
>              (strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
> @@ -898,6 +984,22 @@ static void virt_machine_instance_init(Object *obj)
>  {
>  }
>
> +static bool virt_get_aclint(Object *obj, Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> +
> +    return s->have_aclint;
> +}
> +
> +static void virt_set_aclint(Object *obj, bool value, Error **errp)
> +{
> +    MachineState *ms = MACHINE(obj);
> +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> +
> +    s->have_aclint = value;
> +}
> +
>  static void virt_machine_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> @@ -913,6 +1015,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
>      mc->numa_mem_supported = true;
>
>      machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
> +
> +    object_class_property_add_bool(oc, "aclint", virt_get_aclint,
> +                                   virt_set_aclint);
> +    object_class_property_set_description(oc, "aclint",
> +                                          "Set on/off to enable/disable "
> +                                          "emulating ACLINT devices");
>  }
>
>  static const TypeInfo virt_machine_typeinfo = {
> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> index 349fee1f89..d9105c1886 100644
> --- a/include/hw/riscv/virt.h
> +++ b/include/hw/riscv/virt.h
> @@ -43,6 +43,7 @@ struct RISCVVirtState {
>      FWCfgState *fw_cfg;
>
>      int fdt_size;
> +    bool have_aclint;
>  };
>
>  enum {
> @@ -51,6 +52,7 @@ enum {
>      VIRT_TEST,
>      VIRT_RTC,
>      VIRT_CLINT,
> +    VIRT_ACLINT_SSWI,
>      VIRT_PLIC,
>      VIRT_UART0,
>      VIRT_VIRTIO,

Regards,
Bin


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  2021-06-12 16:06   ` Anup Patel
@ 2021-06-18  6:50     ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-18  6:50 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sun, Jun 13, 2021 at 2:09 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> The RISC-V ACLINT is more modular and backward compatible with
> original SiFive CLINT so instead of duplicating the orignal
> SiFive CLINT implementation we upgrade the current SiFive CLINT
> implementation to RISC-V ACLINT implementation.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/intc/Kconfig                |   2 +-
>  hw/intc/meson.build            |   2 +-
>  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
>  hw/intc/sifive_clint.c         | 266 -----------------------
>  hw/riscv/Kconfig               |  10 +-
>  hw/riscv/microchip_pfsoc.c     |  12 +-
>  hw/riscv/sifive_e.c            |  12 +-
>  hw/riscv/sifive_u.c            |  14 +-
>  hw/riscv/spike.c               |  15 +-
>  hw/riscv/virt.c                |  15 +-
>  include/hw/intc/riscv_aclint.h |  73 +++++++
>  include/hw/intc/sifive_clint.h |  60 ------
>  12 files changed, 494 insertions(+), 361 deletions(-)
>  create mode 100644 hw/intc/riscv_aclint.c
>  delete mode 100644 hw/intc/sifive_clint.c
>  create mode 100644 include/hw/intc/riscv_aclint.h
>  delete mode 100644 include/hw/intc/sifive_clint.h

Could we split this patch into 2? One to rename the file and a second
to add the new implementation? Otherwise there might be a git config
to change file rename detection as this is hard to see the changes.

>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index f4694088a4..78aed93c45 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,7 +62,7 @@ config RX_ICU
>  config LOONGSON_LIOINTC
>      bool
>
> -config SIFIVE_CLINT
> +config RISCV_ACLINT
>      bool
>
>  config SIFIVE_PLIC
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 1c299039f6..2482fcfaf8 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
>  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
>  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
>  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
>  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> new file mode 100644
> index 0000000000..682f95cca7
> --- /dev/null
> +++ b/hw/intc/riscv_aclint.c
> @@ -0,0 +1,374 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor)
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This provides real-time clock, timer and interprocessor interrupts.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "qemu/module.h"
> +#include "hw/sysbus.h"
> +#include "target/riscv/cpu.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/intc/riscv_aclint.h"
> +#include "qemu/timer.h"
> +
> +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> +{
> +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +        timebase_freq, NANOSECONDS_PER_SECOND);
> +}
> +
> +/*
> + * Called when timecmp is written to update the QEMU timer or immediately
> + * trigger timer interrupt if mtimecmp <= current timer value.
> + */
> +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> +    uint32_t timebase_freq)
> +{
> +    uint64_t next;
> +    uint64_t diff;
> +
> +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> +
> +    cpu->env.timecmp = value;
> +    if (cpu->env.timecmp <= rtc_r) {
> +        /* if we're setting an MTIMECMP value in the "past",
> +           immediately raise the timer interrupt */
> +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +        return;
> +    }
> +
> +    /* otherwise, set up the future timer interrupt */
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> +    diff = cpu->env.timecmp - rtc_r;
> +    /* back to ns (note args switched in muldiv64) */
> +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> +    timer_mod(cpu->env.timer, next);
> +}
> +
> +/*
> + * Callback used when the timer set using timer_mod expires.
> + * Should raise the timer interrupt line
> + */
> +static void riscv_aclint_mtimer_cb(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +}
> +
> +/* CPU wants to read MTIMER register */
> +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp = env->timecmp;
> +            return timecmp & 0xFFFFFFFF;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp = env->timecmp;
> +            return (timecmp >> 32) & 0xFFFFFFFF;
> +        } else {
> +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +            return 0;
> +        }
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> +    }
> +
> +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote MTIMER register */
> +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> +    uint64_t value, unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp_hi = env->timecmp >> 32;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +            return;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp_lo = env->timecmp;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +        } else {
> +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> +                         (uint32_t)addr);
> +        }
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        error_report("aclint-mtimer: time_lo write not implemented");
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        error_report("aclint-mtimer: time_hi write not implemented");
> +        return;
> +    }
> +
> +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> +    .read = riscv_aclint_mtimer_read,
> +    .write = riscv_aclint_mtimer_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8
> +    }
> +};
> +
> +static Property riscv_aclint_mtimer_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> +        hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> +        aperture_size, 0),
> +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> +        timebase_freq, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim MTIP so that only MTIMER controls it. */
> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> +            error_report("MTIP already claimed");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_mtimer_realize;
> +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_mtimer_info = {
> +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintMTimerState),
> +    .class_init    = riscv_aclint_mtimer_class_init,
> +};
> +
> +/*
> + * Create ACLINT MTIMER device.
> + */
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime)
> +{
> +    int i;
> +    for (i = 0; i < num_harts; i++) {
> +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            continue;
> +        }
> +        if (provide_rdtime) {
> +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> +        }
> +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                  &riscv_aclint_mtimer_cb, cpu);
> +        env->timecmp = 0;
> +    }
> +
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +/* CPU read [M|S]SWI register */
> +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            return (env->mip & swi->sirq_mask) > 0;
> +        } else {
> +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +            return 0;

We can drop this and just fall through.

> +        }
> +    }
> +
> +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote [M|S]SWI register */
> +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> +        unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> +                                 BOOL_TO_MASK(value));
> +        } else {
> +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> +                         (uint32_t)addr);

Same here

> +        }
> +        return;
> +    }
> +
> +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_swi_ops = {
> +    .read = riscv_aclint_swi_read,
> +    .write = riscv_aclint_swi_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4
> +    }
> +};
> +
> +static Property riscv_aclint_swi_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> +        aperture_size, 0),
> +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim [M|S]SIP so that can SWI controls it. */
> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +
> +        /* We don't claim SSIP bit of mip CSR because this bit is
> +         * writable by software as-per RISC-V privilege specification.
> +         */
> +        if ((s->sirq_mask != MIP_SSIP) &&
> +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> +            error_report("%s already claimed",
> +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_swi_realize;
> +    device_class_set_props(dc, riscv_aclint_swi_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_swi_info = {
> +    .name          = TYPE_RISCV_ACLINT_SWI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintSwiState),
> +    .class_init    = riscv_aclint_swi_class_init,
> +};
> +
> +/*
> + * Create ACLINT [M|S]SWI device.
> + */
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> +{
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +static void riscv_aclint_register_types(void)
> +{
> +    type_register_static(&riscv_aclint_mtimer_info);
> +    type_register_static(&riscv_aclint_swi_info);
> +}
> +
> +type_init(riscv_aclint_register_types)
> diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> deleted file mode 100644
> index 0f41e5ea1c..0000000000
> --- a/hw/intc/sifive_clint.c
> +++ /dev/null
> @@ -1,266 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor)
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This provides real-time clock, timer and interprocessor interrupts.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "qemu/osdep.h"
> -#include "qapi/error.h"
> -#include "qemu/error-report.h"
> -#include "qemu/module.h"
> -#include "hw/sysbus.h"
> -#include "target/riscv/cpu.h"
> -#include "hw/qdev-properties.h"
> -#include "hw/intc/sifive_clint.h"
> -#include "qemu/timer.h"
> -
> -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> -{
> -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> -        timebase_freq, NANOSECONDS_PER_SECOND);
> -}
> -
> -/*
> - * Called when timecmp is written to update the QEMU timer or immediately
> - * trigger timer interrupt if mtimecmp <= current timer value.
> - */
> -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> -                                       uint32_t timebase_freq)
> -{
> -    uint64_t next;
> -    uint64_t diff;
> -
> -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> -
> -    cpu->env.timecmp = value;
> -    if (cpu->env.timecmp <= rtc_r) {
> -        /* if we're setting an MTIMECMP value in the "past",
> -           immediately raise the timer interrupt */
> -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -        return;
> -    }
> -
> -    /* otherwise, set up the future timer interrupt */
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> -    diff = cpu->env.timecmp - rtc_r;
> -    /* back to ns (note args switched in muldiv64) */
> -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> -    timer_mod(cpu->env.timer, next);
> -}
> -
> -/*
> - * Callback used when the timer set using timer_mod expires.
> - * Should raise the timer interrupt line
> - */
> -static void sifive_clint_timer_cb(void *opaque)
> -{
> -    RISCVCPU *cpu = opaque;
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -}
> -
> -/* CPU wants to read rtc or timecmp register */
> -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            return (env->mip & MIP_MSIP) > 0;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp = env->timecmp;
> -            return timecmp & 0xFFFFFFFF;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp = env->timecmp;
> -            return (timecmp >> 32) & 0xFFFFFFFF;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> -    }
> -
> -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> -    return 0;
> -}
> -
> -/* CPU wrote to rtc or timecmp register */
> -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> -        unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> -        } else {
> -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp_hi = env->timecmp >> 32;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> -            return;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp_lo = env->timecmp;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> -        } else {
> -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        error_report("clint: time_lo write not implemented");
> -        return;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        error_report("clint: time_hi write not implemented");
> -        return;
> -    }
> -
> -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> -}
> -
> -static const MemoryRegionOps sifive_clint_ops = {
> -    .read = sifive_clint_read,
> -    .write = sifive_clint_write,
> -    .endianness = DEVICE_LITTLE_ENDIAN,
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 8
> -    }
> -};
> -
> -static Property sifive_clint_properties[] = {
> -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> -    DEFINE_PROP_END_OF_LIST(),
> -};
> -
> -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> -{
> -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> -}
> -
> -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    dc->realize = sifive_clint_realize;
> -    device_class_set_props(dc, sifive_clint_properties);
> -}
> -
> -static const TypeInfo sifive_clint_info = {
> -    .name          = TYPE_SIFIVE_CLINT,
> -    .parent        = TYPE_SYS_BUS_DEVICE,
> -    .instance_size = sizeof(SiFiveCLINTState),
> -    .class_init    = sifive_clint_class_init,
> -};
> -
> -static void sifive_clint_register_types(void)
> -{
> -    type_register_static(&sifive_clint_info);
> -}
> -
> -type_init(sifive_clint_register_types)
> -
> -
> -/*
> - * Create CLINT device.
> - */
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime)
> -{
> -    int i;
> -    for (i = 0; i < num_harts; i++) {
> -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            continue;
> -        }
> -        if (provide_rdtime) {
> -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> -        }
> -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> -                                  &sifive_clint_timer_cb, cpu);
> -        env->timecmp = 0;
> -    }
> -
> -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> -    qdev_prop_set_uint32(dev, "time-base", time_base);
> -    qdev_prop_set_uint32(dev, "aperture-size", size);
> -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> -    return dev;
> -}
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 1de18cdcf1..939cd0ef40 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
>      select MCHP_PFSOC_MMUART
>      select MCHP_PFSOC_SYSREG
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
>      select UNIMP
> @@ -29,7 +29,7 @@ config RISCV_VIRT
>      select PCI_EXPRESS_GENERIC_BRIDGE
>      select PFLASH_CFI01
>      select SERIAL
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PLIC
>      select SIFIVE_TEST
>      select VIRTIO_MMIO
> @@ -38,7 +38,7 @@ config RISCV_VIRT
>  config SIFIVE_E
>      bool
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PLIC
>      select SIFIVE_UART
> @@ -49,7 +49,7 @@ config SIFIVE_U
>      bool
>      select CADENCE
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
> @@ -65,5 +65,5 @@ config SPIKE
>      bool
>      select HTIF
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PLIC
> diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> index c4146b7a6b..e637e5c885 100644
> --- a/hw/riscv/microchip_pfsoc.c
> +++ b/hw/riscv/microchip_pfsoc.c
> @@ -51,7 +51,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/riscv_hart.h"
>  #include "hw/riscv/microchip_pfsoc.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "sysemu/sysemu.h"
>
> @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
>          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
>
>      /* CLINT */
> -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(
> +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      /* L2 cache controller */
>      create_unimplemented_device("microchip.pfsoc.l2cc",
> diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> index f939bcf9ea..ea960a5f2e 100644
> --- a/hw/riscv/sifive_e.c
> +++ b/hw/riscv/sifive_e.c
> @@ -42,7 +42,7 @@
>  #include "hw/riscv/sifive_e.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_e_prci.h"
>  #include "chardev/char.h"
> @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
>          SIFIVE_E_PLIC_CONTEXT_BASE,
>          SIFIVE_E_PLIC_CONTEXT_STRIDE,
>          memmap[SIFIVE_E_DEV_PLIC].size);
> -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>      create_unimplemented_device("riscv.sifive.e.aon",
>          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
>      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> index 7b59942369..e5fe681984 100644
> --- a/hw/riscv/sifive_u.c
> +++ b/hw/riscv/sifive_u.c
> @@ -52,7 +52,7 @@
>  #include "hw/riscv/sifive_u.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "chardev/char.h"
>  #include "net/eth.h"
> @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>
> @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
>          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
>      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
>          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
>          return;
> diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> index ec7cb2f707..10681fbf99 100644
> --- a/hw/riscv/spike.c
> +++ b/hw/riscv/spike.c
> @@ -36,7 +36,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
>  #include "hw/char/riscv_htif.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "chardev/char.h"
>  #include "sysemu/arch_init.h"
>  #include "sysemu/device_tree.h"
> @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Core Local Interruptor (timer and IPI) for each socket */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, false);
>      }
>
>      /* register system main memory (actual RAM) */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c0dc69ff33..5eb63f6efd 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -33,7 +33,7 @@
>  #include "hw/riscv/virt.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_test.h"
>  #include "chardev/char.h"
> @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> +                          RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Per-socket CLINT */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, true);
>
>          /* Per-socket PLIC hart topology configuration string */
>          plic_hart_config_len =
> diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> new file mode 100644
> index 0000000000..471a5ffd0b
> --- /dev/null
> +++ b/include/hw/intc/riscv_aclint.h
> @@ -0,0 +1,73 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_RISCV_ACLINT_H
> +#define HW_RISCV_ACLINT_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> +
> +#define RISCV_ACLINT_MTIMER(obj) \
> +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> +
> +typedef struct RISCVAclintMTimerState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t timebase_freq;
> +} RISCVAclintMTimerState;
> +
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime);
> +
> +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> +
> +#define RISCV_ACLINT_SWI(obj) \
> +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> +
> +typedef struct RISCVAclintSwiState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t sirq_mask;
> +} RISCVAclintSwiState;
> +
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> +
> +enum {
> +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> +    RISCV_ACLINT_SWI_SIZE = 0x4000
> +};
> +
> +#endif
> diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> deleted file mode 100644
> index a30be0f3d6..0000000000
> --- a/include/hw/intc/sifive_clint.h
> +++ /dev/null
> @@ -1,60 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor) interface
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef HW_SIFIVE_CLINT_H
> -#define HW_SIFIVE_CLINT_H
> -
> -#include "hw/sysbus.h"
> -
> -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> -
> -#define SIFIVE_CLINT(obj) \
> -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> -
> -typedef struct SiFiveCLINTState {
> -    /*< private >*/
> -    SysBusDevice parent_obj;
> -
> -    /*< public >*/
> -    MemoryRegion mmio;
> -    uint32_t hartid_base;
> -    uint32_t num_harts;
> -    uint32_t sip_base;
> -    uint32_t timecmp_base;
> -    uint32_t time_base;
> -    uint32_t aperture_size;
> -    uint32_t timebase_freq;
> -} SiFiveCLINTState;
> -
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime);
> -
> -enum {
> -    SIFIVE_SIP_BASE     = 0x0,
> -    SIFIVE_TIMECMP_BASE = 0x4000,
> -    SIFIVE_TIME_BASE    = 0xBFF8
> -};
> -
> -enum {
> -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> -};
> -
> -#endif
> --
> 2.25.1
>
>


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
@ 2021-06-18  6:50     ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-18  6:50 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sun, Jun 13, 2021 at 2:09 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> The RISC-V ACLINT is more modular and backward compatible with
> original SiFive CLINT so instead of duplicating the orignal
> SiFive CLINT implementation we upgrade the current SiFive CLINT
> implementation to RISC-V ACLINT implementation.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  hw/intc/Kconfig                |   2 +-
>  hw/intc/meson.build            |   2 +-
>  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
>  hw/intc/sifive_clint.c         | 266 -----------------------
>  hw/riscv/Kconfig               |  10 +-
>  hw/riscv/microchip_pfsoc.c     |  12 +-
>  hw/riscv/sifive_e.c            |  12 +-
>  hw/riscv/sifive_u.c            |  14 +-
>  hw/riscv/spike.c               |  15 +-
>  hw/riscv/virt.c                |  15 +-
>  include/hw/intc/riscv_aclint.h |  73 +++++++
>  include/hw/intc/sifive_clint.h |  60 ------
>  12 files changed, 494 insertions(+), 361 deletions(-)
>  create mode 100644 hw/intc/riscv_aclint.c
>  delete mode 100644 hw/intc/sifive_clint.c
>  create mode 100644 include/hw/intc/riscv_aclint.h
>  delete mode 100644 include/hw/intc/sifive_clint.h

Could we split this patch into 2? One to rename the file and a second
to add the new implementation? Otherwise there might be a git config
to change file rename detection as this is hard to see the changes.

>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index f4694088a4..78aed93c45 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -62,7 +62,7 @@ config RX_ICU
>  config LOONGSON_LIOINTC
>      bool
>
> -config SIFIVE_CLINT
> +config RISCV_ACLINT
>      bool
>
>  config SIFIVE_PLIC
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 1c299039f6..2482fcfaf8 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
>  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
>  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
>  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
>  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
>  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> new file mode 100644
> index 0000000000..682f95cca7
> --- /dev/null
> +++ b/hw/intc/riscv_aclint.c
> @@ -0,0 +1,374 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor)
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This provides real-time clock, timer and interprocessor interrupts.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "qemu/module.h"
> +#include "hw/sysbus.h"
> +#include "target/riscv/cpu.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/intc/riscv_aclint.h"
> +#include "qemu/timer.h"
> +
> +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> +{
> +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> +        timebase_freq, NANOSECONDS_PER_SECOND);
> +}
> +
> +/*
> + * Called when timecmp is written to update the QEMU timer or immediately
> + * trigger timer interrupt if mtimecmp <= current timer value.
> + */
> +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> +    uint32_t timebase_freq)
> +{
> +    uint64_t next;
> +    uint64_t diff;
> +
> +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> +
> +    cpu->env.timecmp = value;
> +    if (cpu->env.timecmp <= rtc_r) {
> +        /* if we're setting an MTIMECMP value in the "past",
> +           immediately raise the timer interrupt */
> +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +        return;
> +    }
> +
> +    /* otherwise, set up the future timer interrupt */
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> +    diff = cpu->env.timecmp - rtc_r;
> +    /* back to ns (note args switched in muldiv64) */
> +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> +    timer_mod(cpu->env.timer, next);
> +}
> +
> +/*
> + * Callback used when the timer set using timer_mod expires.
> + * Should raise the timer interrupt line
> + */
> +static void riscv_aclint_mtimer_cb(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> +}
> +
> +/* CPU wants to read MTIMER register */
> +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp = env->timecmp;
> +            return timecmp & 0xFFFFFFFF;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp = env->timecmp;
> +            return (timecmp >> 32) & 0xFFFFFFFF;
> +        } else {
> +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +            return 0;
> +        }
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> +    }
> +
> +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote MTIMER register */
> +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> +    uint64_t value, unsigned size)
> +{
> +    RISCVAclintMTimerState *mtimer = opaque;
> +
> +    if (addr < (mtimer->num_harts << 3)) {
> +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x7) == 0) {
> +            /* timecmp_lo */
> +            uint64_t timecmp_hi = env->timecmp >> 32;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +            return;
> +        } else if ((addr & 0x7) == 4) {
> +            /* timecmp_hi */
> +            uint64_t timecmp_lo = env->timecmp;
> +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> +                mtimer->timebase_freq);
> +        } else {
> +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> +                         (uint32_t)addr);
> +        }
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 8)) {
> +        /* time_lo */
> +        error_report("aclint-mtimer: time_lo write not implemented");
> +        return;
> +    } else if (addr == (mtimer->aperture_size - 4)) {
> +        /* time_hi */
> +        error_report("aclint-mtimer: time_hi write not implemented");
> +        return;
> +    }
> +
> +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> +    .read = riscv_aclint_mtimer_read,
> +    .write = riscv_aclint_mtimer_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8
> +    }
> +};
> +
> +static Property riscv_aclint_mtimer_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> +        hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> +        aperture_size, 0),
> +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> +        timebase_freq, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim MTIP so that only MTIMER controls it. */
> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> +            error_report("MTIP already claimed");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_mtimer_realize;
> +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_mtimer_info = {
> +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintMTimerState),
> +    .class_init    = riscv_aclint_mtimer_class_init,
> +};
> +
> +/*
> + * Create ACLINT MTIMER device.
> + */
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime)
> +{
> +    int i;
> +    for (i = 0; i < num_harts; i++) {
> +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            continue;
> +        }
> +        if (provide_rdtime) {
> +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> +        }
> +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                  &riscv_aclint_mtimer_cb, cpu);
> +        env->timecmp = 0;
> +    }
> +
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +/* CPU read [M|S]SWI register */
> +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> +    unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            return (env->mip & swi->sirq_mask) > 0;
> +        } else {
> +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +            return 0;

We can drop this and just fall through.

> +        }
> +    }
> +
> +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> +    return 0;
> +}
> +
> +/* CPU wrote [M|S]SWI register */
> +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> +        unsigned size)
> +{
> +    RISCVAclintSwiState *swi = opaque;
> +
> +    if (addr < (swi->num_harts << 2)) {
> +        size_t hartid = swi->hartid_base + (addr >> 2);
> +        CPUState *cpu = qemu_get_cpu(hartid);
> +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> +        if (!env) {
> +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> +        } else if ((addr & 0x3) == 0) {
> +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> +                                 BOOL_TO_MASK(value));
> +        } else {
> +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> +                         (uint32_t)addr);

Same here

> +        }
> +        return;
> +    }
> +
> +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> +}
> +
> +static const MemoryRegionOps riscv_aclint_swi_ops = {
> +    .read = riscv_aclint_swi_read,
> +    .write = riscv_aclint_swi_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4
> +    }
> +};
> +
> +static Property riscv_aclint_swi_properties[] = {
> +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
> +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> +        aperture_size, 0),
> +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> +{
> +    int i;
> +    RISCVCPU *cpu;
> +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> +
> +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> +
> +    /* Claim [M|S]SIP so that can SWI controls it. */
> +    for (i = 0; i < s->num_harts; i++) {
> +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> +
> +        /* We don't claim SSIP bit of mip CSR because this bit is
> +         * writable by software as-per RISC-V privilege specification.
> +         */
> +        if ((s->sirq_mask != MIP_SSIP) &&
> +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> +            error_report("%s already claimed",
> +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> +            exit(1);
> +        }
> +    }
> +}
> +
> +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    dc->realize = riscv_aclint_swi_realize;
> +    device_class_set_props(dc, riscv_aclint_swi_properties);
> +}
> +
> +static const TypeInfo riscv_aclint_swi_info = {
> +    .name          = TYPE_RISCV_ACLINT_SWI,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(RISCVAclintSwiState),
> +    .class_init    = riscv_aclint_swi_class_init,
> +};
> +
> +/*
> + * Create ACLINT [M|S]SWI device.
> + */
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> +{
> +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> +    qdev_prop_set_uint32(dev, "aperture-size", size);
> +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> +    return dev;
> +}
> +
> +static void riscv_aclint_register_types(void)
> +{
> +    type_register_static(&riscv_aclint_mtimer_info);
> +    type_register_static(&riscv_aclint_swi_info);
> +}
> +
> +type_init(riscv_aclint_register_types)
> diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> deleted file mode 100644
> index 0f41e5ea1c..0000000000
> --- a/hw/intc/sifive_clint.c
> +++ /dev/null
> @@ -1,266 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor)
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This provides real-time clock, timer and interprocessor interrupts.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "qemu/osdep.h"
> -#include "qapi/error.h"
> -#include "qemu/error-report.h"
> -#include "qemu/module.h"
> -#include "hw/sysbus.h"
> -#include "target/riscv/cpu.h"
> -#include "hw/qdev-properties.h"
> -#include "hw/intc/sifive_clint.h"
> -#include "qemu/timer.h"
> -
> -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> -{
> -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> -        timebase_freq, NANOSECONDS_PER_SECOND);
> -}
> -
> -/*
> - * Called when timecmp is written to update the QEMU timer or immediately
> - * trigger timer interrupt if mtimecmp <= current timer value.
> - */
> -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> -                                       uint32_t timebase_freq)
> -{
> -    uint64_t next;
> -    uint64_t diff;
> -
> -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> -
> -    cpu->env.timecmp = value;
> -    if (cpu->env.timecmp <= rtc_r) {
> -        /* if we're setting an MTIMECMP value in the "past",
> -           immediately raise the timer interrupt */
> -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -        return;
> -    }
> -
> -    /* otherwise, set up the future timer interrupt */
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> -    diff = cpu->env.timecmp - rtc_r;
> -    /* back to ns (note args switched in muldiv64) */
> -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> -    timer_mod(cpu->env.timer, next);
> -}
> -
> -/*
> - * Callback used when the timer set using timer_mod expires.
> - * Should raise the timer interrupt line
> - */
> -static void sifive_clint_timer_cb(void *opaque)
> -{
> -    RISCVCPU *cpu = opaque;
> -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> -}
> -
> -/* CPU wants to read rtc or timecmp register */
> -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            return (env->mip & MIP_MSIP) > 0;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp = env->timecmp;
> -            return timecmp & 0xFFFFFFFF;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp = env->timecmp;
> -            return (timecmp >> 32) & 0xFFFFFFFF;
> -        } else {
> -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> -            return 0;
> -        }
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> -    }
> -
> -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> -    return 0;
> -}
> -
> -/* CPU wrote to rtc or timecmp register */
> -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> -        unsigned size)
> -{
> -    SiFiveCLINTState *clint = opaque;
> -
> -    if (addr >= clint->sip_base &&
> -        addr < clint->sip_base + (clint->num_harts << 2)) {
> -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x3) == 0) {
> -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> -        } else {
> -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr >= clint->timecmp_base &&
> -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> -        size_t hartid = clint->hartid_base +
> -            ((addr - clint->timecmp_base) >> 3);
> -        CPUState *cpu = qemu_get_cpu(hartid);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> -        } else if ((addr & 0x7) == 0) {
> -            /* timecmp_lo */
> -            uint64_t timecmp_hi = env->timecmp >> 32;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> -            return;
> -        } else if ((addr & 0x7) == 4) {
> -            /* timecmp_hi */
> -            uint64_t timecmp_lo = env->timecmp;
> -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> -        } else {
> -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> -        }
> -        return;
> -    } else if (addr == clint->time_base) {
> -        /* time_lo */
> -        error_report("clint: time_lo write not implemented");
> -        return;
> -    } else if (addr == clint->time_base + 4) {
> -        /* time_hi */
> -        error_report("clint: time_hi write not implemented");
> -        return;
> -    }
> -
> -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> -}
> -
> -static const MemoryRegionOps sifive_clint_ops = {
> -    .read = sifive_clint_read,
> -    .write = sifive_clint_write,
> -    .endianness = DEVICE_LITTLE_ENDIAN,
> -    .valid = {
> -        .min_access_size = 4,
> -        .max_access_size = 8
> -    }
> -};
> -
> -static Property sifive_clint_properties[] = {
> -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> -    DEFINE_PROP_END_OF_LIST(),
> -};
> -
> -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> -{
> -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> -}
> -
> -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    dc->realize = sifive_clint_realize;
> -    device_class_set_props(dc, sifive_clint_properties);
> -}
> -
> -static const TypeInfo sifive_clint_info = {
> -    .name          = TYPE_SIFIVE_CLINT,
> -    .parent        = TYPE_SYS_BUS_DEVICE,
> -    .instance_size = sizeof(SiFiveCLINTState),
> -    .class_init    = sifive_clint_class_init,
> -};
> -
> -static void sifive_clint_register_types(void)
> -{
> -    type_register_static(&sifive_clint_info);
> -}
> -
> -type_init(sifive_clint_register_types)
> -
> -
> -/*
> - * Create CLINT device.
> - */
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime)
> -{
> -    int i;
> -    for (i = 0; i < num_harts; i++) {
> -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> -        if (!env) {
> -            continue;
> -        }
> -        if (provide_rdtime) {
> -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> -        }
> -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> -                                  &sifive_clint_timer_cb, cpu);
> -        env->timecmp = 0;
> -    }
> -
> -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> -    qdev_prop_set_uint32(dev, "time-base", time_base);
> -    qdev_prop_set_uint32(dev, "aperture-size", size);
> -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> -    return dev;
> -}
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 1de18cdcf1..939cd0ef40 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
>      select MCHP_PFSOC_MMUART
>      select MCHP_PFSOC_SYSREG
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
>      select UNIMP
> @@ -29,7 +29,7 @@ config RISCV_VIRT
>      select PCI_EXPRESS_GENERIC_BRIDGE
>      select PFLASH_CFI01
>      select SERIAL
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PLIC
>      select SIFIVE_TEST
>      select VIRTIO_MMIO
> @@ -38,7 +38,7 @@ config RISCV_VIRT
>  config SIFIVE_E
>      bool
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PLIC
>      select SIFIVE_UART
> @@ -49,7 +49,7 @@ config SIFIVE_U
>      bool
>      select CADENCE
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_GPIO
>      select SIFIVE_PDMA
>      select SIFIVE_PLIC
> @@ -65,5 +65,5 @@ config SPIKE
>      bool
>      select HTIF
>      select MSI_NONBROKEN
> -    select SIFIVE_CLINT
> +    select RISCV_ACLINT
>      select SIFIVE_PLIC
> diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> index c4146b7a6b..e637e5c885 100644
> --- a/hw/riscv/microchip_pfsoc.c
> +++ b/hw/riscv/microchip_pfsoc.c
> @@ -51,7 +51,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/riscv_hart.h"
>  #include "hw/riscv/microchip_pfsoc.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "sysemu/sysemu.h"
>
> @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
>          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
>
>      /* CLINT */
> -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(
> +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      /* L2 cache controller */
>      create_unimplemented_device("microchip.pfsoc.l2cc",
> diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> index f939bcf9ea..ea960a5f2e 100644
> --- a/hw/riscv/sifive_e.c
> +++ b/hw/riscv/sifive_e.c
> @@ -42,7 +42,7 @@
>  #include "hw/riscv/sifive_e.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_e_prci.h"
>  #include "chardev/char.h"
> @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
>          SIFIVE_E_PLIC_CONTEXT_BASE,
>          SIFIVE_E_PLIC_CONTEXT_STRIDE,
>          memmap[SIFIVE_E_DEV_PLIC].size);
> -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>      create_unimplemented_device("riscv.sifive.e.aon",
>          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
>      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> index 7b59942369..e5fe681984 100644
> --- a/hw/riscv/sifive_u.c
> +++ b/hw/riscv/sifive_u.c
> @@ -52,7 +52,7 @@
>  #include "hw/riscv/sifive_u.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/char/sifive_uart.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "chardev/char.h"
>  #include "net/eth.h"
> @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>
> @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
>          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
>      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
>          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> +            RISCV_ACLINT_SWI_SIZE,
> +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> +        RISCV_ACLINT_TIMEBASE_FREQ, false);
>
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
>          return;
> diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> index ec7cb2f707..10681fbf99 100644
> --- a/hw/riscv/spike.c
> +++ b/hw/riscv/spike.c
> @@ -36,7 +36,7 @@
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
>  #include "hw/char/riscv_htif.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "chardev/char.h"
>  #include "sysemu/arch_init.h"
>  #include "sysemu/device_tree.h"
> @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -        SIFIVE_CLINT_TIMEBASE_FREQ);
> +        RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Core Local Interruptor (timer and IPI) for each socket */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, false);
>      }
>
>      /* register system main memory (actual RAM) */
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c0dc69ff33..5eb63f6efd 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -33,7 +33,7 @@
>  #include "hw/riscv/virt.h"
>  #include "hw/riscv/boot.h"
>  #include "hw/riscv/numa.h"
> -#include "hw/intc/sifive_clint.h"
> +#include "hw/intc/riscv_aclint.h"
>  #include "hw/intc/sifive_plic.h"
>  #include "hw/misc/sifive_test.h"
>  #include "chardev/char.h"
> @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>
>      qemu_fdt_add_subnode(fdt, "/cpus");
>      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> +                          RISCV_ACLINT_TIMEBASE_FREQ);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
>      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
>      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
>          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
>
>          /* Per-socket CLINT */
> -        sifive_clint_create(
> +        riscv_aclint_swi_create(
>              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> +        riscv_aclint_mtimer_create(
> +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> +                RISCV_ACLINT_SWI_SIZE,
> +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> +            RISCV_ACLINT_TIMEBASE_FREQ, true);
>
>          /* Per-socket PLIC hart topology configuration string */
>          plic_hart_config_len =
> diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> new file mode 100644
> index 0000000000..471a5ffd0b
> --- /dev/null
> +++ b/include/hw/intc/riscv_aclint.h
> @@ -0,0 +1,73 @@
> +/*
> + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> + *
> + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> + * Copyright (c) 2017 SiFive, Inc.
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_RISCV_ACLINT_H
> +#define HW_RISCV_ACLINT_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> +
> +#define RISCV_ACLINT_MTIMER(obj) \
> +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> +
> +typedef struct RISCVAclintMTimerState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t timebase_freq;
> +} RISCVAclintMTimerState;
> +
> +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> +    bool provide_rdtime);
> +
> +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> +
> +#define RISCV_ACLINT_SWI(obj) \
> +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> +
> +typedef struct RISCVAclintSwiState {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion mmio;
> +    uint32_t hartid_base;
> +    uint32_t num_harts;
> +    uint32_t aperture_size;
> +    uint32_t sirq_mask;
> +} RISCVAclintSwiState;
> +
> +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> +
> +enum {
> +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> +    RISCV_ACLINT_SWI_SIZE = 0x4000
> +};
> +
> +#endif
> diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> deleted file mode 100644
> index a30be0f3d6..0000000000
> --- a/include/hw/intc/sifive_clint.h
> +++ /dev/null
> @@ -1,60 +0,0 @@
> -/*
> - * SiFive CLINT (Core Local Interruptor) interface
> - *
> - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> - * Copyright (c) 2017 SiFive, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify it
> - * under the terms and conditions of the GNU General Public License,
> - * version 2 or later, as published by the Free Software Foundation.
> - *
> - * This program is distributed in the hope it will be useful, but WITHOUT
> - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> - * more details.
> - *
> - * You should have received a copy of the GNU General Public License along with
> - * this program.  If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef HW_SIFIVE_CLINT_H
> -#define HW_SIFIVE_CLINT_H
> -
> -#include "hw/sysbus.h"
> -
> -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> -
> -#define SIFIVE_CLINT(obj) \
> -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> -
> -typedef struct SiFiveCLINTState {
> -    /*< private >*/
> -    SysBusDevice parent_obj;
> -
> -    /*< public >*/
> -    MemoryRegion mmio;
> -    uint32_t hartid_base;
> -    uint32_t num_harts;
> -    uint32_t sip_base;
> -    uint32_t timecmp_base;
> -    uint32_t time_base;
> -    uint32_t aperture_size;
> -    uint32_t timebase_freq;
> -} SiFiveCLINTState;
> -
> -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> -    bool provide_rdtime);
> -
> -enum {
> -    SIFIVE_SIP_BASE     = 0x0,
> -    SIFIVE_TIMECMP_BASE = 0x4000,
> -    SIFIVE_TIME_BASE    = 0xBFF8
> -};
> -
> -enum {
> -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> -};
> -
> -#endif
> --
> 2.25.1
>
>


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  2021-06-14 12:22     ` Bin Meng
@ 2021-07-12  5:00       ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:00 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 12:08 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > The RISC-V ACLINT is more modular and backward compatible with
> > original SiFive CLINT so instead of duplicating the orignal
> > SiFive CLINT implementation we upgrade the current SiFive CLINT
> > implementation to RISC-V ACLINT implementation.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/intc/Kconfig                |   2 +-
> >  hw/intc/meson.build            |   2 +-
> >  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
> >  hw/intc/sifive_clint.c         | 266 -----------------------
> >  hw/riscv/Kconfig               |  10 +-
> >  hw/riscv/microchip_pfsoc.c     |  12 +-
> >  hw/riscv/sifive_e.c            |  12 +-
> >  hw/riscv/sifive_u.c            |  14 +-
> >  hw/riscv/spike.c               |  15 +-
> >  hw/riscv/virt.c                |  15 +-
> >  include/hw/intc/riscv_aclint.h |  73 +++++++
> >  include/hw/intc/sifive_clint.h |  60 ------
> >  12 files changed, 494 insertions(+), 361 deletions(-)
> >  create mode 100644 hw/intc/riscv_aclint.c
> >  delete mode 100644 hw/intc/sifive_clint.c
> >  create mode 100644 include/hw/intc/riscv_aclint.h
> >  delete mode 100644 include/hw/intc/sifive_clint.h
> >
> > diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> > index f4694088a4..78aed93c45 100644
> > --- a/hw/intc/Kconfig
> > +++ b/hw/intc/Kconfig
> > @@ -62,7 +62,7 @@ config RX_ICU
> >  config LOONGSON_LIOINTC
> >      bool
> >
> > -config SIFIVE_CLINT
> > +config RISCV_ACLINT
> >      bool
> >
> >  config SIFIVE_PLIC
> > diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> > index 1c299039f6..2482fcfaf8 100644
> > --- a/hw/intc/meson.build
> > +++ b/hw/intc/meson.build
> > @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
> >  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> > -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> > +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
> >  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
> >  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
> >  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> > diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> > new file mode 100644
> > index 0000000000..682f95cca7
> > --- /dev/null
> > +++ b/hw/intc/riscv_aclint.c
> > @@ -0,0 +1,374 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor)
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This provides real-time clock, timer and interprocessor interrupts.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/error.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/module.h"
> > +#include "hw/sysbus.h"
> > +#include "target/riscv/cpu.h"
> > +#include "hw/qdev-properties.h"
> > +#include "hw/intc/riscv_aclint.h"
> > +#include "qemu/timer.h"
> > +
> > +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > +{
> > +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > +        timebase_freq, NANOSECONDS_PER_SECOND);
> > +}
> > +
> > +/*
> > + * Called when timecmp is written to update the QEMU timer or immediately
> > + * trigger timer interrupt if mtimecmp <= current timer value.
> > + */
> > +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > +    uint32_t timebase_freq)
> > +{
> > +    uint64_t next;
> > +    uint64_t diff;
> > +
> > +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > +
> > +    cpu->env.timecmp = value;
> > +    if (cpu->env.timecmp <= rtc_r) {
> > +        /* if we're setting an MTIMECMP value in the "past",
> > +           immediately raise the timer interrupt */
>
> nits: please use correct multi-line comment format

Okay, will update.

>
> > +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +        return;
> > +    }
> > +
> > +    /* otherwise, set up the future timer interrupt */
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > +    diff = cpu->env.timecmp - rtc_r;
> > +    /* back to ns (note args switched in muldiv64) */
> > +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > +    timer_mod(cpu->env.timer, next);
> > +}
> > +
> > +/*
> > + * Callback used when the timer set using timer_mod expires.
> > + * Should raise the timer interrupt line
> > + */
> > +static void riscv_aclint_mtimer_cb(void *opaque)
> > +{
> > +    RISCVCPU *cpu = opaque;
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +}
> > +
> > +/* CPU wants to read MTIMER register */
>
> nits: CPU read MTIMER register (for consistency with other RW routines)

Okay, will update.

>
> > +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp = env->timecmp;
> > +            return timecmp & 0xFFFFFFFF;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp = env->timecmp;
> > +            return (timecmp >> 32) & 0xFFFFFFFF;
> > +        } else {
> > +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
> > +        }
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote MTIMER register */
>
> nits: write

Okay, will update.

>
> > +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> > +    uint64_t value, unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp_hi = env->timecmp >> 32;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +            return;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp_lo = env->timecmp;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +        } else {
> > +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> > +                         (uint32_t)addr);
> > +        }
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        error_report("aclint-mtimer: time_lo write not implemented");
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        error_report("aclint-mtimer: time_hi write not implemented");
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> > +    .read = riscv_aclint_mtimer_read,
> > +    .write = riscv_aclint_mtimer_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 8
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_mtimer_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> > +        hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
>
> I guess we can set the default value to 4095 according to the spec?

Better to have default as 1 because a RISC-V platform will have at least
1 hart.

>
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> > +        aperture_size, 0),
>
> I don't think this parameter is needed given the spec clearly defines its size.

Based on recent discussion on AIA mailing list, people want more flexibility
to place MTIME register anywhere they want without sacrificing backward
compatibility with SiFive CLINT so we will end-up with separate base address
for MTIMECMPx registers and MTIME register which means the ACLINT
MTIMER device will not have fixed size hence we will require aperture_size
for the ACLINT MTIMER.

The ACLINT MSWI and SSWI will remain fixed size supporting upto 4095
HARTs so for these devices we don't need aperture_size.

>
> > +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> > +        timebase_freq, 0),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> > +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim MTIP so that only MTIMER controls it. */
>
> nits: please remove the ending .

Okay, will update.

>
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> > +            error_report("MTIP already claimed");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_mtimer_realize;
> > +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_mtimer_info = {
> > +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintMTimerState),
> > +    .class_init    = riscv_aclint_mtimer_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT MTIMER device.
> > + */
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime)
> > +{
> > +    int i;
> > +    for (i = 0; i < num_harts; i++) {
> > +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            continue;
> > +        }
> > +        if (provide_rdtime) {
> > +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > +        }
> > +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > +                                  &riscv_aclint_mtimer_cb, cpu);
> > +        env->timecmp = 0;
> > +    }
> > +
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +/* CPU read [M|S]SWI register */
> > +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            return (env->mip & swi->sirq_mask) > 0;
> > +        } else {
> > +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
> > +        }
> > +    }
> > +
> > +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote [M|S]SWI register */
>
> write

Okay, will update.

>
> > +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> > +        unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> > +                                 BOOL_TO_MASK(value));
> > +        } else {
> > +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> > +                         (uint32_t)addr);
> > +        }
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_swi_ops = {
> > +    .read = riscv_aclint_swi_read,
> > +    .write = riscv_aclint_swi_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 4
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_swi_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
>
> ditto

We should use default value as 1 hart.

>
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> > +        aperture_size, 0),
>
> ditto

Yes, this one can be removed.

>
> > +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
>
> Could be more intuitive if we describe it as:
>
> DEFINE_PROP_BOOL("sswi", RISCVAclintSwiState, sswi, false)
>
> so we don't bother user to pass the mask of the MIP register

Okay, I will simplify this.

>
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> > +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim [M|S]SIP so that can SWI controls it. */
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +
> > +        /* We don't claim SSIP bit of mip CSR because this bit is
> > +         * writable by software as-per RISC-V privilege specification.
> > +         */
>
> nits: please use correct multi-line comment format

okay, will update.

>
> > +        if ((s->sirq_mask != MIP_SSIP) &&
> > +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> > +            error_report("%s already claimed",
> > +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_swi_realize;
> > +    device_class_set_props(dc, riscv_aclint_swi_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_swi_info = {
> > +    .name          = TYPE_RISCV_ACLINT_SWI,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintSwiState),
> > +    .class_init    = riscv_aclint_swi_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT [M|S]SWI device.
> > + */
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> > +{
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +static void riscv_aclint_register_types(void)
> > +{
> > +    type_register_static(&riscv_aclint_mtimer_info);
> > +    type_register_static(&riscv_aclint_swi_info);
> > +}
> > +
> > +type_init(riscv_aclint_register_types)
> > diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> > deleted file mode 100644
> > index 0f41e5ea1c..0000000000
> > --- a/hw/intc/sifive_clint.c
> > +++ /dev/null
> > @@ -1,266 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor)
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This provides real-time clock, timer and interprocessor interrupts.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#include "qemu/osdep.h"
> > -#include "qapi/error.h"
> > -#include "qemu/error-report.h"
> > -#include "qemu/module.h"
> > -#include "hw/sysbus.h"
> > -#include "target/riscv/cpu.h"
> > -#include "hw/qdev-properties.h"
> > -#include "hw/intc/sifive_clint.h"
> > -#include "qemu/timer.h"
> > -
> > -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > -{
> > -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > -        timebase_freq, NANOSECONDS_PER_SECOND);
> > -}
> > -
> > -/*
> > - * Called when timecmp is written to update the QEMU timer or immediately
> > - * trigger timer interrupt if mtimecmp <= current timer value.
> > - */
> > -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > -                                       uint32_t timebase_freq)
> > -{
> > -    uint64_t next;
> > -    uint64_t diff;
> > -
> > -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > -
> > -    cpu->env.timecmp = value;
> > -    if (cpu->env.timecmp <= rtc_r) {
> > -        /* if we're setting an MTIMECMP value in the "past",
> > -           immediately raise the timer interrupt */
> > -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -        return;
> > -    }
> > -
> > -    /* otherwise, set up the future timer interrupt */
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > -    diff = cpu->env.timecmp - rtc_r;
> > -    /* back to ns (note args switched in muldiv64) */
> > -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > -    timer_mod(cpu->env.timer, next);
> > -}
> > -
> > -/*
> > - * Callback used when the timer set using timer_mod expires.
> > - * Should raise the timer interrupt line
> > - */
> > -static void sifive_clint_timer_cb(void *opaque)
> > -{
> > -    RISCVCPU *cpu = opaque;
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -}
> > -
> > -/* CPU wants to read rtc or timecmp register */
> > -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            return (env->mip & MIP_MSIP) > 0;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp = env->timecmp;
> > -            return timecmp & 0xFFFFFFFF;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp = env->timecmp;
> > -            return (timecmp >> 32) & 0xFFFFFFFF;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> > -    }
> > -
> > -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -    return 0;
> > -}
> > -
> > -/* CPU wrote to rtc or timecmp register */
> > -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> > -        unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> > -        } else {
> > -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp_hi = env->timecmp >> 32;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> > -            return;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp_lo = env->timecmp;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> > -        } else {
> > -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        error_report("clint: time_lo write not implemented");
> > -        return;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        error_report("clint: time_hi write not implemented");
> > -        return;
> > -    }
> > -
> > -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> > -}
> > -
> > -static const MemoryRegionOps sifive_clint_ops = {
> > -    .read = sifive_clint_read,
> > -    .write = sifive_clint_write,
> > -    .endianness = DEVICE_LITTLE_ENDIAN,
> > -    .valid = {
> > -        .min_access_size = 4,
> > -        .max_access_size = 8
> > -    }
> > -};
> > -
> > -static Property sifive_clint_properties[] = {
> > -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> > -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> > -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> > -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> > -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> > -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> > -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> > -    DEFINE_PROP_END_OF_LIST(),
> > -};
> > -
> > -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> > -{
> > -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> > -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> > -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> > -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > -}
> > -
> > -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> > -{
> > -    DeviceClass *dc = DEVICE_CLASS(klass);
> > -    dc->realize = sifive_clint_realize;
> > -    device_class_set_props(dc, sifive_clint_properties);
> > -}
> > -
> > -static const TypeInfo sifive_clint_info = {
> > -    .name          = TYPE_SIFIVE_CLINT,
> > -    .parent        = TYPE_SYS_BUS_DEVICE,
> > -    .instance_size = sizeof(SiFiveCLINTState),
> > -    .class_init    = sifive_clint_class_init,
> > -};
> > -
> > -static void sifive_clint_register_types(void)
> > -{
> > -    type_register_static(&sifive_clint_info);
> > -}
> > -
> > -type_init(sifive_clint_register_types)
> > -
> > -
> > -/*
> > - * Create CLINT device.
> > - */
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime)
> > -{
> > -    int i;
> > -    for (i = 0; i < num_harts; i++) {
> > -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            continue;
> > -        }
> > -        if (provide_rdtime) {
> > -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > -        }
> > -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > -                                  &sifive_clint_timer_cb, cpu);
> > -        env->timecmp = 0;
> > -    }
> > -
> > -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> > -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> > -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> > -    qdev_prop_set_uint32(dev, "time-base", time_base);
> > -    qdev_prop_set_uint32(dev, "aperture-size", size);
> > -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > -    return dev;
> > -}
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 1de18cdcf1..939cd0ef40 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
> >      select MCHP_PFSOC_MMUART
> >      select MCHP_PFSOC_SYSREG
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> >      select UNIMP
> > @@ -29,7 +29,7 @@ config RISCV_VIRT
> >      select PCI_EXPRESS_GENERIC_BRIDGE
> >      select PFLASH_CFI01
> >      select SERIAL
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
>
> nits: please insert this by following the alphabetical order
>
> >      select SIFIVE_PLIC
> >      select SIFIVE_TEST
> >      select VIRTIO_MMIO
> > @@ -38,7 +38,7 @@ config RISCV_VIRT
> >  config SIFIVE_E
> >      bool
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PLIC
> >      select SIFIVE_UART
> > @@ -49,7 +49,7 @@ config SIFIVE_U
> >      bool
> >      select CADENCE
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> > @@ -65,5 +65,5 @@ config SPIKE
> >      bool
> >      select HTIF
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PLIC
> > diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> > index c4146b7a6b..e637e5c885 100644
> > --- a/hw/riscv/microchip_pfsoc.c
> > +++ b/hw/riscv/microchip_pfsoc.c
> > @@ -51,7 +51,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/riscv_hart.h"
> >  #include "hw/riscv/microchip_pfsoc.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "sysemu/sysemu.h"
> >
> > @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
> >          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
> >
> >      /* CLINT */
> > -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(
> > +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      /* L2 cache controller */
> >      create_unimplemented_device("microchip.pfsoc.l2cc",
> > diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> > index f939bcf9ea..ea960a5f2e 100644
> > --- a/hw/riscv/sifive_e.c
> > +++ b/hw/riscv/sifive_e.c
> > @@ -42,7 +42,7 @@
> >  #include "hw/riscv/sifive_e.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_e_prci.h"
> >  #include "chardev/char.h"
> > @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> >          SIFIVE_E_PLIC_CONTEXT_BASE,
> >          SIFIVE_E_PLIC_CONTEXT_STRIDE,
> >          memmap[SIFIVE_E_DEV_PLIC].size);
> > -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      create_unimplemented_device("riscv.sifive.e.aon",
> >          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
> >      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> > diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> > index 7b59942369..e5fe681984 100644
> > --- a/hw/riscv/sifive_u.c
> > +++ b/hw/riscv/sifive_u.c
> > @@ -52,7 +52,7 @@
> >  #include "hw/riscv/sifive_u.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "chardev/char.h"
> >  #include "net/eth.h"
> > @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >
> > @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
> >          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
> >      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
> >          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> > -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
> >          return;
> > diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> > index ec7cb2f707..10681fbf99 100644
> > --- a/hw/riscv/spike.c
> > +++ b/hw/riscv/spike.c
> > @@ -36,7 +36,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> >  #include "hw/char/riscv_htif.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "chardev/char.h"
> >  #include "sysemu/arch_init.h"
> >  #include "sysemu/device_tree.h"
> > @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Core Local Interruptor (timer and IPI) for each socket */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> > -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      }
> >
> >      /* register system main memory (actual RAM) */
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index c0dc69ff33..5eb63f6efd 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -33,7 +33,7 @@
> >  #include "hw/riscv/virt.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_test.h"
> >  #include "chardev/char.h"
> > @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> > +                          RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Per-socket CLINT */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> > -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, true);
> >
> >          /* Per-socket PLIC hart topology configuration string */
> >          plic_hart_config_len =
> > diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> > new file mode 100644
> > index 0000000000..471a5ffd0b
> > --- /dev/null
> > +++ b/include/hw/intc/riscv_aclint.h
> > @@ -0,0 +1,73 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#ifndef HW_RISCV_ACLINT_H
> > +#define HW_RISCV_ACLINT_H
> > +
> > +#include "hw/sysbus.h"
> > +
> > +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> > +
> > +#define RISCV_ACLINT_MTIMER(obj) \
> > +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> > +
> > +typedef struct RISCVAclintMTimerState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t timebase_freq;
> > +} RISCVAclintMTimerState;
> > +
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime);
> > +
> > +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> > +
> > +#define RISCV_ACLINT_SWI(obj) \
> > +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> > +
> > +typedef struct RISCVAclintSwiState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t sirq_mask;
> > +} RISCVAclintSwiState;
> > +
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> > +
> > +enum {
> > +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> > +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> > +    RISCV_ACLINT_SWI_SIZE = 0x4000
> > +};
> > +
> > +#endif
> > diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> > deleted file mode 100644
> > index a30be0f3d6..0000000000
> > --- a/include/hw/intc/sifive_clint.h
> > +++ /dev/null
> > @@ -1,60 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor) interface
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#ifndef HW_SIFIVE_CLINT_H
> > -#define HW_SIFIVE_CLINT_H
> > -
> > -#include "hw/sysbus.h"
> > -
> > -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> > -
> > -#define SIFIVE_CLINT(obj) \
> > -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> > -
> > -typedef struct SiFiveCLINTState {
> > -    /*< private >*/
> > -    SysBusDevice parent_obj;
> > -
> > -    /*< public >*/
> > -    MemoryRegion mmio;
> > -    uint32_t hartid_base;
> > -    uint32_t num_harts;
> > -    uint32_t sip_base;
> > -    uint32_t timecmp_base;
> > -    uint32_t time_base;
> > -    uint32_t aperture_size;
> > -    uint32_t timebase_freq;
> > -} SiFiveCLINTState;
> > -
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime);
> > -
> > -enum {
> > -    SIFIVE_SIP_BASE     = 0x0,
> > -    SIFIVE_TIMECMP_BASE = 0x4000,
> > -    SIFIVE_TIME_BASE    = 0xBFF8
> > -};
> > -
> > -enum {
> > -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> > -};
> > -
> > -#endif
>
> Regards,
> Bin

Regards,
Anup


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
@ 2021-07-12  5:00       ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:00 UTC (permalink / raw)
  To: Bin Meng
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 12:08 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > The RISC-V ACLINT is more modular and backward compatible with
> > original SiFive CLINT so instead of duplicating the orignal
> > SiFive CLINT implementation we upgrade the current SiFive CLINT
> > implementation to RISC-V ACLINT implementation.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/intc/Kconfig                |   2 +-
> >  hw/intc/meson.build            |   2 +-
> >  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
> >  hw/intc/sifive_clint.c         | 266 -----------------------
> >  hw/riscv/Kconfig               |  10 +-
> >  hw/riscv/microchip_pfsoc.c     |  12 +-
> >  hw/riscv/sifive_e.c            |  12 +-
> >  hw/riscv/sifive_u.c            |  14 +-
> >  hw/riscv/spike.c               |  15 +-
> >  hw/riscv/virt.c                |  15 +-
> >  include/hw/intc/riscv_aclint.h |  73 +++++++
> >  include/hw/intc/sifive_clint.h |  60 ------
> >  12 files changed, 494 insertions(+), 361 deletions(-)
> >  create mode 100644 hw/intc/riscv_aclint.c
> >  delete mode 100644 hw/intc/sifive_clint.c
> >  create mode 100644 include/hw/intc/riscv_aclint.h
> >  delete mode 100644 include/hw/intc/sifive_clint.h
> >
> > diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> > index f4694088a4..78aed93c45 100644
> > --- a/hw/intc/Kconfig
> > +++ b/hw/intc/Kconfig
> > @@ -62,7 +62,7 @@ config RX_ICU
> >  config LOONGSON_LIOINTC
> >      bool
> >
> > -config SIFIVE_CLINT
> > +config RISCV_ACLINT
> >      bool
> >
> >  config SIFIVE_PLIC
> > diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> > index 1c299039f6..2482fcfaf8 100644
> > --- a/hw/intc/meson.build
> > +++ b/hw/intc/meson.build
> > @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
> >  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> > -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> > +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
> >  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
> >  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
> >  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> > diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> > new file mode 100644
> > index 0000000000..682f95cca7
> > --- /dev/null
> > +++ b/hw/intc/riscv_aclint.c
> > @@ -0,0 +1,374 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor)
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This provides real-time clock, timer and interprocessor interrupts.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/error.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/module.h"
> > +#include "hw/sysbus.h"
> > +#include "target/riscv/cpu.h"
> > +#include "hw/qdev-properties.h"
> > +#include "hw/intc/riscv_aclint.h"
> > +#include "qemu/timer.h"
> > +
> > +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > +{
> > +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > +        timebase_freq, NANOSECONDS_PER_SECOND);
> > +}
> > +
> > +/*
> > + * Called when timecmp is written to update the QEMU timer or immediately
> > + * trigger timer interrupt if mtimecmp <= current timer value.
> > + */
> > +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > +    uint32_t timebase_freq)
> > +{
> > +    uint64_t next;
> > +    uint64_t diff;
> > +
> > +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > +
> > +    cpu->env.timecmp = value;
> > +    if (cpu->env.timecmp <= rtc_r) {
> > +        /* if we're setting an MTIMECMP value in the "past",
> > +           immediately raise the timer interrupt */
>
> nits: please use correct multi-line comment format

Okay, will update.

>
> > +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +        return;
> > +    }
> > +
> > +    /* otherwise, set up the future timer interrupt */
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > +    diff = cpu->env.timecmp - rtc_r;
> > +    /* back to ns (note args switched in muldiv64) */
> > +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > +    timer_mod(cpu->env.timer, next);
> > +}
> > +
> > +/*
> > + * Callback used when the timer set using timer_mod expires.
> > + * Should raise the timer interrupt line
> > + */
> > +static void riscv_aclint_mtimer_cb(void *opaque)
> > +{
> > +    RISCVCPU *cpu = opaque;
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +}
> > +
> > +/* CPU wants to read MTIMER register */
>
> nits: CPU read MTIMER register (for consistency with other RW routines)

Okay, will update.

>
> > +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp = env->timecmp;
> > +            return timecmp & 0xFFFFFFFF;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp = env->timecmp;
> > +            return (timecmp >> 32) & 0xFFFFFFFF;
> > +        } else {
> > +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
> > +        }
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote MTIMER register */
>
> nits: write

Okay, will update.

>
> > +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> > +    uint64_t value, unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp_hi = env->timecmp >> 32;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +            return;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp_lo = env->timecmp;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +        } else {
> > +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> > +                         (uint32_t)addr);
> > +        }
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        error_report("aclint-mtimer: time_lo write not implemented");
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        error_report("aclint-mtimer: time_hi write not implemented");
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> > +    .read = riscv_aclint_mtimer_read,
> > +    .write = riscv_aclint_mtimer_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 8
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_mtimer_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> > +        hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
>
> I guess we can set the default value to 4095 according to the spec?

Better to have default as 1 because a RISC-V platform will have at least
1 hart.

>
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> > +        aperture_size, 0),
>
> I don't think this parameter is needed given the spec clearly defines its size.

Based on recent discussion on AIA mailing list, people want more flexibility
to place MTIME register anywhere they want without sacrificing backward
compatibility with SiFive CLINT so we will end-up with separate base address
for MTIMECMPx registers and MTIME register which means the ACLINT
MTIMER device will not have fixed size hence we will require aperture_size
for the ACLINT MTIMER.

The ACLINT MSWI and SSWI will remain fixed size supporting upto 4095
HARTs so for these devices we don't need aperture_size.

>
> > +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> > +        timebase_freq, 0),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> > +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim MTIP so that only MTIMER controls it. */
>
> nits: please remove the ending .

Okay, will update.

>
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> > +            error_report("MTIP already claimed");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_mtimer_realize;
> > +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_mtimer_info = {
> > +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintMTimerState),
> > +    .class_init    = riscv_aclint_mtimer_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT MTIMER device.
> > + */
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime)
> > +{
> > +    int i;
> > +    for (i = 0; i < num_harts; i++) {
> > +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            continue;
> > +        }
> > +        if (provide_rdtime) {
> > +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > +        }
> > +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > +                                  &riscv_aclint_mtimer_cb, cpu);
> > +        env->timecmp = 0;
> > +    }
> > +
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +/* CPU read [M|S]SWI register */
> > +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            return (env->mip & swi->sirq_mask) > 0;
> > +        } else {
> > +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
> > +        }
> > +    }
> > +
> > +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote [M|S]SWI register */
>
> write

Okay, will update.

>
> > +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> > +        unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> > +                                 BOOL_TO_MASK(value));
> > +        } else {
> > +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> > +                         (uint32_t)addr);
> > +        }
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_swi_ops = {
> > +    .read = riscv_aclint_swi_read,
> > +    .write = riscv_aclint_swi_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 4
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_swi_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
>
> ditto

We should use default value as 1 hart.

>
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> > +        aperture_size, 0),
>
> ditto

Yes, this one can be removed.

>
> > +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
>
> Could be more intuitive if we describe it as:
>
> DEFINE_PROP_BOOL("sswi", RISCVAclintSwiState, sswi, false)
>
> so we don't bother user to pass the mask of the MIP register

Okay, I will simplify this.

>
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> > +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim [M|S]SIP so that can SWI controls it. */
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +
> > +        /* We don't claim SSIP bit of mip CSR because this bit is
> > +         * writable by software as-per RISC-V privilege specification.
> > +         */
>
> nits: please use correct multi-line comment format

okay, will update.

>
> > +        if ((s->sirq_mask != MIP_SSIP) &&
> > +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> > +            error_report("%s already claimed",
> > +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_swi_realize;
> > +    device_class_set_props(dc, riscv_aclint_swi_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_swi_info = {
> > +    .name          = TYPE_RISCV_ACLINT_SWI,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintSwiState),
> > +    .class_init    = riscv_aclint_swi_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT [M|S]SWI device.
> > + */
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> > +{
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +static void riscv_aclint_register_types(void)
> > +{
> > +    type_register_static(&riscv_aclint_mtimer_info);
> > +    type_register_static(&riscv_aclint_swi_info);
> > +}
> > +
> > +type_init(riscv_aclint_register_types)
> > diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> > deleted file mode 100644
> > index 0f41e5ea1c..0000000000
> > --- a/hw/intc/sifive_clint.c
> > +++ /dev/null
> > @@ -1,266 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor)
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This provides real-time clock, timer and interprocessor interrupts.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#include "qemu/osdep.h"
> > -#include "qapi/error.h"
> > -#include "qemu/error-report.h"
> > -#include "qemu/module.h"
> > -#include "hw/sysbus.h"
> > -#include "target/riscv/cpu.h"
> > -#include "hw/qdev-properties.h"
> > -#include "hw/intc/sifive_clint.h"
> > -#include "qemu/timer.h"
> > -
> > -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > -{
> > -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > -        timebase_freq, NANOSECONDS_PER_SECOND);
> > -}
> > -
> > -/*
> > - * Called when timecmp is written to update the QEMU timer or immediately
> > - * trigger timer interrupt if mtimecmp <= current timer value.
> > - */
> > -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > -                                       uint32_t timebase_freq)
> > -{
> > -    uint64_t next;
> > -    uint64_t diff;
> > -
> > -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > -
> > -    cpu->env.timecmp = value;
> > -    if (cpu->env.timecmp <= rtc_r) {
> > -        /* if we're setting an MTIMECMP value in the "past",
> > -           immediately raise the timer interrupt */
> > -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -        return;
> > -    }
> > -
> > -    /* otherwise, set up the future timer interrupt */
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > -    diff = cpu->env.timecmp - rtc_r;
> > -    /* back to ns (note args switched in muldiv64) */
> > -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > -    timer_mod(cpu->env.timer, next);
> > -}
> > -
> > -/*
> > - * Callback used when the timer set using timer_mod expires.
> > - * Should raise the timer interrupt line
> > - */
> > -static void sifive_clint_timer_cb(void *opaque)
> > -{
> > -    RISCVCPU *cpu = opaque;
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -}
> > -
> > -/* CPU wants to read rtc or timecmp register */
> > -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            return (env->mip & MIP_MSIP) > 0;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp = env->timecmp;
> > -            return timecmp & 0xFFFFFFFF;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp = env->timecmp;
> > -            return (timecmp >> 32) & 0xFFFFFFFF;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> > -    }
> > -
> > -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -    return 0;
> > -}
> > -
> > -/* CPU wrote to rtc or timecmp register */
> > -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> > -        unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> > -        } else {
> > -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp_hi = env->timecmp >> 32;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> > -            return;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp_lo = env->timecmp;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> > -        } else {
> > -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        error_report("clint: time_lo write not implemented");
> > -        return;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        error_report("clint: time_hi write not implemented");
> > -        return;
> > -    }
> > -
> > -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> > -}
> > -
> > -static const MemoryRegionOps sifive_clint_ops = {
> > -    .read = sifive_clint_read,
> > -    .write = sifive_clint_write,
> > -    .endianness = DEVICE_LITTLE_ENDIAN,
> > -    .valid = {
> > -        .min_access_size = 4,
> > -        .max_access_size = 8
> > -    }
> > -};
> > -
> > -static Property sifive_clint_properties[] = {
> > -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> > -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> > -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> > -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> > -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> > -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> > -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> > -    DEFINE_PROP_END_OF_LIST(),
> > -};
> > -
> > -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> > -{
> > -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> > -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> > -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> > -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > -}
> > -
> > -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> > -{
> > -    DeviceClass *dc = DEVICE_CLASS(klass);
> > -    dc->realize = sifive_clint_realize;
> > -    device_class_set_props(dc, sifive_clint_properties);
> > -}
> > -
> > -static const TypeInfo sifive_clint_info = {
> > -    .name          = TYPE_SIFIVE_CLINT,
> > -    .parent        = TYPE_SYS_BUS_DEVICE,
> > -    .instance_size = sizeof(SiFiveCLINTState),
> > -    .class_init    = sifive_clint_class_init,
> > -};
> > -
> > -static void sifive_clint_register_types(void)
> > -{
> > -    type_register_static(&sifive_clint_info);
> > -}
> > -
> > -type_init(sifive_clint_register_types)
> > -
> > -
> > -/*
> > - * Create CLINT device.
> > - */
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime)
> > -{
> > -    int i;
> > -    for (i = 0; i < num_harts; i++) {
> > -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            continue;
> > -        }
> > -        if (provide_rdtime) {
> > -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > -        }
> > -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > -                                  &sifive_clint_timer_cb, cpu);
> > -        env->timecmp = 0;
> > -    }
> > -
> > -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> > -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> > -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> > -    qdev_prop_set_uint32(dev, "time-base", time_base);
> > -    qdev_prop_set_uint32(dev, "aperture-size", size);
> > -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > -    return dev;
> > -}
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 1de18cdcf1..939cd0ef40 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
> >      select MCHP_PFSOC_MMUART
> >      select MCHP_PFSOC_SYSREG
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> >      select UNIMP
> > @@ -29,7 +29,7 @@ config RISCV_VIRT
> >      select PCI_EXPRESS_GENERIC_BRIDGE
> >      select PFLASH_CFI01
> >      select SERIAL
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
>
> nits: please insert this by following the alphabetical order
>
> >      select SIFIVE_PLIC
> >      select SIFIVE_TEST
> >      select VIRTIO_MMIO
> > @@ -38,7 +38,7 @@ config RISCV_VIRT
> >  config SIFIVE_E
> >      bool
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PLIC
> >      select SIFIVE_UART
> > @@ -49,7 +49,7 @@ config SIFIVE_U
> >      bool
> >      select CADENCE
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> > @@ -65,5 +65,5 @@ config SPIKE
> >      bool
> >      select HTIF
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PLIC
> > diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> > index c4146b7a6b..e637e5c885 100644
> > --- a/hw/riscv/microchip_pfsoc.c
> > +++ b/hw/riscv/microchip_pfsoc.c
> > @@ -51,7 +51,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/riscv_hart.h"
> >  #include "hw/riscv/microchip_pfsoc.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "sysemu/sysemu.h"
> >
> > @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
> >          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
> >
> >      /* CLINT */
> > -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(
> > +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      /* L2 cache controller */
> >      create_unimplemented_device("microchip.pfsoc.l2cc",
> > diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> > index f939bcf9ea..ea960a5f2e 100644
> > --- a/hw/riscv/sifive_e.c
> > +++ b/hw/riscv/sifive_e.c
> > @@ -42,7 +42,7 @@
> >  #include "hw/riscv/sifive_e.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_e_prci.h"
> >  #include "chardev/char.h"
> > @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> >          SIFIVE_E_PLIC_CONTEXT_BASE,
> >          SIFIVE_E_PLIC_CONTEXT_STRIDE,
> >          memmap[SIFIVE_E_DEV_PLIC].size);
> > -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      create_unimplemented_device("riscv.sifive.e.aon",
> >          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
> >      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> > diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> > index 7b59942369..e5fe681984 100644
> > --- a/hw/riscv/sifive_u.c
> > +++ b/hw/riscv/sifive_u.c
> > @@ -52,7 +52,7 @@
> >  #include "hw/riscv/sifive_u.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "chardev/char.h"
> >  #include "net/eth.h"
> > @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >
> > @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
> >          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
> >      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
> >          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> > -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
> >          return;
> > diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> > index ec7cb2f707..10681fbf99 100644
> > --- a/hw/riscv/spike.c
> > +++ b/hw/riscv/spike.c
> > @@ -36,7 +36,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> >  #include "hw/char/riscv_htif.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "chardev/char.h"
> >  #include "sysemu/arch_init.h"
> >  #include "sysemu/device_tree.h"
> > @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Core Local Interruptor (timer and IPI) for each socket */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> > -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      }
> >
> >      /* register system main memory (actual RAM) */
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index c0dc69ff33..5eb63f6efd 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -33,7 +33,7 @@
> >  #include "hw/riscv/virt.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_test.h"
> >  #include "chardev/char.h"
> > @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> > +                          RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Per-socket CLINT */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> > -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, true);
> >
> >          /* Per-socket PLIC hart topology configuration string */
> >          plic_hart_config_len =
> > diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> > new file mode 100644
> > index 0000000000..471a5ffd0b
> > --- /dev/null
> > +++ b/include/hw/intc/riscv_aclint.h
> > @@ -0,0 +1,73 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#ifndef HW_RISCV_ACLINT_H
> > +#define HW_RISCV_ACLINT_H
> > +
> > +#include "hw/sysbus.h"
> > +
> > +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> > +
> > +#define RISCV_ACLINT_MTIMER(obj) \
> > +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> > +
> > +typedef struct RISCVAclintMTimerState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t timebase_freq;
> > +} RISCVAclintMTimerState;
> > +
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime);
> > +
> > +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> > +
> > +#define RISCV_ACLINT_SWI(obj) \
> > +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> > +
> > +typedef struct RISCVAclintSwiState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t sirq_mask;
> > +} RISCVAclintSwiState;
> > +
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> > +
> > +enum {
> > +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> > +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> > +    RISCV_ACLINT_SWI_SIZE = 0x4000
> > +};
> > +
> > +#endif
> > diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> > deleted file mode 100644
> > index a30be0f3d6..0000000000
> > --- a/include/hw/intc/sifive_clint.h
> > +++ /dev/null
> > @@ -1,60 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor) interface
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#ifndef HW_SIFIVE_CLINT_H
> > -#define HW_SIFIVE_CLINT_H
> > -
> > -#include "hw/sysbus.h"
> > -
> > -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> > -
> > -#define SIFIVE_CLINT(obj) \
> > -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> > -
> > -typedef struct SiFiveCLINTState {
> > -    /*< private >*/
> > -    SysBusDevice parent_obj;
> > -
> > -    /*< public >*/
> > -    MemoryRegion mmio;
> > -    uint32_t hartid_base;
> > -    uint32_t num_harts;
> > -    uint32_t sip_base;
> > -    uint32_t timecmp_base;
> > -    uint32_t time_base;
> > -    uint32_t aperture_size;
> > -    uint32_t timebase_freq;
> > -} SiFiveCLINTState;
> > -
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime);
> > -
> > -enum {
> > -    SIFIVE_SIP_BASE     = 0x0,
> > -    SIFIVE_TIMECMP_BASE = 0x4000,
> > -    SIFIVE_TIME_BASE    = 0xBFF8
> > -};
> > -
> > -enum {
> > -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> > -};
> > -
> > -#endif
>
> Regards,
> Bin

Regards,
Anup


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
  2021-06-18  6:50     ` Alistair Francis
@ 2021-07-12  5:32       ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:32 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Fri, Jun 18, 2021 at 12:20 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 2:09 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > The RISC-V ACLINT is more modular and backward compatible with
> > original SiFive CLINT so instead of duplicating the orignal
> > SiFive CLINT implementation we upgrade the current SiFive CLINT
> > implementation to RISC-V ACLINT implementation.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/intc/Kconfig                |   2 +-
> >  hw/intc/meson.build            |   2 +-
> >  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
> >  hw/intc/sifive_clint.c         | 266 -----------------------
> >  hw/riscv/Kconfig               |  10 +-
> >  hw/riscv/microchip_pfsoc.c     |  12 +-
> >  hw/riscv/sifive_e.c            |  12 +-
> >  hw/riscv/sifive_u.c            |  14 +-
> >  hw/riscv/spike.c               |  15 +-
> >  hw/riscv/virt.c                |  15 +-
> >  include/hw/intc/riscv_aclint.h |  73 +++++++
> >  include/hw/intc/sifive_clint.h |  60 ------
> >  12 files changed, 494 insertions(+), 361 deletions(-)
> >  create mode 100644 hw/intc/riscv_aclint.c
> >  delete mode 100644 hw/intc/sifive_clint.c
> >  create mode 100644 include/hw/intc/riscv_aclint.h
> >  delete mode 100644 include/hw/intc/sifive_clint.h
>
> Could we split this patch into 2? One to rename the file and a second
> to add the new implementation? Otherwise there might be a git config
> to change file rename detection as this is hard to see the changes.

Sure, I will split this patch into two patches.

>
> >
> > diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> > index f4694088a4..78aed93c45 100644
> > --- a/hw/intc/Kconfig
> > +++ b/hw/intc/Kconfig
> > @@ -62,7 +62,7 @@ config RX_ICU
> >  config LOONGSON_LIOINTC
> >      bool
> >
> > -config SIFIVE_CLINT
> > +config RISCV_ACLINT
> >      bool
> >
> >  config SIFIVE_PLIC
> > diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> > index 1c299039f6..2482fcfaf8 100644
> > --- a/hw/intc/meson.build
> > +++ b/hw/intc/meson.build
> > @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
> >  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> > -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> > +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
> >  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
> >  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
> >  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> > diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> > new file mode 100644
> > index 0000000000..682f95cca7
> > --- /dev/null
> > +++ b/hw/intc/riscv_aclint.c
> > @@ -0,0 +1,374 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor)
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This provides real-time clock, timer and interprocessor interrupts.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/error.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/module.h"
> > +#include "hw/sysbus.h"
> > +#include "target/riscv/cpu.h"
> > +#include "hw/qdev-properties.h"
> > +#include "hw/intc/riscv_aclint.h"
> > +#include "qemu/timer.h"
> > +
> > +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > +{
> > +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > +        timebase_freq, NANOSECONDS_PER_SECOND);
> > +}
> > +
> > +/*
> > + * Called when timecmp is written to update the QEMU timer or immediately
> > + * trigger timer interrupt if mtimecmp <= current timer value.
> > + */
> > +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > +    uint32_t timebase_freq)
> > +{
> > +    uint64_t next;
> > +    uint64_t diff;
> > +
> > +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > +
> > +    cpu->env.timecmp = value;
> > +    if (cpu->env.timecmp <= rtc_r) {
> > +        /* if we're setting an MTIMECMP value in the "past",
> > +           immediately raise the timer interrupt */
> > +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +        return;
> > +    }
> > +
> > +    /* otherwise, set up the future timer interrupt */
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > +    diff = cpu->env.timecmp - rtc_r;
> > +    /* back to ns (note args switched in muldiv64) */
> > +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > +    timer_mod(cpu->env.timer, next);
> > +}
> > +
> > +/*
> > + * Callback used when the timer set using timer_mod expires.
> > + * Should raise the timer interrupt line
> > + */
> > +static void riscv_aclint_mtimer_cb(void *opaque)
> > +{
> > +    RISCVCPU *cpu = opaque;
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +}
> > +
> > +/* CPU wants to read MTIMER register */
> > +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp = env->timecmp;
> > +            return timecmp & 0xFFFFFFFF;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp = env->timecmp;
> > +            return (timecmp >> 32) & 0xFFFFFFFF;
> > +        } else {
> > +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
> > +        }
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote MTIMER register */
> > +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> > +    uint64_t value, unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp_hi = env->timecmp >> 32;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +            return;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp_lo = env->timecmp;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +        } else {
> > +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> > +                         (uint32_t)addr);
> > +        }
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        error_report("aclint-mtimer: time_lo write not implemented");
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        error_report("aclint-mtimer: time_hi write not implemented");
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> > +    .read = riscv_aclint_mtimer_read,
> > +    .write = riscv_aclint_mtimer_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 8
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_mtimer_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> > +        hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> > +        aperture_size, 0),
> > +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> > +        timebase_freq, 0),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> > +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim MTIP so that only MTIMER controls it. */
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> > +            error_report("MTIP already claimed");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_mtimer_realize;
> > +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_mtimer_info = {
> > +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintMTimerState),
> > +    .class_init    = riscv_aclint_mtimer_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT MTIMER device.
> > + */
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime)
> > +{
> > +    int i;
> > +    for (i = 0; i < num_harts; i++) {
> > +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            continue;
> > +        }
> > +        if (provide_rdtime) {
> > +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > +        }
> > +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > +                                  &riscv_aclint_mtimer_cb, cpu);
> > +        env->timecmp = 0;
> > +    }
> > +
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +/* CPU read [M|S]SWI register */
> > +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            return (env->mip & swi->sirq_mask) > 0;
> > +        } else {
> > +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
>
> We can drop this and just fall through.

Okay, will update.

>
> > +        }
> > +    }
> > +
> > +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote [M|S]SWI register */
> > +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> > +        unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> > +                                 BOOL_TO_MASK(value));
> > +        } else {
> > +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> > +                         (uint32_t)addr);
>
> Same here

Okay, will update.

>
> > +        }
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_swi_ops = {
> > +    .read = riscv_aclint_swi_read,
> > +    .write = riscv_aclint_swi_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 4
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_swi_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> > +        aperture_size, 0),
> > +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> > +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim [M|S]SIP so that can SWI controls it. */
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +
> > +        /* We don't claim SSIP bit of mip CSR because this bit is
> > +         * writable by software as-per RISC-V privilege specification.
> > +         */
> > +        if ((s->sirq_mask != MIP_SSIP) &&
> > +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> > +            error_report("%s already claimed",
> > +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_swi_realize;
> > +    device_class_set_props(dc, riscv_aclint_swi_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_swi_info = {
> > +    .name          = TYPE_RISCV_ACLINT_SWI,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintSwiState),
> > +    .class_init    = riscv_aclint_swi_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT [M|S]SWI device.
> > + */
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> > +{
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +static void riscv_aclint_register_types(void)
> > +{
> > +    type_register_static(&riscv_aclint_mtimer_info);
> > +    type_register_static(&riscv_aclint_swi_info);
> > +}
> > +
> > +type_init(riscv_aclint_register_types)
> > diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> > deleted file mode 100644
> > index 0f41e5ea1c..0000000000
> > --- a/hw/intc/sifive_clint.c
> > +++ /dev/null
> > @@ -1,266 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor)
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This provides real-time clock, timer and interprocessor interrupts.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#include "qemu/osdep.h"
> > -#include "qapi/error.h"
> > -#include "qemu/error-report.h"
> > -#include "qemu/module.h"
> > -#include "hw/sysbus.h"
> > -#include "target/riscv/cpu.h"
> > -#include "hw/qdev-properties.h"
> > -#include "hw/intc/sifive_clint.h"
> > -#include "qemu/timer.h"
> > -
> > -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > -{
> > -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > -        timebase_freq, NANOSECONDS_PER_SECOND);
> > -}
> > -
> > -/*
> > - * Called when timecmp is written to update the QEMU timer or immediately
> > - * trigger timer interrupt if mtimecmp <= current timer value.
> > - */
> > -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > -                                       uint32_t timebase_freq)
> > -{
> > -    uint64_t next;
> > -    uint64_t diff;
> > -
> > -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > -
> > -    cpu->env.timecmp = value;
> > -    if (cpu->env.timecmp <= rtc_r) {
> > -        /* if we're setting an MTIMECMP value in the "past",
> > -           immediately raise the timer interrupt */
> > -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -        return;
> > -    }
> > -
> > -    /* otherwise, set up the future timer interrupt */
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > -    diff = cpu->env.timecmp - rtc_r;
> > -    /* back to ns (note args switched in muldiv64) */
> > -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > -    timer_mod(cpu->env.timer, next);
> > -}
> > -
> > -/*
> > - * Callback used when the timer set using timer_mod expires.
> > - * Should raise the timer interrupt line
> > - */
> > -static void sifive_clint_timer_cb(void *opaque)
> > -{
> > -    RISCVCPU *cpu = opaque;
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -}
> > -
> > -/* CPU wants to read rtc or timecmp register */
> > -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            return (env->mip & MIP_MSIP) > 0;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp = env->timecmp;
> > -            return timecmp & 0xFFFFFFFF;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp = env->timecmp;
> > -            return (timecmp >> 32) & 0xFFFFFFFF;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> > -    }
> > -
> > -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -    return 0;
> > -}
> > -
> > -/* CPU wrote to rtc or timecmp register */
> > -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> > -        unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> > -        } else {
> > -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp_hi = env->timecmp >> 32;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> > -            return;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp_lo = env->timecmp;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> > -        } else {
> > -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        error_report("clint: time_lo write not implemented");
> > -        return;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        error_report("clint: time_hi write not implemented");
> > -        return;
> > -    }
> > -
> > -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> > -}
> > -
> > -static const MemoryRegionOps sifive_clint_ops = {
> > -    .read = sifive_clint_read,
> > -    .write = sifive_clint_write,
> > -    .endianness = DEVICE_LITTLE_ENDIAN,
> > -    .valid = {
> > -        .min_access_size = 4,
> > -        .max_access_size = 8
> > -    }
> > -};
> > -
> > -static Property sifive_clint_properties[] = {
> > -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> > -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> > -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> > -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> > -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> > -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> > -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> > -    DEFINE_PROP_END_OF_LIST(),
> > -};
> > -
> > -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> > -{
> > -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> > -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> > -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> > -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > -}
> > -
> > -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> > -{
> > -    DeviceClass *dc = DEVICE_CLASS(klass);
> > -    dc->realize = sifive_clint_realize;
> > -    device_class_set_props(dc, sifive_clint_properties);
> > -}
> > -
> > -static const TypeInfo sifive_clint_info = {
> > -    .name          = TYPE_SIFIVE_CLINT,
> > -    .parent        = TYPE_SYS_BUS_DEVICE,
> > -    .instance_size = sizeof(SiFiveCLINTState),
> > -    .class_init    = sifive_clint_class_init,
> > -};
> > -
> > -static void sifive_clint_register_types(void)
> > -{
> > -    type_register_static(&sifive_clint_info);
> > -}
> > -
> > -type_init(sifive_clint_register_types)
> > -
> > -
> > -/*
> > - * Create CLINT device.
> > - */
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime)
> > -{
> > -    int i;
> > -    for (i = 0; i < num_harts; i++) {
> > -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            continue;
> > -        }
> > -        if (provide_rdtime) {
> > -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > -        }
> > -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > -                                  &sifive_clint_timer_cb, cpu);
> > -        env->timecmp = 0;
> > -    }
> > -
> > -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> > -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> > -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> > -    qdev_prop_set_uint32(dev, "time-base", time_base);
> > -    qdev_prop_set_uint32(dev, "aperture-size", size);
> > -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > -    return dev;
> > -}
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 1de18cdcf1..939cd0ef40 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
> >      select MCHP_PFSOC_MMUART
> >      select MCHP_PFSOC_SYSREG
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> >      select UNIMP
> > @@ -29,7 +29,7 @@ config RISCV_VIRT
> >      select PCI_EXPRESS_GENERIC_BRIDGE
> >      select PFLASH_CFI01
> >      select SERIAL
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PLIC
> >      select SIFIVE_TEST
> >      select VIRTIO_MMIO
> > @@ -38,7 +38,7 @@ config RISCV_VIRT
> >  config SIFIVE_E
> >      bool
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PLIC
> >      select SIFIVE_UART
> > @@ -49,7 +49,7 @@ config SIFIVE_U
> >      bool
> >      select CADENCE
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> > @@ -65,5 +65,5 @@ config SPIKE
> >      bool
> >      select HTIF
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PLIC
> > diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> > index c4146b7a6b..e637e5c885 100644
> > --- a/hw/riscv/microchip_pfsoc.c
> > +++ b/hw/riscv/microchip_pfsoc.c
> > @@ -51,7 +51,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/riscv_hart.h"
> >  #include "hw/riscv/microchip_pfsoc.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "sysemu/sysemu.h"
> >
> > @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
> >          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
> >
> >      /* CLINT */
> > -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(
> > +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      /* L2 cache controller */
> >      create_unimplemented_device("microchip.pfsoc.l2cc",
> > diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> > index f939bcf9ea..ea960a5f2e 100644
> > --- a/hw/riscv/sifive_e.c
> > +++ b/hw/riscv/sifive_e.c
> > @@ -42,7 +42,7 @@
> >  #include "hw/riscv/sifive_e.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_e_prci.h"
> >  #include "chardev/char.h"
> > @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> >          SIFIVE_E_PLIC_CONTEXT_BASE,
> >          SIFIVE_E_PLIC_CONTEXT_STRIDE,
> >          memmap[SIFIVE_E_DEV_PLIC].size);
> > -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      create_unimplemented_device("riscv.sifive.e.aon",
> >          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
> >      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> > diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> > index 7b59942369..e5fe681984 100644
> > --- a/hw/riscv/sifive_u.c
> > +++ b/hw/riscv/sifive_u.c
> > @@ -52,7 +52,7 @@
> >  #include "hw/riscv/sifive_u.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "chardev/char.h"
> >  #include "net/eth.h"
> > @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >
> > @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
> >          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
> >      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
> >          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> > -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
> >          return;
> > diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> > index ec7cb2f707..10681fbf99 100644
> > --- a/hw/riscv/spike.c
> > +++ b/hw/riscv/spike.c
> > @@ -36,7 +36,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> >  #include "hw/char/riscv_htif.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "chardev/char.h"
> >  #include "sysemu/arch_init.h"
> >  #include "sysemu/device_tree.h"
> > @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Core Local Interruptor (timer and IPI) for each socket */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> > -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      }
> >
> >      /* register system main memory (actual RAM) */
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index c0dc69ff33..5eb63f6efd 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -33,7 +33,7 @@
> >  #include "hw/riscv/virt.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_test.h"
> >  #include "chardev/char.h"
> > @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> > +                          RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Per-socket CLINT */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> > -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, true);
> >
> >          /* Per-socket PLIC hart topology configuration string */
> >          plic_hart_config_len =
> > diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> > new file mode 100644
> > index 0000000000..471a5ffd0b
> > --- /dev/null
> > +++ b/include/hw/intc/riscv_aclint.h
> > @@ -0,0 +1,73 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#ifndef HW_RISCV_ACLINT_H
> > +#define HW_RISCV_ACLINT_H
> > +
> > +#include "hw/sysbus.h"
> > +
> > +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> > +
> > +#define RISCV_ACLINT_MTIMER(obj) \
> > +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> > +
> > +typedef struct RISCVAclintMTimerState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t timebase_freq;
> > +} RISCVAclintMTimerState;
> > +
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime);
> > +
> > +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> > +
> > +#define RISCV_ACLINT_SWI(obj) \
> > +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> > +
> > +typedef struct RISCVAclintSwiState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t sirq_mask;
> > +} RISCVAclintSwiState;
> > +
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> > +
> > +enum {
> > +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> > +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> > +    RISCV_ACLINT_SWI_SIZE = 0x4000
> > +};
> > +
> > +#endif
> > diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> > deleted file mode 100644
> > index a30be0f3d6..0000000000
> > --- a/include/hw/intc/sifive_clint.h
> > +++ /dev/null
> > @@ -1,60 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor) interface
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#ifndef HW_SIFIVE_CLINT_H
> > -#define HW_SIFIVE_CLINT_H
> > -
> > -#include "hw/sysbus.h"
> > -
> > -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> > -
> > -#define SIFIVE_CLINT(obj) \
> > -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> > -
> > -typedef struct SiFiveCLINTState {
> > -    /*< private >*/
> > -    SysBusDevice parent_obj;
> > -
> > -    /*< public >*/
> > -    MemoryRegion mmio;
> > -    uint32_t hartid_base;
> > -    uint32_t num_harts;
> > -    uint32_t sip_base;
> > -    uint32_t timecmp_base;
> > -    uint32_t time_base;
> > -    uint32_t aperture_size;
> > -    uint32_t timebase_freq;
> > -} SiFiveCLINTState;
> > -
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime);
> > -
> > -enum {
> > -    SIFIVE_SIP_BASE     = 0x0,
> > -    SIFIVE_TIMECMP_BASE = 0x4000,
> > -    SIFIVE_TIME_BASE    = 0xBFF8
> > -};
> > -
> > -enum {
> > -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> > -};
> > -
> > -#endif
> > --
> > 2.25.1
> >
> >

Regards,
Anup


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

* Re: [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT
@ 2021-07-12  5:32       ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:32 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Fri, Jun 18, 2021 at 12:20 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 2:09 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > The RISC-V ACLINT is more modular and backward compatible with
> > original SiFive CLINT so instead of duplicating the orignal
> > SiFive CLINT implementation we upgrade the current SiFive CLINT
> > implementation to RISC-V ACLINT implementation.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/intc/Kconfig                |   2 +-
> >  hw/intc/meson.build            |   2 +-
> >  hw/intc/riscv_aclint.c         | 374 +++++++++++++++++++++++++++++++++
> >  hw/intc/sifive_clint.c         | 266 -----------------------
> >  hw/riscv/Kconfig               |  10 +-
> >  hw/riscv/microchip_pfsoc.c     |  12 +-
> >  hw/riscv/sifive_e.c            |  12 +-
> >  hw/riscv/sifive_u.c            |  14 +-
> >  hw/riscv/spike.c               |  15 +-
> >  hw/riscv/virt.c                |  15 +-
> >  include/hw/intc/riscv_aclint.h |  73 +++++++
> >  include/hw/intc/sifive_clint.h |  60 ------
> >  12 files changed, 494 insertions(+), 361 deletions(-)
> >  create mode 100644 hw/intc/riscv_aclint.c
> >  delete mode 100644 hw/intc/sifive_clint.c
> >  create mode 100644 include/hw/intc/riscv_aclint.h
> >  delete mode 100644 include/hw/intc/sifive_clint.h
>
> Could we split this patch into 2? One to rename the file and a second
> to add the new implementation? Otherwise there might be a git config
> to change file rename detection as this is hard to see the changes.

Sure, I will split this patch into two patches.

>
> >
> > diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> > index f4694088a4..78aed93c45 100644
> > --- a/hw/intc/Kconfig
> > +++ b/hw/intc/Kconfig
> > @@ -62,7 +62,7 @@ config RX_ICU
> >  config LOONGSON_LIOINTC
> >      bool
> >
> > -config SIFIVE_CLINT
> > +config RISCV_ACLINT
> >      bool
> >
> >  config SIFIVE_PLIC
> > diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> > index 1c299039f6..2482fcfaf8 100644
> > --- a/hw/intc/meson.build
> > +++ b/hw/intc/meson.build
> > @@ -48,7 +48,7 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
> >  specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
> >  specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
> > -specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
> > +specific_ss.add(when: 'CONFIG_RISCV_ACLINT', if_true: files('riscv_aclint.c'))
> >  specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
> >  specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
> >  specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XICS'],
> > diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> > new file mode 100644
> > index 0000000000..682f95cca7
> > --- /dev/null
> > +++ b/hw/intc/riscv_aclint.c
> > @@ -0,0 +1,374 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor)
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This provides real-time clock, timer and interprocessor interrupts.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/error.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/module.h"
> > +#include "hw/sysbus.h"
> > +#include "target/riscv/cpu.h"
> > +#include "hw/qdev-properties.h"
> > +#include "hw/intc/riscv_aclint.h"
> > +#include "qemu/timer.h"
> > +
> > +static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > +{
> > +    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > +        timebase_freq, NANOSECONDS_PER_SECOND);
> > +}
> > +
> > +/*
> > + * Called when timecmp is written to update the QEMU timer or immediately
> > + * trigger timer interrupt if mtimecmp <= current timer value.
> > + */
> > +static void riscv_aclint_mtimer_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > +    uint32_t timebase_freq)
> > +{
> > +    uint64_t next;
> > +    uint64_t diff;
> > +
> > +    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > +
> > +    cpu->env.timecmp = value;
> > +    if (cpu->env.timecmp <= rtc_r) {
> > +        /* if we're setting an MTIMECMP value in the "past",
> > +           immediately raise the timer interrupt */
> > +        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +        return;
> > +    }
> > +
> > +    /* otherwise, set up the future timer interrupt */
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > +    diff = cpu->env.timecmp - rtc_r;
> > +    /* back to ns (note args switched in muldiv64) */
> > +    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > +        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > +    timer_mod(cpu->env.timer, next);
> > +}
> > +
> > +/*
> > + * Callback used when the timer set using timer_mod expires.
> > + * Should raise the timer interrupt line
> > + */
> > +static void riscv_aclint_mtimer_cb(void *opaque)
> > +{
> > +    RISCVCPU *cpu = opaque;
> > +    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > +}
> > +
> > +/* CPU wants to read MTIMER register */
> > +static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp = env->timecmp;
> > +            return timecmp & 0xFFFFFFFF;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp = env->timecmp;
> > +            return (timecmp >> 32) & 0xFFFFFFFF;
> > +        } else {
> > +            error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
> > +        }
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote MTIMER register */
> > +static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
> > +    uint64_t value, unsigned size)
> > +{
> > +    RISCVAclintMTimerState *mtimer = opaque;
> > +
> > +    if (addr < (mtimer->num_harts << 3)) {
> > +        size_t hartid = mtimer->hartid_base + (addr >> 3);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-mtimer: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x7) == 0) {
> > +            /* timecmp_lo */
> > +            uint64_t timecmp_hi = env->timecmp >> 32;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                timecmp_hi << 32 | (value & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +            return;
> > +        } else if ((addr & 0x7) == 4) {
> > +            /* timecmp_hi */
> > +            uint64_t timecmp_lo = env->timecmp;
> > +            riscv_aclint_mtimer_write_timecmp(RISCV_CPU(cpu),
> > +                value << 32 | (timecmp_lo & 0xFFFFFFFF),
> > +                mtimer->timebase_freq);
> > +        } else {
> > +            error_report("aclint-mtimer: invalid timecmp write: %08x",
> > +                         (uint32_t)addr);
> > +        }
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 8)) {
> > +        /* time_lo */
> > +        error_report("aclint-mtimer: time_lo write not implemented");
> > +        return;
> > +    } else if (addr == (mtimer->aperture_size - 4)) {
> > +        /* time_hi */
> > +        error_report("aclint-mtimer: time_hi write not implemented");
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-mtimer: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_mtimer_ops = {
> > +    .read = riscv_aclint_mtimer_read,
> > +    .write = riscv_aclint_mtimer_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 8
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_mtimer_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState,
> > +        hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 0),
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState,
> > +        aperture_size, 0),
> > +    DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState,
> > +        timebase_freq, 0),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, s,
> > +                          TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim MTIP so that only MTIMER controls it. */
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +        if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
> > +            error_report("MTIP already claimed");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_mtimer_realize;
> > +    device_class_set_props(dc, riscv_aclint_mtimer_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_mtimer_info = {
> > +    .name          = TYPE_RISCV_ACLINT_MTIMER,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintMTimerState),
> > +    .class_init    = riscv_aclint_mtimer_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT MTIMER device.
> > + */
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime)
> > +{
> > +    int i;
> > +    for (i = 0; i < num_harts; i++) {
> > +        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            continue;
> > +        }
> > +        if (provide_rdtime) {
> > +            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > +        }
> > +        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > +                                  &riscv_aclint_mtimer_cb, cpu);
> > +        env->timecmp = 0;
> > +    }
> > +
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +/* CPU read [M|S]SWI register */
> > +static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
> > +    unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            return (env->mip & swi->sirq_mask) > 0;
> > +        } else {
> > +            error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +            return 0;
>
> We can drop this and just fall through.

Okay, will update.

>
> > +        }
> > +    }
> > +
> > +    error_report("aclint-swi: invalid read: %08x", (uint32_t)addr);
> > +    return 0;
> > +}
> > +
> > +/* CPU wrote [M|S]SWI register */
> > +static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
> > +        unsigned size)
> > +{
> > +    RISCVAclintSwiState *swi = opaque;
> > +
> > +    if (addr < (swi->num_harts << 2)) {
> > +        size_t hartid = swi->hartid_base + (addr >> 2);
> > +        CPUState *cpu = qemu_get_cpu(hartid);
> > +        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > +        if (!env) {
> > +            error_report("aclint-swi: invalid hartid: %zu", hartid);
> > +        } else if ((addr & 0x3) == 0) {
> > +            riscv_cpu_update_mip(RISCV_CPU(cpu), swi->sirq_mask,
> > +                                 BOOL_TO_MASK(value));
> > +        } else {
> > +            error_report("aclint-swi: invalid [M|S]SIP write: %08x",
> > +                         (uint32_t)addr);
>
> Same here

Okay, will update.

>
> > +        }
> > +        return;
> > +    }
> > +
> > +    error_report("aclint-swi: invalid write: %08x", (uint32_t)addr);
> > +}
> > +
> > +static const MemoryRegionOps riscv_aclint_swi_ops = {
> > +    .read = riscv_aclint_swi_read,
> > +    .write = riscv_aclint_swi_write,
> > +    .endianness = DEVICE_LITTLE_ENDIAN,
> > +    .valid = {
> > +        .min_access_size = 4,
> > +        .max_access_size = 4
> > +    }
> > +};
> > +
> > +static Property riscv_aclint_swi_properties[] = {
> > +    DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0),
> > +    DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 0),
> > +    DEFINE_PROP_UINT32("aperture-size", RISCVAclintSwiState,
> > +        aperture_size, 0),
> > +    DEFINE_PROP_UINT32("sirq-mask", RISCVAclintSwiState, sirq_mask, 0),
> > +    DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp)
> > +{
> > +    int i;
> > +    RISCVCPU *cpu;
> > +    RISCVAclintSwiState *s = RISCV_ACLINT_SWI(dev);
> > +
> > +    memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_swi_ops, s,
> > +                          TYPE_RISCV_ACLINT_SWI, s->aperture_size);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > +
> > +    /* Claim [M|S]SIP so that can SWI controls it. */
> > +    for (i = 0; i < s->num_harts; i++) {
> > +        cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
> > +
> > +        /* We don't claim SSIP bit of mip CSR because this bit is
> > +         * writable by software as-per RISC-V privilege specification.
> > +         */
> > +        if ((s->sirq_mask != MIP_SSIP) &&
> > +            riscv_cpu_claim_interrupts(cpu, s->sirq_mask) < 0) {
> > +            error_report("%s already claimed",
> > +                (s->sirq_mask == MIP_SSIP) ? "SSIP" : "MSIP");
> > +            exit(1);
> > +        }
> > +    }
> > +}
> > +
> > +static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +    dc->realize = riscv_aclint_swi_realize;
> > +    device_class_set_props(dc, riscv_aclint_swi_properties);
> > +}
> > +
> > +static const TypeInfo riscv_aclint_swi_info = {
> > +    .name          = TYPE_RISCV_ACLINT_SWI,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(RISCVAclintSwiState),
> > +    .class_init    = riscv_aclint_swi_class_init,
> > +};
> > +
> > +/*
> > + * Create ACLINT [M|S]SWI device.
> > + */
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi)
> > +{
> > +    DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI);
> > +    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > +    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > +    qdev_prop_set_uint32(dev, "aperture-size", size);
> > +    qdev_prop_set_uint32(dev, "sirq-mask", smode_swi ? MIP_SSIP : MIP_MSIP);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > +    return dev;
> > +}
> > +
> > +static void riscv_aclint_register_types(void)
> > +{
> > +    type_register_static(&riscv_aclint_mtimer_info);
> > +    type_register_static(&riscv_aclint_swi_info);
> > +}
> > +
> > +type_init(riscv_aclint_register_types)
> > diff --git a/hw/intc/sifive_clint.c b/hw/intc/sifive_clint.c
> > deleted file mode 100644
> > index 0f41e5ea1c..0000000000
> > --- a/hw/intc/sifive_clint.c
> > +++ /dev/null
> > @@ -1,266 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor)
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This provides real-time clock, timer and interprocessor interrupts.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#include "qemu/osdep.h"
> > -#include "qapi/error.h"
> > -#include "qemu/error-report.h"
> > -#include "qemu/module.h"
> > -#include "hw/sysbus.h"
> > -#include "target/riscv/cpu.h"
> > -#include "hw/qdev-properties.h"
> > -#include "hw/intc/sifive_clint.h"
> > -#include "qemu/timer.h"
> > -
> > -static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
> > -{
> > -    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
> > -        timebase_freq, NANOSECONDS_PER_SECOND);
> > -}
> > -
> > -/*
> > - * Called when timecmp is written to update the QEMU timer or immediately
> > - * trigger timer interrupt if mtimecmp <= current timer value.
> > - */
> > -static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
> > -                                       uint32_t timebase_freq)
> > -{
> > -    uint64_t next;
> > -    uint64_t diff;
> > -
> > -    uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
> > -
> > -    cpu->env.timecmp = value;
> > -    if (cpu->env.timecmp <= rtc_r) {
> > -        /* if we're setting an MTIMECMP value in the "past",
> > -           immediately raise the timer interrupt */
> > -        riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -        return;
> > -    }
> > -
> > -    /* otherwise, set up the future timer interrupt */
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
> > -    diff = cpu->env.timecmp - rtc_r;
> > -    /* back to ns (note args switched in muldiv64) */
> > -    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> > -        muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> > -    timer_mod(cpu->env.timer, next);
> > -}
> > -
> > -/*
> > - * Callback used when the timer set using timer_mod expires.
> > - * Should raise the timer interrupt line
> > - */
> > -static void sifive_clint_timer_cb(void *opaque)
> > -{
> > -    RISCVCPU *cpu = opaque;
> > -    riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
> > -}
> > -
> > -/* CPU wants to read rtc or timecmp register */
> > -static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            return (env->mip & MIP_MSIP) > 0;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp = env->timecmp;
> > -            return timecmp & 0xFFFFFFFF;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp = env->timecmp;
> > -            return (timecmp >> 32) & 0xFFFFFFFF;
> > -        } else {
> > -            error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -            return 0;
> > -        }
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
> > -    }
> > -
> > -    error_report("clint: invalid read: %08x", (uint32_t)addr);
> > -    return 0;
> > -}
> > -
> > -/* CPU wrote to rtc or timecmp register */
> > -static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
> > -        unsigned size)
> > -{
> > -    SiFiveCLINTState *clint = opaque;
> > -
> > -    if (addr >= clint->sip_base &&
> > -        addr < clint->sip_base + (clint->num_harts << 2)) {
> > -        size_t hartid = clint->hartid_base + ((addr - clint->sip_base) >> 2);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x3) == 0) {
> > -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
> > -        } else {
> > -            error_report("clint: invalid sip write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr >= clint->timecmp_base &&
> > -        addr < clint->timecmp_base + (clint->num_harts << 3)) {
> > -        size_t hartid = clint->hartid_base +
> > -            ((addr - clint->timecmp_base) >> 3);
> > -        CPUState *cpu = qemu_get_cpu(hartid);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            error_report("clint: invalid timecmp hartid: %zu", hartid);
> > -        } else if ((addr & 0x7) == 0) {
> > -            /* timecmp_lo */
> > -            uint64_t timecmp_hi = env->timecmp >> 32;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
> > -            return;
> > -        } else if ((addr & 0x7) == 4) {
> > -            /* timecmp_hi */
> > -            uint64_t timecmp_lo = env->timecmp;
> > -            sifive_clint_write_timecmp(RISCV_CPU(cpu),
> > -                value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
> > -        } else {
> > -            error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
> > -        }
> > -        return;
> > -    } else if (addr == clint->time_base) {
> > -        /* time_lo */
> > -        error_report("clint: time_lo write not implemented");
> > -        return;
> > -    } else if (addr == clint->time_base + 4) {
> > -        /* time_hi */
> > -        error_report("clint: time_hi write not implemented");
> > -        return;
> > -    }
> > -
> > -    error_report("clint: invalid write: %08x", (uint32_t)addr);
> > -}
> > -
> > -static const MemoryRegionOps sifive_clint_ops = {
> > -    .read = sifive_clint_read,
> > -    .write = sifive_clint_write,
> > -    .endianness = DEVICE_LITTLE_ENDIAN,
> > -    .valid = {
> > -        .min_access_size = 4,
> > -        .max_access_size = 8
> > -    }
> > -};
> > -
> > -static Property sifive_clint_properties[] = {
> > -    DEFINE_PROP_UINT32("hartid-base", SiFiveCLINTState, hartid_base, 0),
> > -    DEFINE_PROP_UINT32("num-harts", SiFiveCLINTState, num_harts, 0),
> > -    DEFINE_PROP_UINT32("sip-base", SiFiveCLINTState, sip_base, 0),
> > -    DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
> > -    DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
> > -    DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
> > -    DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
> > -    DEFINE_PROP_END_OF_LIST(),
> > -};
> > -
> > -static void sifive_clint_realize(DeviceState *dev, Error **errp)
> > -{
> > -    SiFiveCLINTState *s = SIFIVE_CLINT(dev);
> > -    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_clint_ops, s,
> > -                          TYPE_SIFIVE_CLINT, s->aperture_size);
> > -    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
> > -}
> > -
> > -static void sifive_clint_class_init(ObjectClass *klass, void *data)
> > -{
> > -    DeviceClass *dc = DEVICE_CLASS(klass);
> > -    dc->realize = sifive_clint_realize;
> > -    device_class_set_props(dc, sifive_clint_properties);
> > -}
> > -
> > -static const TypeInfo sifive_clint_info = {
> > -    .name          = TYPE_SIFIVE_CLINT,
> > -    .parent        = TYPE_SYS_BUS_DEVICE,
> > -    .instance_size = sizeof(SiFiveCLINTState),
> > -    .class_init    = sifive_clint_class_init,
> > -};
> > -
> > -static void sifive_clint_register_types(void)
> > -{
> > -    type_register_static(&sifive_clint_info);
> > -}
> > -
> > -type_init(sifive_clint_register_types)
> > -
> > -
> > -/*
> > - * Create CLINT device.
> > - */
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime)
> > -{
> > -    int i;
> > -    for (i = 0; i < num_harts; i++) {
> > -        CPUState *cpu = qemu_get_cpu(hartid_base + i);
> > -        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
> > -        if (!env) {
> > -            continue;
> > -        }
> > -        if (provide_rdtime) {
> > -            riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
> > -        }
> > -        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > -                                  &sifive_clint_timer_cb, cpu);
> > -        env->timecmp = 0;
> > -    }
> > -
> > -    DeviceState *dev = qdev_new(TYPE_SIFIVE_CLINT);
> > -    qdev_prop_set_uint32(dev, "hartid-base", hartid_base);
> > -    qdev_prop_set_uint32(dev, "num-harts", num_harts);
> > -    qdev_prop_set_uint32(dev, "sip-base", sip_base);
> > -    qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
> > -    qdev_prop_set_uint32(dev, "time-base", time_base);
> > -    qdev_prop_set_uint32(dev, "aperture-size", size);
> > -    qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
> > -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > -    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
> > -    return dev;
> > -}
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 1de18cdcf1..939cd0ef40 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -9,7 +9,7 @@ config MICROCHIP_PFSOC
> >      select MCHP_PFSOC_MMUART
> >      select MCHP_PFSOC_SYSREG
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> >      select UNIMP
> > @@ -29,7 +29,7 @@ config RISCV_VIRT
> >      select PCI_EXPRESS_GENERIC_BRIDGE
> >      select PFLASH_CFI01
> >      select SERIAL
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PLIC
> >      select SIFIVE_TEST
> >      select VIRTIO_MMIO
> > @@ -38,7 +38,7 @@ config RISCV_VIRT
> >  config SIFIVE_E
> >      bool
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PLIC
> >      select SIFIVE_UART
> > @@ -49,7 +49,7 @@ config SIFIVE_U
> >      bool
> >      select CADENCE
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_GPIO
> >      select SIFIVE_PDMA
> >      select SIFIVE_PLIC
> > @@ -65,5 +65,5 @@ config SPIKE
> >      bool
> >      select HTIF
> >      select MSI_NONBROKEN
> > -    select SIFIVE_CLINT
> > +    select RISCV_ACLINT
> >      select SIFIVE_PLIC
> > diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
> > index c4146b7a6b..e637e5c885 100644
> > --- a/hw/riscv/microchip_pfsoc.c
> > +++ b/hw/riscv/microchip_pfsoc.c
> > @@ -51,7 +51,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/riscv_hart.h"
> >  #include "hw/riscv/microchip_pfsoc.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "sysemu/sysemu.h"
> >
> > @@ -235,10 +235,12 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
> >          memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
> >
> >      /* CLINT */
> > -    sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > -        memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[MICROCHIP_PFSOC_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(
> > +        memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      /* L2 cache controller */
> >      create_unimplemented_device("microchip.pfsoc.l2cc",
> > diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> > index f939bcf9ea..ea960a5f2e 100644
> > --- a/hw/riscv/sifive_e.c
> > +++ b/hw/riscv/sifive_e.c
> > @@ -42,7 +42,7 @@
> >  #include "hw/riscv/sifive_e.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_e_prci.h"
> >  #include "chardev/char.h"
> > @@ -210,10 +210,12 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> >          SIFIVE_E_PLIC_CONTEXT_BASE,
> >          SIFIVE_E_PLIC_CONTEXT_STRIDE,
> >          memmap[SIFIVE_E_DEV_PLIC].size);
> > -    sifive_clint_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > -        memmap[SIFIVE_E_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_E_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_E_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      create_unimplemented_device("riscv.sifive.e.aon",
> >          memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
> >      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
> > diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> > index 7b59942369..e5fe681984 100644
> > --- a/hw/riscv/sifive_u.c
> > +++ b/hw/riscv/sifive_u.c
> > @@ -52,7 +52,7 @@
> >  #include "hw/riscv/sifive_u.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/char/sifive_uart.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "chardev/char.h"
> >  #include "net/eth.h"
> > @@ -160,7 +160,7 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >
> > @@ -839,10 +839,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
> >          serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
> >      sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
> >          serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
> > -    sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > -        memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
> > -        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -        SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +    riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base,
> > +        RISCV_ACLINT_SWI_SIZE, 0, ms->smp.cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
> > +            RISCV_ACLINT_SWI_SIZE,
> > +        RISCV_ACLINT_MTIMER_SIZE, 0, ms->smp.cpus,
> > +        RISCV_ACLINT_TIMEBASE_FREQ, false);
> >
> >      if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
> >          return;
> > diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
> > index ec7cb2f707..10681fbf99 100644
> > --- a/hw/riscv/spike.c
> > +++ b/hw/riscv/spike.c
> > @@ -36,7 +36,7 @@
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> >  #include "hw/char/riscv_htif.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "chardev/char.h"
> >  #include "sysemu/arch_init.h"
> >  #include "sysemu/device_tree.h"
> > @@ -83,7 +83,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -        SIFIVE_CLINT_TIMEBASE_FREQ);
> > +        RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -225,11 +225,14 @@ static void spike_board_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Core Local Interruptor (timer and IPI) for each socket */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
> > -            memmap[SPIKE_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, false);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, false);
> >      }
> >
> >      /* register system main memory (actual RAM) */
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index c0dc69ff33..5eb63f6efd 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -33,7 +33,7 @@
> >  #include "hw/riscv/virt.h"
> >  #include "hw/riscv/boot.h"
> >  #include "hw/riscv/numa.h"
> > -#include "hw/intc/sifive_clint.h"
> > +#include "hw/intc/riscv_aclint.h"
> >  #include "hw/intc/sifive_plic.h"
> >  #include "hw/misc/sifive_test.h"
> >  #include "chardev/char.h"
> > @@ -224,7 +224,7 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >
> >      qemu_fdt_add_subnode(fdt, "/cpus");
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > -                          SIFIVE_CLINT_TIMEBASE_FREQ);
> > +                          RISCV_ACLINT_TIMEBASE_FREQ);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> >      qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> >      qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > @@ -587,11 +587,14 @@ static void virt_machine_init(MachineState *machine)
> >          sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
> >
> >          /* Per-socket CLINT */
> > -        sifive_clint_create(
> > +        riscv_aclint_swi_create(
> >              memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
> > -            memmap[VIRT_CLINT].size, base_hartid, hart_count,
> > -            SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
> > -            SIFIVE_CLINT_TIMEBASE_FREQ, true);
> > +            RISCV_ACLINT_SWI_SIZE, base_hartid, hart_count, false);
> > +        riscv_aclint_mtimer_create(
> > +            memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
> > +                RISCV_ACLINT_SWI_SIZE,
> > +            RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> > +            RISCV_ACLINT_TIMEBASE_FREQ, true);
> >
> >          /* Per-socket PLIC hart topology configuration string */
> >          plic_hart_config_len =
> > diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
> > new file mode 100644
> > index 0000000000..471a5ffd0b
> > --- /dev/null
> > +++ b/include/hw/intc/riscv_aclint.h
> > @@ -0,0 +1,73 @@
> > +/*
> > + * RISC-V ACLINT (Advanced Core Local Interruptor) interface
> > + *
> > + * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > + * Copyright (c) 2017 SiFive, Inc.
> > + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#ifndef HW_RISCV_ACLINT_H
> > +#define HW_RISCV_ACLINT_H
> > +
> > +#include "hw/sysbus.h"
> > +
> > +#define TYPE_RISCV_ACLINT_MTIMER "riscv.aclint.mtimer"
> > +
> > +#define RISCV_ACLINT_MTIMER(obj) \
> > +    OBJECT_CHECK(RISCVAclintMTimerState, (obj), TYPE_RISCV_ACLINT_MTIMER)
> > +
> > +typedef struct RISCVAclintMTimerState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t timebase_freq;
> > +} RISCVAclintMTimerState;
> > +
> > +DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, uint32_t timebase_freq,
> > +    bool provide_rdtime);
> > +
> > +#define TYPE_RISCV_ACLINT_SWI "riscv.aclint.swi"
> > +
> > +#define RISCV_ACLINT_SWI(obj) \
> > +    OBJECT_CHECK(RISCVAclintSwiState, (obj), TYPE_RISCV_ACLINT_SWI)
> > +
> > +typedef struct RISCVAclintSwiState {
> > +    /*< private >*/
> > +    SysBusDevice parent_obj;
> > +
> > +    /*< public >*/
> > +    MemoryRegion mmio;
> > +    uint32_t hartid_base;
> > +    uint32_t num_harts;
> > +    uint32_t aperture_size;
> > +    uint32_t sirq_mask;
> > +} RISCVAclintSwiState;
> > +
> > +DeviceState *riscv_aclint_swi_create(hwaddr addr, hwaddr size,
> > +    uint32_t hartid_base, uint32_t num_harts, bool smode_swi);
> > +
> > +enum {
> > +    RISCV_ACLINT_MTIMER_SIZE = 0x8000,
> > +    RISCV_ACLINT_TIMEBASE_FREQ = 10000000,
> > +    RISCV_ACLINT_SWI_SIZE = 0x4000
> > +};
> > +
> > +#endif
> > diff --git a/include/hw/intc/sifive_clint.h b/include/hw/intc/sifive_clint.h
> > deleted file mode 100644
> > index a30be0f3d6..0000000000
> > --- a/include/hw/intc/sifive_clint.h
> > +++ /dev/null
> > @@ -1,60 +0,0 @@
> > -/*
> > - * SiFive CLINT (Core Local Interruptor) interface
> > - *
> > - * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
> > - * Copyright (c) 2017 SiFive, Inc.
> > - *
> > - * This program is free software; you can redistribute it and/or modify it
> > - * under the terms and conditions of the GNU General Public License,
> > - * version 2 or later, as published by the Free Software Foundation.
> > - *
> > - * This program is distributed in the hope it will be useful, but WITHOUT
> > - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > - * more details.
> > - *
> > - * You should have received a copy of the GNU General Public License along with
> > - * this program.  If not, see <http://www.gnu.org/licenses/>.
> > - */
> > -
> > -#ifndef HW_SIFIVE_CLINT_H
> > -#define HW_SIFIVE_CLINT_H
> > -
> > -#include "hw/sysbus.h"
> > -
> > -#define TYPE_SIFIVE_CLINT "riscv.sifive.clint"
> > -
> > -#define SIFIVE_CLINT(obj) \
> > -    OBJECT_CHECK(SiFiveCLINTState, (obj), TYPE_SIFIVE_CLINT)
> > -
> > -typedef struct SiFiveCLINTState {
> > -    /*< private >*/
> > -    SysBusDevice parent_obj;
> > -
> > -    /*< public >*/
> > -    MemoryRegion mmio;
> > -    uint32_t hartid_base;
> > -    uint32_t num_harts;
> > -    uint32_t sip_base;
> > -    uint32_t timecmp_base;
> > -    uint32_t time_base;
> > -    uint32_t aperture_size;
> > -    uint32_t timebase_freq;
> > -} SiFiveCLINTState;
> > -
> > -DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
> > -    uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
> > -    uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
> > -    bool provide_rdtime);
> > -
> > -enum {
> > -    SIFIVE_SIP_BASE     = 0x0,
> > -    SIFIVE_TIMECMP_BASE = 0x4000,
> > -    SIFIVE_TIME_BASE    = 0xBFF8
> > -};
> > -
> > -enum {
> > -    SIFIVE_CLINT_TIMEBASE_FREQ = 10000000
> > -};
> > -
> > -#endif
> > --
> > 2.25.1
> >
> >

Regards,
Anup


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-06-14 12:22     ` Bin Meng
@ 2021-07-12  5:38       ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:38 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > parameter is passed along with machine name in QEMU command-line.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> >  include/hw/riscv/virt.h |   2 +
> >  2 files changed, 111 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index 977d699753..a35f66af13 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
>
> How about we reuse the same register space to support both CLINT and
> ACLINT? This saves some register space for future extension.

The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
MSWI is to minimize PMP region usage.

When we have multiple sockets, each socket will have it's own set of
ACLINT devices so we deliberately keep ACLINT MTIMER and MSWI
devices of all sockets next to each other so that we need just 1-2 PMP
regions to cover all M-level ACLINT devices.

In general, RISC-V platform vendors will have to carefully design
memory layout of M-level devices so that M-mode runtime firmware
needs fewer PMP regions. The spare PMP regions can be used by
M-mode runtime firmware to partition the system into domains and
implement TEE.

>
> >      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
> >      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
> >      [VIRT_UART0] =       { 0x10000000,         0x100 },
> > @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
> >      g_free(clint_cells);
> >  }
> >
> > +static void create_fdt_socket_aclint(RISCVVirtState *s,
> > +                                     const MemMapEntry *memmap, int socket,
> > +                                     uint32_t *intc_phandles)
> > +{
> > +    int cpu;
> > +    char *name;
> > +    unsigned long addr;
> > +    uint32_t aclint_cells_size;
> > +    uint32_t *aclint_mswi_cells;
> > +    uint32_t *aclint_sswi_cells;
> > +    uint32_t *aclint_mtimer_cells;
> > +    MachineState *mc = 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;
> > +
> > +    addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> > +    name = g_strdup_printf("/soc/mswi@%lx", addr);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> > +        aclint_mswi_cells, aclint_cells_size);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> > +    g_free(name);
> > +
> > +    addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> > +        (memmap[VIRT_CLINT].size * socket);
> > +    name = g_strdup_printf("/soc/mtimer@%lx", addr);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> > +        "riscv,aclint-mtimer");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, addr, 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> > +        aclint_mtimer_cells, aclint_cells_size);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> > +    g_free(name);
> > +
> > +    addr = memmap[VIRT_ACLINT_SSWI].base +
> > +        (memmap[VIRT_ACLINT_SSWI].size * socket);
> > +    name = g_strdup_printf("/soc/sswi@%lx", addr);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> > +        aclint_sswi_cells, aclint_cells_size);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> > +    g_free(name);
> > +
> > +    g_free(aclint_mswi_cells);
> > +    g_free(aclint_mtimer_cells);
> > +    g_free(aclint_sswi_cells);
> > +}
> > +
> >  static void create_fdt_socket_plic(RISCVVirtState *s,
> >                                     const MemMapEntry *memmap, int socket,
> >                                     uint32_t *phandle, uint32_t *intc_phandles,
> > @@ -352,7 +425,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
> >
> >          create_fdt_socket_memory(s, memmap, socket);
> >
> > -        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> > +        if (s->have_aclint) {
> > +            create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
> > +        } else {
> > +            create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> > +        }
> >
> >          create_fdt_socket_plic(s, memmap, socket, phandle,
> >              intc_phandles, xplic_phandles);
> > @@ -722,6 +799,15 @@ static void virt_machine_init(MachineState *machine)
> >              RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> >              RISCV_ACLINT_TIMEBASE_FREQ, true);
> >
> > +        /* Per-socket ACLINT SSWI */
> > +        if (s->have_aclint) {
> > +            riscv_aclint_swi_create(
> > +                memmap[VIRT_ACLINT_SSWI].base +
> > +                    i * memmap[VIRT_ACLINT_SSWI].size,
> > +                memmap[VIRT_ACLINT_SSWI].size,
> > +                base_hartid, hart_count, true);
> > +        }
> > +
> >          /* Per-socket PLIC hart topology configuration string */
> >          plic_hart_config_len =
> >              (strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
> > @@ -898,6 +984,22 @@ static void virt_machine_instance_init(Object *obj)
> >  {
> >  }
> >
> > +static bool virt_get_aclint(Object *obj, Error **errp)
> > +{
> > +    MachineState *ms = MACHINE(obj);
> > +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> > +
> > +    return s->have_aclint;
> > +}
> > +
> > +static void virt_set_aclint(Object *obj, bool value, Error **errp)
> > +{
> > +    MachineState *ms = MACHINE(obj);
> > +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> > +
> > +    s->have_aclint = value;
> > +}
> > +
> >  static void virt_machine_class_init(ObjectClass *oc, void *data)
> >  {
> >      MachineClass *mc = MACHINE_CLASS(oc);
> > @@ -913,6 +1015,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
> >      mc->numa_mem_supported = true;
> >
> >      machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
> > +
> > +    object_class_property_add_bool(oc, "aclint", virt_get_aclint,
> > +                                   virt_set_aclint);
> > +    object_class_property_set_description(oc, "aclint",
> > +                                          "Set on/off to enable/disable "
> > +                                          "emulating ACLINT devices");
> >  }
> >
> >  static const TypeInfo virt_machine_typeinfo = {
> > diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> > index 349fee1f89..d9105c1886 100644
> > --- a/include/hw/riscv/virt.h
> > +++ b/include/hw/riscv/virt.h
> > @@ -43,6 +43,7 @@ struct RISCVVirtState {
> >      FWCfgState *fw_cfg;
> >
> >      int fdt_size;
> > +    bool have_aclint;
> >  };
> >
> >  enum {
> > @@ -51,6 +52,7 @@ enum {
> >      VIRT_TEST,
> >      VIRT_RTC,
> >      VIRT_CLINT,
> > +    VIRT_ACLINT_SSWI,
> >      VIRT_PLIC,
> >      VIRT_UART0,
> >      VIRT_VIRTIO,
>
> Regards,
> Bin

Regards,
Anup


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-07-12  5:38       ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:38 UTC (permalink / raw)
  To: Bin Meng
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > parameter is passed along with machine name in QEMU command-line.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> >  include/hw/riscv/virt.h |   2 +
> >  2 files changed, 111 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index 977d699753..a35f66af13 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
>
> How about we reuse the same register space to support both CLINT and
> ACLINT? This saves some register space for future extension.

The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
MSWI is to minimize PMP region usage.

When we have multiple sockets, each socket will have it's own set of
ACLINT devices so we deliberately keep ACLINT MTIMER and MSWI
devices of all sockets next to each other so that we need just 1-2 PMP
regions to cover all M-level ACLINT devices.

In general, RISC-V platform vendors will have to carefully design
memory layout of M-level devices so that M-mode runtime firmware
needs fewer PMP regions. The spare PMP regions can be used by
M-mode runtime firmware to partition the system into domains and
implement TEE.

>
> >      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
> >      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
> >      [VIRT_UART0] =       { 0x10000000,         0x100 },
> > @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
> >      g_free(clint_cells);
> >  }
> >
> > +static void create_fdt_socket_aclint(RISCVVirtState *s,
> > +                                     const MemMapEntry *memmap, int socket,
> > +                                     uint32_t *intc_phandles)
> > +{
> > +    int cpu;
> > +    char *name;
> > +    unsigned long addr;
> > +    uint32_t aclint_cells_size;
> > +    uint32_t *aclint_mswi_cells;
> > +    uint32_t *aclint_sswi_cells;
> > +    uint32_t *aclint_mtimer_cells;
> > +    MachineState *mc = 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;
> > +
> > +    addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> > +    name = g_strdup_printf("/soc/mswi@%lx", addr);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> > +        aclint_mswi_cells, aclint_cells_size);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> > +    g_free(name);
> > +
> > +    addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE +
> > +        (memmap[VIRT_CLINT].size * socket);
> > +    name = g_strdup_printf("/soc/mtimer@%lx", addr);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> > +        "riscv,aclint-mtimer");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, addr, 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> > +        aclint_mtimer_cells, aclint_cells_size);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> > +    g_free(name);
> > +
> > +    addr = memmap[VIRT_ACLINT_SSWI].base +
> > +        (memmap[VIRT_ACLINT_SSWI].size * socket);
> > +    name = g_strdup_printf("/soc/sswi@%lx", addr);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupts-extended",
> > +        aclint_sswi_cells, aclint_cells_size);
> > +    qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, name, socket);
> > +    g_free(name);
> > +
> > +    g_free(aclint_mswi_cells);
> > +    g_free(aclint_mtimer_cells);
> > +    g_free(aclint_sswi_cells);
> > +}
> > +
> >  static void create_fdt_socket_plic(RISCVVirtState *s,
> >                                     const MemMapEntry *memmap, int socket,
> >                                     uint32_t *phandle, uint32_t *intc_phandles,
> > @@ -352,7 +425,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
> >
> >          create_fdt_socket_memory(s, memmap, socket);
> >
> > -        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> > +        if (s->have_aclint) {
> > +            create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
> > +        } else {
> > +            create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> > +        }
> >
> >          create_fdt_socket_plic(s, memmap, socket, phandle,
> >              intc_phandles, xplic_phandles);
> > @@ -722,6 +799,15 @@ static void virt_machine_init(MachineState *machine)
> >              RISCV_ACLINT_MTIMER_SIZE, base_hartid, hart_count,
> >              RISCV_ACLINT_TIMEBASE_FREQ, true);
> >
> > +        /* Per-socket ACLINT SSWI */
> > +        if (s->have_aclint) {
> > +            riscv_aclint_swi_create(
> > +                memmap[VIRT_ACLINT_SSWI].base +
> > +                    i * memmap[VIRT_ACLINT_SSWI].size,
> > +                memmap[VIRT_ACLINT_SSWI].size,
> > +                base_hartid, hart_count, true);
> > +        }
> > +
> >          /* Per-socket PLIC hart topology configuration string */
> >          plic_hart_config_len =
> >              (strlen(VIRT_PLIC_HART_CONFIG) + 1) * hart_count;
> > @@ -898,6 +984,22 @@ static void virt_machine_instance_init(Object *obj)
> >  {
> >  }
> >
> > +static bool virt_get_aclint(Object *obj, Error **errp)
> > +{
> > +    MachineState *ms = MACHINE(obj);
> > +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> > +
> > +    return s->have_aclint;
> > +}
> > +
> > +static void virt_set_aclint(Object *obj, bool value, Error **errp)
> > +{
> > +    MachineState *ms = MACHINE(obj);
> > +    RISCVVirtState *s = RISCV_VIRT_MACHINE(ms);
> > +
> > +    s->have_aclint = value;
> > +}
> > +
> >  static void virt_machine_class_init(ObjectClass *oc, void *data)
> >  {
> >      MachineClass *mc = MACHINE_CLASS(oc);
> > @@ -913,6 +1015,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
> >      mc->numa_mem_supported = true;
> >
> >      machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
> > +
> > +    object_class_property_add_bool(oc, "aclint", virt_get_aclint,
> > +                                   virt_set_aclint);
> > +    object_class_property_set_description(oc, "aclint",
> > +                                          "Set on/off to enable/disable "
> > +                                          "emulating ACLINT devices");
> >  }
> >
> >  static const TypeInfo virt_machine_typeinfo = {
> > diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
> > index 349fee1f89..d9105c1886 100644
> > --- a/include/hw/riscv/virt.h
> > +++ b/include/hw/riscv/virt.h
> > @@ -43,6 +43,7 @@ struct RISCVVirtState {
> >      FWCfgState *fw_cfg;
> >
> >      int fdt_size;
> > +    bool have_aclint;
> >  };
> >
> >  enum {
> > @@ -51,6 +52,7 @@ enum {
> >      VIRT_TEST,
> >      VIRT_RTC,
> >      VIRT_CLINT,
> > +    VIRT_ACLINT_SSWI,
> >      VIRT_PLIC,
> >      VIRT_UART0,
> >      VIRT_VIRTIO,
>
> Regards,
> Bin

Regards,
Anup


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

* Re: [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation
  2021-06-14 12:22     ` Bin Meng
@ 2021-07-12  5:40       ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:40 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 12:12 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We re-factor and break the FDT generation into smaller functions
> > so that it is easier to modify FDT generation for different
> > configurations of virt machine.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/riscv/virt.c | 514 ++++++++++++++++++++++++++++++------------------
> >  1 file changed, 320 insertions(+), 194 deletions(-)
> >
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index 5eb63f6efd..977d699753 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -178,206 +178,253 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
> >                             0x1800, 0, 0, 0x7);
> >  }
> >
> > -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> > -                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> > +static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
> > +                                   char *clust_name, uint32_t *phandle,
> > +                                   bool is_32_bit, uint32_t *intc_phandles)
> >  {
> > -    void *fdt;
> > -    int i, cpu, socket;
> > +    int cpu;
> > +    uint32_t cpu_phandle;
> >      MachineState *mc = MACHINE(s);
> > +    char *name, *cpu_name, *core_name, *intc_name;
> > +
> > +    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> > +        cpu_phandle = (*phandle)++;
> > +
> > +        cpu_name = g_strdup_printf("/cpus/cpu@%d",
> > +            s->soc[socket].hartid_base + cpu);
> > +        qemu_fdt_add_subnode(mc->fdt, cpu_name);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type",
> > +            (is_32_bit) ? "riscv,sv32" : "riscv,sv48");
> > +        name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name);
> > +        g_free(name);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv");
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay");
> > +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg",
> > +            s->soc[socket].hartid_base + cpu);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu");
> > +        riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket);
> > +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle);
> > +
> > +        intc_phandles[cpu] = (*phandle)++;
> > +
> > +        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> > +        qemu_fdt_add_subnode(mc->fdt, intc_name);
> > +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
> > +            intc_phandles[cpu]);
> > +        qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
> > +            "riscv,cpu-intc");
> > +        qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
> > +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
> > +
> > +        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> > +        qemu_fdt_add_subnode(mc->fdt, core_name);
> > +        qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle);
> > +
> > +        g_free(core_name);
> > +        g_free(intc_name);
> > +        g_free(cpu_name);
> > +    }
> > +}
> > +
> > +static void create_fdt_socket_memory(RISCVVirtState *s,
> > +                                     const MemMapEntry *memmap, int socket)
> > +{
> > +    char *mem_name;
> >      uint64_t addr, size;
> > -    uint32_t *clint_cells, *plic_cells;
> > -    unsigned long clint_addr, plic_addr;
> > -    uint32_t plic_phandle[MAX_NODES];
> > -    uint32_t cpu_phandle, intc_phandle, test_phandle;
> > -    uint32_t phandle = 1, plic_mmio_phandle = 1;
> > -    uint32_t plic_pcie_phandle = 1, plic_virtio_phandle = 1;
> > -    char *mem_name, *cpu_name, *core_name, *intc_name;
> > -    char *name, *clint_name, *plic_name, *clust_name;
> > -    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> > -    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
> > +    MachineState *mc = MACHINE(s);
> >
> > -    if (mc->dtb) {
> > -        fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> > -        if (!fdt) {
> > -            error_report("load_device_tree() failed");
> > -            exit(1);
> > -        }
> > -        goto update_bootargs;
> > -    } else {
> > -        fdt = mc->fdt = create_device_tree(&s->fdt_size);
> > -        if (!fdt) {
> > -            error_report("create_device_tree() failed");
> > -            exit(1);
> > -        }
> > +    addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> > +    size = riscv_socket_mem_size(mc, socket);
> > +    mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> > +    qemu_fdt_add_subnode(mc->fdt, mem_name);
> > +    qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg",
> > +        addr >> 32, addr, size >> 32, size);
> > +    qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory");
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket);
> > +    g_free(mem_name);
> > +}
> > +
> > +static void create_fdt_socket_clint(RISCVVirtState *s,
> > +                                    const MemMapEntry *memmap, int socket,
> > +                                    uint32_t *intc_phandles)
> > +{
> > +    int cpu;
> > +    char *clint_name;
> > +    uint32_t *clint_cells;
> > +    unsigned long clint_addr;
> > +    MachineState *mc = MACHINE(s);
> > +
> > +    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> > +
> > +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> > +        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> > +        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> > +        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> > +        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
> >      }
> >
> > -    qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
> > -    qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
> > -    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
> > -    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
> > +    clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> > +    clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> > +    qemu_fdt_add_subnode(mc->fdt, clint_name);
> > +    qemu_fdt_setprop_string(mc->fdt, clint_name, "compatible",
> > +        "riscv,clint0");
>
> This patch seems to be based on some old commit, as the latest QEMU
> head has the following commit that supports the official clint
> compatible name via:
>
> commit b387236bff95 ("hw/riscv: Support the official CLINT DT bindings")

Yes, I will be rebasing on the most recent tree of Alistair.

Regards,
Anup

>
> > +    qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg",
> > +        0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> > +    qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended",
> > +        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket);
> > +    g_free(clint_name);
> > +
> > +    g_free(clint_cells);
> > +}
> > +
> > +static void create_fdt_socket_plic(RISCVVirtState *s,
> > +                                   const MemMapEntry *memmap, int socket,
> > +                                   uint32_t *phandle, uint32_t *intc_phandles,
> > +                                   uint32_t *plic_phandles)
> > +{
> > +    int cpu;
> > +    char *plic_name;
> > +    uint32_t *plic_cells;
> > +    unsigned long plic_addr;
> > +    MachineState *mc = MACHINE(s);
> >
> > -    qemu_fdt_add_subnode(fdt, "/soc");
> > -    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
> > -    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
> > -    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
> > -    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
> > +    plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> >
> > -    qemu_fdt_add_subnode(fdt, "/cpus");
> > -    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> > +        plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> > +        plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> > +        plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> > +        plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> > +    }
> > +
> > +    plic_phandles[socket] = (*phandle)++;
> > +    plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> > +    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> > +    qemu_fdt_add_subnode(mc->fdt, plic_name);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> > +        "#address-cells", FDT_PLIC_ADDR_CELLS);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> > +        "#interrupt-cells", FDT_PLIC_INT_CELLS);
> > +    qemu_fdt_setprop_string(mc->fdt, plic_name, "compatible", "riscv,plic0");
> > +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0);
> > +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended",
> > +        plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > +    qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
> > +        0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
> > +        plic_phandles[socket]);
> > +    g_free(plic_name);
> > +
> > +    g_free(plic_cells);
> > +}
> > +
> > +static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                               bool is_32_bit, uint32_t *phandle,
> > +                               uint32_t *irq_mmio_phandle,
> > +                               uint32_t *irq_pcie_phandle,
> > +                               uint32_t *irq_virtio_phandle)
> > +{
> > +    int socket;
> > +    char *clust_name;
> > +    uint32_t *intc_phandles;
> > +    MachineState *mc = MACHINE(s);
> > +    uint32_t xplic_phandles[MAX_NODES];
> > +
> > +    qemu_fdt_add_subnode(mc->fdt, "/cpus");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency",
> >                            RISCV_ACLINT_TIMEBASE_FREQ);
> > -    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> > -    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> > -    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0);
> > +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1);
> > +    qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map");
> >
> >      for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) {
> >          clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
> > -        qemu_fdt_add_subnode(fdt, clust_name);
> > +        qemu_fdt_add_subnode(mc->fdt, clust_name);
> >
> > -        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> > -        clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> > +        intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts);
> >
> > -        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> > -            cpu_phandle = phandle++;
> > +        create_fdt_socket_cpus(s, socket, clust_name, phandle,
> > +            is_32_bit, intc_phandles);
> >
> > -            cpu_name = g_strdup_printf("/cpus/cpu@%d",
> > -                s->soc[socket].hartid_base + cpu);
> > -            qemu_fdt_add_subnode(fdt, cpu_name);
> > -            if (is_32_bit) {
> > -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
> > -            } else {
> > -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
> > -            }
> > -            name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
> > -            g_free(name);
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
> > -            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
> > -                s->soc[socket].hartid_base + cpu);
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
> > -            riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket);
> > -            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
> > -
> > -            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> > -            qemu_fdt_add_subnode(fdt, intc_name);
> > -            intc_phandle = phandle++;
> > -            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
> > -            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> > -                "riscv,cpu-intc");
> > -            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
> > -            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
> > -
> > -            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> > -            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> > -            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> > -            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
> > -
> > -            plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> > -            plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> > -            plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> > -            plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> > -
> > -            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> > -            qemu_fdt_add_subnode(fdt, core_name);
> > -            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
> > -
> > -            g_free(core_name);
> > -            g_free(intc_name);
> > -            g_free(cpu_name);
> > -        }
> > +        create_fdt_socket_memory(s, memmap, socket);
> >
> > -        addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> > -        size = riscv_socket_mem_size(mc, socket);
> > -        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> > -        qemu_fdt_add_subnode(fdt, mem_name);
> > -        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
> > -            addr >> 32, addr, size >> 32, size);
> > -        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
> > -        riscv_socket_fdt_write_id(mc, fdt, mem_name, socket);
> > -        g_free(mem_name);
> > -
> > -        clint_addr = memmap[VIRT_CLINT].base +
> > -            (memmap[VIRT_CLINT].size * socket);
> > -        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> > -        qemu_fdt_add_subnode(fdt, clint_name);
> > -        qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
> > -        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
> > -            0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> > -        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
> > -            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > -        riscv_socket_fdt_write_id(mc, fdt, clint_name, socket);
> > -        g_free(clint_name);
> > -
> > -        plic_phandle[socket] = phandle++;
> > -        plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> > -        plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> > -        qemu_fdt_add_subnode(fdt, plic_name);
> > -        qemu_fdt_setprop_cell(fdt, plic_name,
> > -            "#address-cells", FDT_PLIC_ADDR_CELLS);
> > -        qemu_fdt_setprop_cell(fdt, plic_name,
> > -            "#interrupt-cells", FDT_PLIC_INT_CELLS);
> > -        qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
> > -        qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
> > -        qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
> > -            plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > -        qemu_fdt_setprop_cells(fdt, plic_name, "reg",
> > -            0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> > -        qemu_fdt_setprop_cell(fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> > -        riscv_socket_fdt_write_id(mc, fdt, plic_name, socket);
> > -        qemu_fdt_setprop_cell(fdt, plic_name, "phandle", plic_phandle[socket]);
> > -        g_free(plic_name);
> > -
> > -        g_free(clint_cells);
> > -        g_free(plic_cells);
> > +        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> > +
> > +        create_fdt_socket_plic(s, memmap, socket, phandle,
> > +            intc_phandles, xplic_phandles);
> > +
> > +        g_free(intc_phandles);
> >          g_free(clust_name);
> >      }
> >
> >      for (socket = 0; socket < riscv_socket_count(mc); socket++) {
> >          if (socket == 0) {
> > -            plic_mmio_phandle = plic_phandle[socket];
> > -            plic_virtio_phandle = plic_phandle[socket];
> > -            plic_pcie_phandle = plic_phandle[socket];
> > +            *irq_mmio_phandle = xplic_phandles[socket];
> > +            *irq_virtio_phandle = xplic_phandles[socket];
> > +            *irq_pcie_phandle = xplic_phandles[socket];
> >          }
> >          if (socket == 1) {
> > -            plic_virtio_phandle = plic_phandle[socket];
> > -            plic_pcie_phandle = plic_phandle[socket];
> > +            *irq_virtio_phandle = xplic_phandles[socket];
> > +            *irq_pcie_phandle = xplic_phandles[socket];
> >          }
> >          if (socket == 2) {
> > -            plic_pcie_phandle = plic_phandle[socket];
> > +            *irq_pcie_phandle = xplic_phandles[socket];
> >          }
> >      }
> >
> > -    riscv_socket_fdt_write_distance_matrix(mc, fdt);
> > +    riscv_socket_fdt_write_distance_matrix(mc, mc->fdt);
> > +}
> > +
> > +static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                              uint32_t irq_virtio_phandle)
> > +{
> > +    int i;
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      for (i = 0; i < VIRTIO_COUNT; i++) {
> >          name = g_strdup_printf("/soc/virtio_mmio@%lx",
> >              (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
> > -        qemu_fdt_add_subnode(fdt, name);
> > -        qemu_fdt_setprop_string(fdt, name, "compatible", "virtio,mmio");
> > -        qemu_fdt_setprop_cells(fdt, name, "reg",
> > +        qemu_fdt_add_subnode(mc->fdt, name);
> > +        qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio");
> > +        qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> >              0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
> >              0x0, memmap[VIRT_VIRTIO].size);
> > -        qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
> > -            plic_virtio_phandle);
> > -        qemu_fdt_setprop_cell(fdt, name, "interrupts", VIRTIO_IRQ + i);
> > +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> > +            irq_virtio_phandle);
> > +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i);
> >          g_free(name);
> >      }
> > +}
> > +
> > +static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                            uint32_t irq_pcie_phandle)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      name = g_strdup_printf("/soc/pci@%lx",
> >          (long) memmap[VIRT_PCIE_ECAM].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    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,
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells",
> > +        FDT_PCI_ADDR_CELLS);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells",
> > +        FDT_PCI_INT_CELLS);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> > +        "pci-host-ecam-generic");
> > +    qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci");
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0);
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0,
> >          memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> > -    qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> > -    qemu_fdt_setprop_cells(fdt, name, "reg", 0,
> > +    qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0);
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0,
> >          memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
> > -    qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> > +    qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges",
> >          1, FDT_PCI_RANGE_IOPORT, 2, 0,
> >          2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
> >          1, FDT_PCI_RANGE_MMIO,
> > @@ -387,63 +434,93 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >          2, virt_high_pcie_memmap.base,
> >          2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
> >
> > -    create_pcie_irq_map(fdt, name, plic_pcie_phandle);
> > +    create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                             uint32_t *phandle)
> > +{
> > +    char *name;
> > +    uint32_t test_phandle;
> > +    MachineState *mc = MACHINE(s);
> >
> > -    test_phandle = phandle++;
> > +    test_phandle = (*phandle)++;
> >      name = g_strdup_printf("/soc/test@%lx",
> >          (long)memmap[VIRT_TEST].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> >      {
> >          const char compat[] = "sifive,test1\0sifive,test0\0syscon";
> > -        qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
> > +        qemu_fdt_setprop(mc->fdt, name, "compatible", compat, sizeof(compat));
> >      }
> > -    qemu_fdt_setprop_cells(fdt, name, "reg",
> > -        0x0, memmap[VIRT_TEST].base,
> > -        0x0, memmap[VIRT_TEST].size);
> > -    qemu_fdt_setprop_cell(fdt, name, "phandle", test_phandle);
> > -    test_phandle = qemu_fdt_get_phandle(fdt, name);
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle);
> > +    test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
> >      g_free(name);
> >
> >      name = g_strdup_printf("/soc/reboot");
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
> > -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> > -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_RESET);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
> >      g_free(name);
> >
> >      name = g_strdup_printf("/soc/poweroff");
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
> > -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> > -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_PASS);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                            uint32_t irq_mmio_phandle)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> > -    qemu_fdt_setprop_cells(fdt, name, "reg",
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> >          0x0, memmap[VIRT_UART0].base,
> >          0x0, memmap[VIRT_UART0].size);
> > -    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupts", UART0_IRQ);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
> >
> > -    qemu_fdt_add_subnode(fdt, "/chosen");
> > -    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
> > +    qemu_fdt_add_subnode(mc->fdt, "/chosen");
> > +    qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                           uint32_t irq_mmio_phandle)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
> > -    qemu_fdt_setprop_cells(fdt, name, "reg",
> > -        0x0, memmap[VIRT_RTC].base,
> > -        0x0, memmap[VIRT_RTC].size);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> > +        "google,goldfish-rtc");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> > +        irq_mmio_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> > +    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> > +    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
> >
> >      name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
> >      qemu_fdt_add_subnode(mc->fdt, name);
> > @@ -453,10 +530,59 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >                                   2, flashbase + flashsize, 2, flashsize);
> >      qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> > +{
> > +    MachineState *mc = MACHINE(s);
> > +    uint32_t phandle = 1, irq_mmio_phandle = 1;
> > +    uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
> > +
> > +    if (mc->dtb) {
> > +        mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> > +        if (!mc->fdt) {
> > +            error_report("load_device_tree() failed");
> > +            exit(1);
> > +        }
> > +        goto update_bootargs;
> > +    } else {
> > +        mc->fdt = create_device_tree(&s->fdt_size);
> > +        if (!mc->fdt) {
> > +            error_report("create_device_tree() failed");
> > +            exit(1);
> > +        }
> > +    }
> > +
> > +    qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu");
> > +    qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2);
> > +    qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2);
> > +
> > +    qemu_fdt_add_subnode(mc->fdt, "/soc");
> > +    qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0);
> > +    qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2);
> > +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2);
> > +
> > +    create_fdt_sockets(s, memmap, is_32_bit, &phandle,
> > +        &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle);
> > +
> > +    create_fdt_virtio(s, memmap, irq_virtio_phandle);
> > +
> > +    create_fdt_pcie(s, memmap, irq_pcie_phandle);
> > +
> > +    create_fdt_reset(s, memmap, &phandle);
> > +
> > +    create_fdt_uart(s, memmap, irq_mmio_phandle);
> > +
> > +    create_fdt_rtc(s, memmap, irq_mmio_phandle);
> > +
> > +    create_fdt_flash(s, memmap);
> >
> >  update_bootargs:
> >      if (cmdline) {
> > -        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
> > +        qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
> >      }
> >  }
>
> Regards,
> Bin


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

* Re: [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation
@ 2021-07-12  5:40       ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12  5:40 UTC (permalink / raw)
  To: Bin Meng
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Sun, Jun 13, 2021 at 12:12 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We re-factor and break the FDT generation into smaller functions
> > so that it is easier to modify FDT generation for different
> > configurations of virt machine.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  hw/riscv/virt.c | 514 ++++++++++++++++++++++++++++++------------------
> >  1 file changed, 320 insertions(+), 194 deletions(-)
> >
> > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > index 5eb63f6efd..977d699753 100644
> > --- a/hw/riscv/virt.c
> > +++ b/hw/riscv/virt.c
> > @@ -178,206 +178,253 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
> >                             0x1800, 0, 0, 0x7);
> >  }
> >
> > -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> > -                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> > +static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
> > +                                   char *clust_name, uint32_t *phandle,
> > +                                   bool is_32_bit, uint32_t *intc_phandles)
> >  {
> > -    void *fdt;
> > -    int i, cpu, socket;
> > +    int cpu;
> > +    uint32_t cpu_phandle;
> >      MachineState *mc = MACHINE(s);
> > +    char *name, *cpu_name, *core_name, *intc_name;
> > +
> > +    for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> > +        cpu_phandle = (*phandle)++;
> > +
> > +        cpu_name = g_strdup_printf("/cpus/cpu@%d",
> > +            s->soc[socket].hartid_base + cpu);
> > +        qemu_fdt_add_subnode(mc->fdt, cpu_name);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type",
> > +            (is_32_bit) ? "riscv,sv32" : "riscv,sv48");
> > +        name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name);
> > +        g_free(name);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv");
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay");
> > +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg",
> > +            s->soc[socket].hartid_base + cpu);
> > +        qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu");
> > +        riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket);
> > +        qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle);
> > +
> > +        intc_phandles[cpu] = (*phandle)++;
> > +
> > +        intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> > +        qemu_fdt_add_subnode(mc->fdt, intc_name);
> > +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle",
> > +            intc_phandles[cpu]);
> > +        qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible",
> > +            "riscv,cpu-intc");
> > +        qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0);
> > +        qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1);
> > +
> > +        core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> > +        qemu_fdt_add_subnode(mc->fdt, core_name);
> > +        qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle);
> > +
> > +        g_free(core_name);
> > +        g_free(intc_name);
> > +        g_free(cpu_name);
> > +    }
> > +}
> > +
> > +static void create_fdt_socket_memory(RISCVVirtState *s,
> > +                                     const MemMapEntry *memmap, int socket)
> > +{
> > +    char *mem_name;
> >      uint64_t addr, size;
> > -    uint32_t *clint_cells, *plic_cells;
> > -    unsigned long clint_addr, plic_addr;
> > -    uint32_t plic_phandle[MAX_NODES];
> > -    uint32_t cpu_phandle, intc_phandle, test_phandle;
> > -    uint32_t phandle = 1, plic_mmio_phandle = 1;
> > -    uint32_t plic_pcie_phandle = 1, plic_virtio_phandle = 1;
> > -    char *mem_name, *cpu_name, *core_name, *intc_name;
> > -    char *name, *clint_name, *plic_name, *clust_name;
> > -    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> > -    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
> > +    MachineState *mc = MACHINE(s);
> >
> > -    if (mc->dtb) {
> > -        fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> > -        if (!fdt) {
> > -            error_report("load_device_tree() failed");
> > -            exit(1);
> > -        }
> > -        goto update_bootargs;
> > -    } else {
> > -        fdt = mc->fdt = create_device_tree(&s->fdt_size);
> > -        if (!fdt) {
> > -            error_report("create_device_tree() failed");
> > -            exit(1);
> > -        }
> > +    addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> > +    size = riscv_socket_mem_size(mc, socket);
> > +    mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> > +    qemu_fdt_add_subnode(mc->fdt, mem_name);
> > +    qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg",
> > +        addr >> 32, addr, size >> 32, size);
> > +    qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory");
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket);
> > +    g_free(mem_name);
> > +}
> > +
> > +static void create_fdt_socket_clint(RISCVVirtState *s,
> > +                                    const MemMapEntry *memmap, int socket,
> > +                                    uint32_t *intc_phandles)
> > +{
> > +    int cpu;
> > +    char *clint_name;
> > +    uint32_t *clint_cells;
> > +    unsigned long clint_addr;
> > +    MachineState *mc = MACHINE(s);
> > +
> > +    clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> > +
> > +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> > +        clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> > +        clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> > +        clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> > +        clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
> >      }
> >
> > -    qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
> > -    qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
> > -    qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
> > -    qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
> > +    clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket);
> > +    clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> > +    qemu_fdt_add_subnode(mc->fdt, clint_name);
> > +    qemu_fdt_setprop_string(mc->fdt, clint_name, "compatible",
> > +        "riscv,clint0");
>
> This patch seems to be based on some old commit, as the latest QEMU
> head has the following commit that supports the official clint
> compatible name via:
>
> commit b387236bff95 ("hw/riscv: Support the official CLINT DT bindings")

Yes, I will be rebasing on the most recent tree of Alistair.

Regards,
Anup

>
> > +    qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg",
> > +        0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> > +    qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended",
> > +        clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket);
> > +    g_free(clint_name);
> > +
> > +    g_free(clint_cells);
> > +}
> > +
> > +static void create_fdt_socket_plic(RISCVVirtState *s,
> > +                                   const MemMapEntry *memmap, int socket,
> > +                                   uint32_t *phandle, uint32_t *intc_phandles,
> > +                                   uint32_t *plic_phandles)
> > +{
> > +    int cpu;
> > +    char *plic_name;
> > +    uint32_t *plic_cells;
> > +    unsigned long plic_addr;
> > +    MachineState *mc = MACHINE(s);
> >
> > -    qemu_fdt_add_subnode(fdt, "/soc");
> > -    qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
> > -    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
> > -    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
> > -    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
> > +    plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> >
> > -    qemu_fdt_add_subnode(fdt, "/cpus");
> > -    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
> > +    for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
> > +        plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
> > +        plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> > +        plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
> > +        plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> > +    }
> > +
> > +    plic_phandles[socket] = (*phandle)++;
> > +    plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> > +    plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> > +    qemu_fdt_add_subnode(mc->fdt, plic_name);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> > +        "#address-cells", FDT_PLIC_ADDR_CELLS);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name,
> > +        "#interrupt-cells", FDT_PLIC_INT_CELLS);
> > +    qemu_fdt_setprop_string(mc->fdt, plic_name, "compatible", "riscv,plic0");
> > +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0);
> > +    qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended",
> > +        plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > +    qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
> > +        0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> > +    riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
> > +    qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
> > +        plic_phandles[socket]);
> > +    g_free(plic_name);
> > +
> > +    g_free(plic_cells);
> > +}
> > +
> > +static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                               bool is_32_bit, uint32_t *phandle,
> > +                               uint32_t *irq_mmio_phandle,
> > +                               uint32_t *irq_pcie_phandle,
> > +                               uint32_t *irq_virtio_phandle)
> > +{
> > +    int socket;
> > +    char *clust_name;
> > +    uint32_t *intc_phandles;
> > +    MachineState *mc = MACHINE(s);
> > +    uint32_t xplic_phandles[MAX_NODES];
> > +
> > +    qemu_fdt_add_subnode(mc->fdt, "/cpus");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency",
> >                            RISCV_ACLINT_TIMEBASE_FREQ);
> > -    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
> > -    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
> > -    qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0);
> > +    qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1);
> > +    qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map");
> >
> >      for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) {
> >          clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket);
> > -        qemu_fdt_add_subnode(fdt, clust_name);
> > +        qemu_fdt_add_subnode(mc->fdt, clust_name);
> >
> > -        plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> > -        clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
> > +        intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts);
> >
> > -        for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
> > -            cpu_phandle = phandle++;
> > +        create_fdt_socket_cpus(s, socket, clust_name, phandle,
> > +            is_32_bit, intc_phandles);
> >
> > -            cpu_name = g_strdup_printf("/cpus/cpu@%d",
> > -                s->soc[socket].hartid_base + cpu);
> > -            qemu_fdt_add_subnode(fdt, cpu_name);
> > -            if (is_32_bit) {
> > -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv32");
> > -            } else {
> > -                qemu_fdt_setprop_string(fdt, cpu_name, "mmu-type", "riscv,sv48");
> > -            }
> > -            name = riscv_isa_string(&s->soc[socket].harts[cpu]);
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "riscv,isa", name);
> > -            g_free(name);
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "compatible", "riscv");
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
> > -            qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
> > -                s->soc[socket].hartid_base + cpu);
> > -            qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
> > -            riscv_socket_fdt_write_id(mc, fdt, cpu_name, socket);
> > -            qemu_fdt_setprop_cell(fdt, cpu_name, "phandle", cpu_phandle);
> > -
> > -            intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name);
> > -            qemu_fdt_add_subnode(fdt, intc_name);
> > -            intc_phandle = phandle++;
> > -            qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
> > -            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> > -                "riscv,cpu-intc");
> > -            qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
> > -            qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
> > -
> > -            clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> > -            clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
> > -            clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> > -            clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
> > -
> > -            plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
> > -            plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
> > -            plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
> > -            plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
> > -
> > -            core_name = g_strdup_printf("%s/core%d", clust_name, cpu);
> > -            qemu_fdt_add_subnode(fdt, core_name);
> > -            qemu_fdt_setprop_cell(fdt, core_name, "cpu", cpu_phandle);
> > -
> > -            g_free(core_name);
> > -            g_free(intc_name);
> > -            g_free(cpu_name);
> > -        }
> > +        create_fdt_socket_memory(s, memmap, socket);
> >
> > -        addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket);
> > -        size = riscv_socket_mem_size(mc, socket);
> > -        mem_name = g_strdup_printf("/memory@%lx", (long)addr);
> > -        qemu_fdt_add_subnode(fdt, mem_name);
> > -        qemu_fdt_setprop_cells(fdt, mem_name, "reg",
> > -            addr >> 32, addr, size >> 32, size);
> > -        qemu_fdt_setprop_string(fdt, mem_name, "device_type", "memory");
> > -        riscv_socket_fdt_write_id(mc, fdt, mem_name, socket);
> > -        g_free(mem_name);
> > -
> > -        clint_addr = memmap[VIRT_CLINT].base +
> > -            (memmap[VIRT_CLINT].size * socket);
> > -        clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
> > -        qemu_fdt_add_subnode(fdt, clint_name);
> > -        qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
> > -        qemu_fdt_setprop_cells(fdt, clint_name, "reg",
> > -            0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size);
> > -        qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
> > -            clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > -        riscv_socket_fdt_write_id(mc, fdt, clint_name, socket);
> > -        g_free(clint_name);
> > -
> > -        plic_phandle[socket] = phandle++;
> > -        plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
> > -        plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
> > -        qemu_fdt_add_subnode(fdt, plic_name);
> > -        qemu_fdt_setprop_cell(fdt, plic_name,
> > -            "#address-cells", FDT_PLIC_ADDR_CELLS);
> > -        qemu_fdt_setprop_cell(fdt, plic_name,
> > -            "#interrupt-cells", FDT_PLIC_INT_CELLS);
> > -        qemu_fdt_setprop_string(fdt, plic_name, "compatible", "riscv,plic0");
> > -        qemu_fdt_setprop(fdt, plic_name, "interrupt-controller", NULL, 0);
> > -        qemu_fdt_setprop(fdt, plic_name, "interrupts-extended",
> > -            plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
> > -        qemu_fdt_setprop_cells(fdt, plic_name, "reg",
> > -            0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
> > -        qemu_fdt_setprop_cell(fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
> > -        riscv_socket_fdt_write_id(mc, fdt, plic_name, socket);
> > -        qemu_fdt_setprop_cell(fdt, plic_name, "phandle", plic_phandle[socket]);
> > -        g_free(plic_name);
> > -
> > -        g_free(clint_cells);
> > -        g_free(plic_cells);
> > +        create_fdt_socket_clint(s, memmap, socket, intc_phandles);
> > +
> > +        create_fdt_socket_plic(s, memmap, socket, phandle,
> > +            intc_phandles, xplic_phandles);
> > +
> > +        g_free(intc_phandles);
> >          g_free(clust_name);
> >      }
> >
> >      for (socket = 0; socket < riscv_socket_count(mc); socket++) {
> >          if (socket == 0) {
> > -            plic_mmio_phandle = plic_phandle[socket];
> > -            plic_virtio_phandle = plic_phandle[socket];
> > -            plic_pcie_phandle = plic_phandle[socket];
> > +            *irq_mmio_phandle = xplic_phandles[socket];
> > +            *irq_virtio_phandle = xplic_phandles[socket];
> > +            *irq_pcie_phandle = xplic_phandles[socket];
> >          }
> >          if (socket == 1) {
> > -            plic_virtio_phandle = plic_phandle[socket];
> > -            plic_pcie_phandle = plic_phandle[socket];
> > +            *irq_virtio_phandle = xplic_phandles[socket];
> > +            *irq_pcie_phandle = xplic_phandles[socket];
> >          }
> >          if (socket == 2) {
> > -            plic_pcie_phandle = plic_phandle[socket];
> > +            *irq_pcie_phandle = xplic_phandles[socket];
> >          }
> >      }
> >
> > -    riscv_socket_fdt_write_distance_matrix(mc, fdt);
> > +    riscv_socket_fdt_write_distance_matrix(mc, mc->fdt);
> > +}
> > +
> > +static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                              uint32_t irq_virtio_phandle)
> > +{
> > +    int i;
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      for (i = 0; i < VIRTIO_COUNT; i++) {
> >          name = g_strdup_printf("/soc/virtio_mmio@%lx",
> >              (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
> > -        qemu_fdt_add_subnode(fdt, name);
> > -        qemu_fdt_setprop_string(fdt, name, "compatible", "virtio,mmio");
> > -        qemu_fdt_setprop_cells(fdt, name, "reg",
> > +        qemu_fdt_add_subnode(mc->fdt, name);
> > +        qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio");
> > +        qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> >              0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
> >              0x0, memmap[VIRT_VIRTIO].size);
> > -        qemu_fdt_setprop_cell(fdt, name, "interrupt-parent",
> > -            plic_virtio_phandle);
> > -        qemu_fdt_setprop_cell(fdt, name, "interrupts", VIRTIO_IRQ + i);
> > +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> > +            irq_virtio_phandle);
> > +        qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i);
> >          g_free(name);
> >      }
> > +}
> > +
> > +static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                            uint32_t irq_pcie_phandle)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      name = g_strdup_printf("/soc/pci@%lx",
> >          (long) memmap[VIRT_PCIE_ECAM].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    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,
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells",
> > +        FDT_PCI_ADDR_CELLS);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells",
> > +        FDT_PCI_INT_CELLS);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> > +        "pci-host-ecam-generic");
> > +    qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci");
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0);
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0,
> >          memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1);
> > -    qemu_fdt_setprop(fdt, name, "dma-coherent", NULL, 0);
> > -    qemu_fdt_setprop_cells(fdt, name, "reg", 0,
> > +    qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0);
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0,
> >          memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size);
> > -    qemu_fdt_setprop_sized_cells(fdt, name, "ranges",
> > +    qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges",
> >          1, FDT_PCI_RANGE_IOPORT, 2, 0,
> >          2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
> >          1, FDT_PCI_RANGE_MMIO,
> > @@ -387,63 +434,93 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >          2, virt_high_pcie_memmap.base,
> >          2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
> >
> > -    create_pcie_irq_map(fdt, name, plic_pcie_phandle);
> > +    create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                             uint32_t *phandle)
> > +{
> > +    char *name;
> > +    uint32_t test_phandle;
> > +    MachineState *mc = MACHINE(s);
> >
> > -    test_phandle = phandle++;
> > +    test_phandle = (*phandle)++;
> >      name = g_strdup_printf("/soc/test@%lx",
> >          (long)memmap[VIRT_TEST].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> >      {
> >          const char compat[] = "sifive,test1\0sifive,test0\0syscon";
> > -        qemu_fdt_setprop(fdt, name, "compatible", compat, sizeof(compat));
> > +        qemu_fdt_setprop(mc->fdt, name, "compatible", compat, sizeof(compat));
> >      }
> > -    qemu_fdt_setprop_cells(fdt, name, "reg",
> > -        0x0, memmap[VIRT_TEST].base,
> > -        0x0, memmap[VIRT_TEST].size);
> > -    qemu_fdt_setprop_cell(fdt, name, "phandle", test_phandle);
> > -    test_phandle = qemu_fdt_get_phandle(fdt, name);
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle);
> > +    test_phandle = qemu_fdt_get_phandle(mc->fdt, name);
> >      g_free(name);
> >
> >      name = g_strdup_printf("/soc/reboot");
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
> > -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> > -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_RESET);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot");
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET);
> >      g_free(name);
> >
> >      name = g_strdup_printf("/soc/poweroff");
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-poweroff");
> > -    qemu_fdt_setprop_cell(fdt, name, "regmap", test_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "offset", 0x0);
> > -    qemu_fdt_setprop_cell(fdt, name, "value", FINISHER_PASS);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff");
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                            uint32_t irq_mmio_phandle)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
> > -    qemu_fdt_setprop_cells(fdt, name, "reg",
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> >          0x0, memmap[VIRT_UART0].base,
> >          0x0, memmap[VIRT_UART0].size);
> > -    qemu_fdt_setprop_cell(fdt, name, "clock-frequency", 3686400);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupts", UART0_IRQ);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
> >
> > -    qemu_fdt_add_subnode(fdt, "/chosen");
> > -    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", name);
> > +    qemu_fdt_add_subnode(mc->fdt, "/chosen");
> > +    qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                           uint32_t irq_mmio_phandle)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> >
> >      name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base);
> > -    qemu_fdt_add_subnode(fdt, name);
> > -    qemu_fdt_setprop_string(fdt, name, "compatible", "google,goldfish-rtc");
> > -    qemu_fdt_setprop_cells(fdt, name, "reg",
> > -        0x0, memmap[VIRT_RTC].base,
> > -        0x0, memmap[VIRT_RTC].size);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", plic_mmio_phandle);
> > -    qemu_fdt_setprop_cell(fdt, name, "interrupts", RTC_IRQ);
> > +    qemu_fdt_add_subnode(mc->fdt, name);
> > +    qemu_fdt_setprop_string(mc->fdt, name, "compatible",
> > +        "google,goldfish-rtc");
> > +    qemu_fdt_setprop_cells(mc->fdt, name, "reg",
> > +        0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
> > +        irq_mmio_phandle);
> > +    qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap)
> > +{
> > +    char *name;
> > +    MachineState *mc = MACHINE(s);
> > +    hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
> > +    hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
> >
> >      name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
> >      qemu_fdt_add_subnode(mc->fdt, name);
> > @@ -453,10 +530,59 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> >                                   2, flashbase + flashsize, 2, flashsize);
> >      qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
> >      g_free(name);
> > +}
> > +
> > +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
> > +                       uint64_t mem_size, const char *cmdline, bool is_32_bit)
> > +{
> > +    MachineState *mc = MACHINE(s);
> > +    uint32_t phandle = 1, irq_mmio_phandle = 1;
> > +    uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1;
> > +
> > +    if (mc->dtb) {
> > +        mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
> > +        if (!mc->fdt) {
> > +            error_report("load_device_tree() failed");
> > +            exit(1);
> > +        }
> > +        goto update_bootargs;
> > +    } else {
> > +        mc->fdt = create_device_tree(&s->fdt_size);
> > +        if (!mc->fdt) {
> > +            error_report("create_device_tree() failed");
> > +            exit(1);
> > +        }
> > +    }
> > +
> > +    qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu");
> > +    qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2);
> > +    qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2);
> > +
> > +    qemu_fdt_add_subnode(mc->fdt, "/soc");
> > +    qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0);
> > +    qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus");
> > +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2);
> > +    qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2);
> > +
> > +    create_fdt_sockets(s, memmap, is_32_bit, &phandle,
> > +        &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle);
> > +
> > +    create_fdt_virtio(s, memmap, irq_virtio_phandle);
> > +
> > +    create_fdt_pcie(s, memmap, irq_pcie_phandle);
> > +
> > +    create_fdt_reset(s, memmap, &phandle);
> > +
> > +    create_fdt_uart(s, memmap, irq_mmio_phandle);
> > +
> > +    create_fdt_rtc(s, memmap, irq_mmio_phandle);
> > +
> > +    create_fdt_flash(s, memmap);
> >
> >  update_bootargs:
> >      if (cmdline) {
> > -        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
> > +        qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline);
> >      }
> >  }
>
> Regards,
> Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-07-12  5:38       ` Anup Patel
@ 2021-07-12  6:15         ` Bin Meng
  -1 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-07-12  6:15 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > >
> > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > parameter is passed along with machine name in QEMU command-line.
> > >
> > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > ---
> > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > >  include/hw/riscv/virt.h |   2 +
> > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > index 977d699753..a35f66af13 100644
> > > --- a/hw/riscv/virt.c
> > > +++ b/hw/riscv/virt.c
> > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> >
> > How about we reuse the same register space to support both CLINT and
> > ACLINT? This saves some register space for future extension.
>
> The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> MSWI is to minimize PMP region usage.

Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
for 64 ACLINT SSWI devices. Is this enough?

>
> When we have multiple sockets, each socket will have it's own set of
> ACLINT devices so we deliberately keep ACLINT MTIMER and MSWI
> devices of all sockets next to each other so that we need just 1-2 PMP
> regions to cover all M-level ACLINT devices.
>
> In general, RISC-V platform vendors will have to carefully design
> memory layout of M-level devices so that M-mode runtime firmware
> needs fewer PMP regions. The spare PMP regions can be used by
> M-mode runtime firmware to partition the system into domains and
> implement TEE.
>
> >
> > >      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
> > >      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
> > >      [VIRT_UART0] =       { 0x10000000,         0x100 },
> > > @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
> > >      g_free(clint_cells);
> > >  }

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-07-12  6:15         ` Bin Meng
  0 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-07-12  6:15 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > >
> > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > parameter is passed along with machine name in QEMU command-line.
> > >
> > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > ---
> > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > >  include/hw/riscv/virt.h |   2 +
> > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > index 977d699753..a35f66af13 100644
> > > --- a/hw/riscv/virt.c
> > > +++ b/hw/riscv/virt.c
> > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> >
> > How about we reuse the same register space to support both CLINT and
> > ACLINT? This saves some register space for future extension.
>
> The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> MSWI is to minimize PMP region usage.

Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
for 64 ACLINT SSWI devices. Is this enough?

>
> When we have multiple sockets, each socket will have it's own set of
> ACLINT devices so we deliberately keep ACLINT MTIMER and MSWI
> devices of all sockets next to each other so that we need just 1-2 PMP
> regions to cover all M-level ACLINT devices.
>
> In general, RISC-V platform vendors will have to carefully design
> memory layout of M-level devices so that M-mode runtime firmware
> needs fewer PMP regions. The spare PMP regions can be used by
> M-mode runtime firmware to partition the system into domains and
> implement TEE.
>
> >
> > >      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
> > >      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
> > >      [VIRT_UART0] =       { 0x10000000,         0x100 },
> > > @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
> > >      g_free(clint_cells);
> > >  }

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-07-12  6:15         ` Bin Meng
@ 2021-07-12 10:53           ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12 10:53 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > >
> > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > >
> > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > parameter is passed along with machine name in QEMU command-line.
> > > >
> > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > ---
> > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > >  include/hw/riscv/virt.h |   2 +
> > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > index 977d699753..a35f66af13 100644
> > > > --- a/hw/riscv/virt.c
> > > > +++ b/hw/riscv/virt.c
> > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > >
> > > How about we reuse the same register space to support both CLINT and
> > > ACLINT? This saves some register space for future extension.
> >
> > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > MSWI is to minimize PMP region usage.
>
> Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> for 64 ACLINT SSWI devices. Is this enough?

We just need one instance of MTIMER, MSWI, and SSWI per-socket.
Current limit of max sockets in RISC-V virt machine is 8. We will be
reducing this to 4 due space required by IMSICs. This means no matter
what 8 instances of each MTIMER, MSWI, and SSWI is the max we
can go for RISC-V virt machine. This limits are due to the fact that
we want to fit devices in first 2GB space.

Regards,
Anup

>
> >
> > When we have multiple sockets, each socket will have it's own set of
> > ACLINT devices so we deliberately keep ACLINT MTIMER and MSWI
> > devices of all sockets next to each other so that we need just 1-2 PMP
> > regions to cover all M-level ACLINT devices.
> >
> > In general, RISC-V platform vendors will have to carefully design
> > memory layout of M-level devices so that M-mode runtime firmware
> > needs fewer PMP regions. The spare PMP regions can be used by
> > M-mode runtime firmware to partition the system into domains and
> > implement TEE.
> >
> > >
> > > >      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
> > > >      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
> > > >      [VIRT_UART0] =       { 0x10000000,         0x100 },
> > > > @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
> > > >      g_free(clint_cells);
> > > >  }
>
> Regards,
> Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-07-12 10:53           ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12 10:53 UTC (permalink / raw)
  To: Bin Meng
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > >
> > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > >
> > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > parameter is passed along with machine name in QEMU command-line.
> > > >
> > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > ---
> > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > >  include/hw/riscv/virt.h |   2 +
> > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > index 977d699753..a35f66af13 100644
> > > > --- a/hw/riscv/virt.c
> > > > +++ b/hw/riscv/virt.c
> > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > >
> > > How about we reuse the same register space to support both CLINT and
> > > ACLINT? This saves some register space for future extension.
> >
> > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > MSWI is to minimize PMP region usage.
>
> Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> for 64 ACLINT SSWI devices. Is this enough?

We just need one instance of MTIMER, MSWI, and SSWI per-socket.
Current limit of max sockets in RISC-V virt machine is 8. We will be
reducing this to 4 due space required by IMSICs. This means no matter
what 8 instances of each MTIMER, MSWI, and SSWI is the max we
can go for RISC-V virt machine. This limits are due to the fact that
we want to fit devices in first 2GB space.

Regards,
Anup

>
> >
> > When we have multiple sockets, each socket will have it's own set of
> > ACLINT devices so we deliberately keep ACLINT MTIMER and MSWI
> > devices of all sockets next to each other so that we need just 1-2 PMP
> > regions to cover all M-level ACLINT devices.
> >
> > In general, RISC-V platform vendors will have to carefully design
> > memory layout of M-level devices so that M-mode runtime firmware
> > needs fewer PMP regions. The spare PMP regions can be used by
> > M-mode runtime firmware to partition the system into domains and
> > implement TEE.
> >
> > >
> > > >      [VIRT_PCIE_PIO] =    {  0x3000000,       0x10000 },
> > > >      [VIRT_PLIC] =        {  0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
> > > >      [VIRT_UART0] =       { 0x10000000,         0x100 },
> > > > @@ -279,6 +280,78 @@ static void create_fdt_socket_clint(RISCVVirtState *s,
> > > >      g_free(clint_cells);
> > > >  }
>
> Regards,
> Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-07-12 10:53           ` Anup Patel
@ 2021-07-12 13:11             ` Bin Meng
  -1 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-07-12 13:11 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jul 12, 2021 at 6:54 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > >
> > > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > >
> > > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > > parameter is passed along with machine name in QEMU command-line.
> > > > >
> > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > ---
> > > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > > >  include/hw/riscv/virt.h |   2 +
> > > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > > index 977d699753..a35f66af13 100644
> > > > > --- a/hw/riscv/virt.c
> > > > > +++ b/hw/riscv/virt.c
> > > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > > >
> > > > How about we reuse the same register space to support both CLINT and
> > > > ACLINT? This saves some register space for future extension.
> > >
> > > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > > MSWI is to minimize PMP region usage.
> >
> > Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> > total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> > for 64 ACLINT SSWI devices. Is this enough?
>
> We just need one instance of MTIMER, MSWI, and SSWI per-socket.
> Current limit of max sockets in RISC-V virt machine is 8. We will be
> reducing this to 4 due space required by IMSICs. This means no matter
> what 8 instances of each MTIMER, MSWI, and SSWI is the max we
> can go for RISC-V virt machine. This limits are due to the fact that
> we want to fit devices in first 2GB space.
>

Can you list the maximum ACLINT devices and their memory map we intend
to support and with that we can see how many PMP is used?

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-07-12 13:11             ` Bin Meng
  0 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-07-12 13:11 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jul 12, 2021 at 6:54 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > >
> > > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > >
> > > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > > parameter is passed along with machine name in QEMU command-line.
> > > > >
> > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > ---
> > > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > > >  include/hw/riscv/virt.h |   2 +
> > > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > > index 977d699753..a35f66af13 100644
> > > > > --- a/hw/riscv/virt.c
> > > > > +++ b/hw/riscv/virt.c
> > > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > > >
> > > > How about we reuse the same register space to support both CLINT and
> > > > ACLINT? This saves some register space for future extension.
> > >
> > > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > > MSWI is to minimize PMP region usage.
> >
> > Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> > total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> > for 64 ACLINT SSWI devices. Is this enough?
>
> We just need one instance of MTIMER, MSWI, and SSWI per-socket.
> Current limit of max sockets in RISC-V virt machine is 8. We will be
> reducing this to 4 due space required by IMSICs. This means no matter
> what 8 instances of each MTIMER, MSWI, and SSWI is the max we
> can go for RISC-V virt machine. This limits are due to the fact that
> we want to fit devices in first 2GB space.
>

Can you list the maximum ACLINT devices and their memory map we intend
to support and with that we can see how many PMP is used?

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-07-12 13:11             ` Bin Meng
@ 2021-07-12 15:02               ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12 15:02 UTC (permalink / raw)
  To: Bin Meng
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jul 12, 2021 at 6:41 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Mon, Jul 12, 2021 at 6:54 PM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> > >
> > > On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> > > >
> > > > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > > >
> > > > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > > >
> > > > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > > > parameter is passed along with machine name in QEMU command-line.
> > > > > >
> > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > > ---
> > > > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > > > >  include/hw/riscv/virt.h |   2 +
> > > > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > > > index 977d699753..a35f66af13 100644
> > > > > > --- a/hw/riscv/virt.c
> > > > > > +++ b/hw/riscv/virt.c
> > > > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > > > >
> > > > > How about we reuse the same register space to support both CLINT and
> > > > > ACLINT? This saves some register space for future extension.
> > > >
> > > > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > > > MSWI is to minimize PMP region usage.
> > >
> > > Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> > > total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> > > for 64 ACLINT SSWI devices. Is this enough?
> >
> > We just need one instance of MTIMER, MSWI, and SSWI per-socket.
> > Current limit of max sockets in RISC-V virt machine is 8. We will be
> > reducing this to 4 due space required by IMSICs. This means no matter
> > what 8 instances of each MTIMER, MSWI, and SSWI is the max we
> > can go for RISC-V virt machine. This limits are due to the fact that
> > we want to fit devices in first 2GB space.
> >
>
> Can you list the maximum ACLINT devices and their memory map we intend
> to support and with that we can see how many PMP is used?

For 4 sockets, we will have following layout:
0x2000000-0x200FFFF (Socket0 MTIMER and MSWI)
0x2010000-0x201FFFF (Socket1 MTIMER and MSWI)
0x2020000-0x202FFFF (Socket2 MTIMER and MSWI)
0x2030000-0x203FFFF (Socket3 MTIMER and MSWI)
0x2F00000-0x2F03FFF (Socket0 SSWI)
0x2F04000-0x2F07FFF (Socket1 SSWI)
0x2F08000-0x2F0bFFF (Socket2 SSWI)
0x2F0C000-0x2F0FFFF (Socket3 SSWI)

OpenSBI will create one PMP region to protect all
MTIMERs and MSWIs which is:
0x2000000-0x203FFFF

Regards,
Anup

>
> Regards,
> Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-07-12 15:02               ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-07-12 15:02 UTC (permalink / raw)
  To: Bin Meng
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jul 12, 2021 at 6:41 PM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Mon, Jul 12, 2021 at 6:54 PM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> > >
> > > On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> > > >
> > > > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > > >
> > > > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > > >
> > > > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > > > parameter is passed along with machine name in QEMU command-line.
> > > > > >
> > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > > ---
> > > > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > > > >  include/hw/riscv/virt.h |   2 +
> > > > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > > > index 977d699753..a35f66af13 100644
> > > > > > --- a/hw/riscv/virt.c
> > > > > > +++ b/hw/riscv/virt.c
> > > > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > > > >
> > > > > How about we reuse the same register space to support both CLINT and
> > > > > ACLINT? This saves some register space for future extension.
> > > >
> > > > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > > > MSWI is to minimize PMP region usage.
> > >
> > > Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> > > total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> > > for 64 ACLINT SSWI devices. Is this enough?
> >
> > We just need one instance of MTIMER, MSWI, and SSWI per-socket.
> > Current limit of max sockets in RISC-V virt machine is 8. We will be
> > reducing this to 4 due space required by IMSICs. This means no matter
> > what 8 instances of each MTIMER, MSWI, and SSWI is the max we
> > can go for RISC-V virt machine. This limits are due to the fact that
> > we want to fit devices in first 2GB space.
> >
>
> Can you list the maximum ACLINT devices and their memory map we intend
> to support and with that we can see how many PMP is used?

For 4 sockets, we will have following layout:
0x2000000-0x200FFFF (Socket0 MTIMER and MSWI)
0x2010000-0x201FFFF (Socket1 MTIMER and MSWI)
0x2020000-0x202FFFF (Socket2 MTIMER and MSWI)
0x2030000-0x203FFFF (Socket3 MTIMER and MSWI)
0x2F00000-0x2F03FFF (Socket0 SSWI)
0x2F04000-0x2F07FFF (Socket1 SSWI)
0x2F08000-0x2F0bFFF (Socket2 SSWI)
0x2F0C000-0x2F0FFFF (Socket3 SSWI)

OpenSBI will create one PMP region to protect all
MTIMERs and MSWIs which is:
0x2000000-0x203FFFF

Regards,
Anup

>
> Regards,
> Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
  2021-07-12 15:02               ` Anup Patel
@ 2021-07-12 23:05                 ` Bin Meng
  -1 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-07-12 23:05 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Mon, Jul 12, 2021 at 11:03 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Mon, Jul 12, 2021 at 6:41 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Mon, Jul 12, 2021 at 6:54 PM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > >
> > > > On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> > > > >
> > > > > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > > > >
> > > > > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > > > >
> > > > > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > > > > parameter is passed along with machine name in QEMU command-line.
> > > > > > >
> > > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > > > ---
> > > > > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > > > > >  include/hw/riscv/virt.h |   2 +
> > > > > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > > > > >
> > > > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > > > > index 977d699753..a35f66af13 100644
> > > > > > > --- a/hw/riscv/virt.c
> > > > > > > +++ b/hw/riscv/virt.c
> > > > > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > > > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > > > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > > > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > > > > >
> > > > > > How about we reuse the same register space to support both CLINT and
> > > > > > ACLINT? This saves some register space for future extension.
> > > > >
> > > > > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > > > > MSWI is to minimize PMP region usage.
> > > >
> > > > Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> > > > total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> > > > for 64 ACLINT SSWI devices. Is this enough?
> > >
> > > We just need one instance of MTIMER, MSWI, and SSWI per-socket.
> > > Current limit of max sockets in RISC-V virt machine is 8. We will be
> > > reducing this to 4 due space required by IMSICs. This means no matter
> > > what 8 instances of each MTIMER, MSWI, and SSWI is the max we
> > > can go for RISC-V virt machine. This limits are due to the fact that
> > > we want to fit devices in first 2GB space.
> > >
> >
> > Can you list the maximum ACLINT devices and their memory map we intend
> > to support and with that we can see how many PMP is used?
>
> For 4 sockets, we will have following layout:
> 0x2000000-0x200FFFF (Socket0 MTIMER and MSWI)
> 0x2010000-0x201FFFF (Socket1 MTIMER and MSWI)
> 0x2020000-0x202FFFF (Socket2 MTIMER and MSWI)
> 0x2030000-0x203FFFF (Socket3 MTIMER and MSWI)
> 0x2F00000-0x2F03FFF (Socket0 SSWI)
> 0x2F04000-0x2F07FFF (Socket1 SSWI)
> 0x2F08000-0x2F0bFFF (Socket2 SSWI)
> 0x2F0C000-0x2F0FFFF (Socket3 SSWI)
>
> OpenSBI will create one PMP region to protect all
> MTIMERs and MSWIs which is:
> 0x2000000-0x203FFFF

Thanks! This makes sense.

Regards,
Bin


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

* Re: [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine
@ 2021-07-12 23:05                 ` Bin Meng
  0 siblings, 0 replies; 34+ messages in thread
From: Bin Meng @ 2021-07-12 23:05 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Mon, Jul 12, 2021 at 11:03 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Mon, Jul 12, 2021 at 6:41 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Mon, Jul 12, 2021 at 6:54 PM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Mon, Jul 12, 2021 at 11:45 AM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > >
> > > > On Mon, Jul 12, 2021 at 1:39 PM Anup Patel <anup@brainfault.org> wrote:
> > > > >
> > > > > On Mon, Jun 14, 2021 at 5:52 PM Bin Meng <bmeng.cn@gmail.com> wrote:
> > > > > >
> > > > > > On Sun, Jun 13, 2021 at 12:14 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > > > >
> > > > > > > We extend virt machine to emulate ACLINT devices only when "aclint=on"
> > > > > > > parameter is passed along with machine name in QEMU command-line.
> > > > > > >
> > > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > > > ---
> > > > > > >  hw/riscv/virt.c         | 110 +++++++++++++++++++++++++++++++++++++++-
> > > > > > >  include/hw/riscv/virt.h |   2 +
> > > > > > >  2 files changed, 111 insertions(+), 1 deletion(-)
> > > > > > >
> > > > > > > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> > > > > > > index 977d699753..a35f66af13 100644
> > > > > > > --- a/hw/riscv/virt.c
> > > > > > > +++ b/hw/riscv/virt.c
> > > > > > > @@ -50,6 +50,7 @@ static const MemMapEntry virt_memmap[] = {
> > > > > > >      [VIRT_TEST] =        {   0x100000,        0x1000 },
> > > > > > >      [VIRT_RTC] =         {   0x101000,        0x1000 },
> > > > > > >      [VIRT_CLINT] =       {  0x2000000,       0x10000 },
> > > > > > > +    [VIRT_ACLINT_SSWI] = {  0x2F00000,        0x4000 },
> > > > > >
> > > > > > How about we reuse the same register space to support both CLINT and
> > > > > > ACLINT? This saves some register space for future extension.
> > > > >
> > > > > The intention of placing ACLINT SSWI separate from ACLINT MTIMER and
> > > > > MSWI is to minimize PMP region usage.
> > > >
> > > > Okay, so this leaves spaces for 240 ACLINT MTIMER and MSWI devices in
> > > > total, if we put ACLINT SSWI at 0x2F00000, and we still have spaces
> > > > for 64 ACLINT SSWI devices. Is this enough?
> > >
> > > We just need one instance of MTIMER, MSWI, and SSWI per-socket.
> > > Current limit of max sockets in RISC-V virt machine is 8. We will be
> > > reducing this to 4 due space required by IMSICs. This means no matter
> > > what 8 instances of each MTIMER, MSWI, and SSWI is the max we
> > > can go for RISC-V virt machine. This limits are due to the fact that
> > > we want to fit devices in first 2GB space.
> > >
> >
> > Can you list the maximum ACLINT devices and their memory map we intend
> > to support and with that we can see how many PMP is used?
>
> For 4 sockets, we will have following layout:
> 0x2000000-0x200FFFF (Socket0 MTIMER and MSWI)
> 0x2010000-0x201FFFF (Socket1 MTIMER and MSWI)
> 0x2020000-0x202FFFF (Socket2 MTIMER and MSWI)
> 0x2030000-0x203FFFF (Socket3 MTIMER and MSWI)
> 0x2F00000-0x2F03FFF (Socket0 SSWI)
> 0x2F04000-0x2F07FFF (Socket1 SSWI)
> 0x2F08000-0x2F0bFFF (Socket2 SSWI)
> 0x2F0C000-0x2F0FFFF (Socket3 SSWI)
>
> OpenSBI will create one PMP region to protect all
> MTIMERs and MSWIs which is:
> 0x2000000-0x203FFFF

Thanks! This makes sense.

Regards,
Bin


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

end of thread, other threads:[~2021-07-12 23:06 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-12 16:06 [PATCH v1 0/3] RISC-V ACLINT Support Anup Patel
2021-06-12 16:06 ` Anup Patel
2021-06-12 16:06 ` [PATCH v1 1/3] hw/intc: Upgrade the SiFive CLINT implementation to RISC-V ACLINT Anup Patel
2021-06-12 16:06   ` Anup Patel
2021-06-14 12:22   ` Bin Meng
2021-06-14 12:22     ` Bin Meng
2021-07-12  5:00     ` Anup Patel
2021-07-12  5:00       ` Anup Patel
2021-06-18  6:50   ` Alistair Francis
2021-06-18  6:50     ` Alistair Francis
2021-07-12  5:32     ` Anup Patel
2021-07-12  5:32       ` Anup Patel
2021-06-12 16:06 ` [PATCH v1 2/3] hw/riscv: virt: Re-factor FDT generation Anup Patel
2021-06-12 16:06   ` Anup Patel
2021-06-14 12:22   ` Bin Meng
2021-06-14 12:22     ` Bin Meng
2021-07-12  5:40     ` Anup Patel
2021-07-12  5:40       ` Anup Patel
2021-06-12 16:06 ` [PATCH v1 3/3] hw/riscv: virt: Add optional ACLINT support to virt machine Anup Patel
2021-06-12 16:06   ` Anup Patel
2021-06-14 12:22   ` Bin Meng
2021-06-14 12:22     ` Bin Meng
2021-07-12  5:38     ` Anup Patel
2021-07-12  5:38       ` Anup Patel
2021-07-12  6:15       ` Bin Meng
2021-07-12  6:15         ` Bin Meng
2021-07-12 10:53         ` Anup Patel
2021-07-12 10:53           ` Anup Patel
2021-07-12 13:11           ` Bin Meng
2021-07-12 13:11             ` Bin Meng
2021-07-12 15:02             ` Anup Patel
2021-07-12 15:02               ` Anup Patel
2021-07-12 23:05               ` Bin Meng
2021-07-12 23:05                 ` Bin Meng

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.