|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] xen/riscv: generate IMSIC DT node for guest domains
commit 3559e12585322e534cfd2bb27d0fcb6ff4d1834d
Author: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
AuthorDate: Wed Sep 9 17:07:32 2026 +0200
Commit: Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Mon Sep 21 10:09:00 2026 +0200
xen/riscv: generate IMSIC DT node for guest domains
Guests using the IMSIC interrupt controller require a corresponding
Device Tree description.
Add support for generating an IMSIC node when building the guest DT.
This allows guests to discover and use the IMSIC interrupt controller.
The value choosen for GUEST_IMSIC_S_BASE is an address which is typically
used for IMSIC and QEMU.
DT-building functions are marked __init because domain creation happens at
boot time, before the init sections are freed. In a typical deployment
libxl creates the interrupt controller node in userspace and hands the
complete FDT to Xen, so these functions are only called during early
domain construction.
Co-developed-by: Romain Caritey <Romain.Caritey@xxxxxxxxxxxxx>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
---
xen/arch/riscv/imsic.c | 143 +++++++++++++++++++++++++++++-
xen/arch/riscv/include/asm/guest-layout.h | 6 ++
xen/arch/riscv/include/asm/imsic.h | 3 +
3 files changed, 151 insertions(+), 1 deletion(-)
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index 809f29af86..44b8640ea3 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -13,8 +13,12 @@
#include <xen/const.h>
#include <xen/cpumask.h>
#include <xen/device_tree.h>
+#include <xen/domain.h>
#include <xen/errno.h>
+#include <xen/fdt-domain-build.h>
+#include <xen/fdt-kernel.h>
#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/macros.h>
#include <xen/sched.h>
#include <xen/smp.h>
@@ -34,6 +38,21 @@ static struct imsic_config imsic_cfg = {
.lock = SPIN_LOCK_UNLOCKED,
};
+/*
+ * Number of MSIs available to a guest. Determined by the host interrupt
+ * controller, so it is identical for every domain -- hence a single global
+ * rather than a per-domain value.
+ */
+static unsigned int __ro_after_init guest_num_msis;
+
+#define GUEST_IMSIC_COMPATIBLE "riscv,imsics"
+
+/*
+ * Value is inspired by what QEMU is using for riscv,num-ids property for IMSIC
+ * node.
+ */
+#define GUEST_IMSIC_MAX_MSIS 255U
+
#define IMSIC_DISABLE_EIDELIVERY 0
#define IMSIC_ENABLE_EIDELIVERY 1
#define IMSIC_DISABLE_EITHRESHOLD 1
@@ -182,7 +201,7 @@ static int __init imsic_get_parent_hartid(const struct
dt_device_node *node,
* or IRQ_M_EXT if the IMSIC node corresponds to a machine-mode IMSIC,
* which should be ignored by the hypervisor.
*/
-static int imsic_parse_node(const struct dt_device_node *node,
+static int __init imsic_parse_node(const struct dt_device_node *node,
unsigned int *nr_parent_irqs,
unsigned int *nr_mmios)
{
@@ -285,6 +304,11 @@ static int imsic_parse_node(const struct dt_device_node
*node,
return -ENOENT;
}
+ if ( dt_property_read_u32(node, "riscv,num-guest-ids", &tmp) )
+ guest_num_msis = min(GUEST_IMSIC_MAX_MSIS, tmp);
+ else
+ guest_num_msis = GUEST_IMSIC_MAX_MSIS;
+
if ( (imsic_cfg.nr_ids < IMSIC_MIN_ID) ||
(imsic_cfg.nr_ids > IMSIC_MAX_ID) )
{
@@ -526,3 +550,120 @@ int __init imsic_init(const struct dt_device_node *node)
return rc;
}
+
+static int __init guest_imsic_make_reg_property(struct domain *d, void *fdt)
+{
+ paddr_t size = IMSIC_MMIO_PAGE_SZ * d->max_vcpus;
+ __be32 regs[4] = {
+ cpu_to_be32(GUEST_IMSIC_S_BASE >> 32),
+ cpu_to_be32(GUEST_IMSIC_S_BASE),
+ cpu_to_be32(size >> 32),
+ cpu_to_be32(size),
+ };
+
+ return fdt_property(fdt, "reg", regs, sizeof(regs));
+}
+
+static int __init guest_imsic_set_interrupt_extended_prop(struct domain *d,
+ void *fdt)
+{
+ unsigned int cpu, pos = 0;
+ __be32 *irq_ext;
+ int res;
+
+ irq_ext = xvzalloc_array(__be32, d->max_vcpus * 2);
+ if ( !irq_ext )
+ return -ENOMEM;
+
+ for ( cpu = 0; cpu < d->max_vcpus; cpu++ )
+ {
+ char buf[64];
+ uint32_t phandle;
+
+ snprintf(buf, ARRAY_SIZE(buf), "/cpus/cpu@%u/interrupt-controller",
cpu);
+ phandle = fdt_get_phandle(fdt, fdt_path_offset(fdt, buf));
+
+ if ( !phandle )
+ {
+ res = -ENODEV;
+ goto out;
+ }
+
+ irq_ext[pos++] = cpu_to_be32(phandle);
+ irq_ext[pos++] = cpu_to_be32(IRQ_S_EXT);
+ }
+
+ res = fdt_property(fdt, "interrupts-extended", irq_ext,
+ d->max_vcpus * 2 * sizeof(*irq_ext));
+
+ out:
+ xvfree(irq_ext);
+
+ return res;
+}
+
+int __init vimsic_make_domu_dt_node(struct kernel_info *kinfo,
+ unsigned int *phandle)
+{
+ int res;
+ void *fdt = kinfo->fdt;
+ char vimsic_name[32];
+ unsigned int vimsic_phandle;
+
+ res = snprintf(vimsic_name, ARRAY_SIZE(vimsic_name), "/soc/imsic@%lx",
+ GUEST_IMSIC_S_BASE);
+ if ( res >= ARRAY_SIZE(vimsic_name) )
+ {
+ dprintk(XENLOG_DEBUG, "vimsic name is truncated\n");
+ return -ENOBUFS;
+ }
+
+ res = fdt_begin_node(fdt, vimsic_name);
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "compatible", GUEST_IMSIC_COMPATIBLE);
+ if ( res )
+ return res;
+
+ res = guest_imsic_make_reg_property(kinfo->bd.d, fdt);
+ if ( res )
+ return res;
+
+ res = guest_imsic_set_interrupt_extended_prop(kinfo->bd.d, fdt);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "riscv,num-ids", guest_num_msis);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "msi-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "#msi-cells", 0);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "#interrupt-cells", 0);
+ if ( res )
+ return res;
+
+ vimsic_phandle = alloc_phandle(kinfo);
+ if ( !vimsic_phandle )
+ return -EOVERFLOW;
+
+ res = fdt_property_cell(fdt, "phandle", vimsic_phandle);
+ if ( res )
+ return res;
+
+ if ( phandle )
+ *phandle = vimsic_phandle;
+
+ return fdt_end_node(fdt);
+}
diff --git a/xen/arch/riscv/include/asm/guest-layout.h
b/xen/arch/riscv/include/asm/guest-layout.h
index 68d95a0939..5e566450bd 100644
--- a/xen/arch/riscv/include/asm/guest-layout.h
+++ b/xen/arch/riscv/include/asm/guest-layout.h
@@ -3,6 +3,12 @@
#include <public/xen.h>
+/*
+ * Base address of the guest's supervisor-mode IMSIC. The value is the address
+ * typically used for IMSIC by QEMU.
+ */
+#define GUEST_IMSIC_S_BASE _UL(0x28000000)
+
#define GUEST_RAM_BANKS 2
/*
diff --git a/xen/arch/riscv/include/asm/imsic.h
b/xen/arch/riscv/include/asm/imsic.h
index 5ee954bbf3..2425430ed1 100644
--- a/xen/arch/riscv/include/asm/imsic.h
+++ b/xen/arch/riscv/include/asm/imsic.h
@@ -78,6 +78,7 @@ struct vimsic_state {
};
struct dt_device_node;
+struct kernel_info;
struct vcpu;
int imsic_init(const struct dt_device_node *node);
@@ -93,4 +94,6 @@ int vcpu_imsic_init(struct vcpu *v);
void vcpu_imsic_deinit(struct vcpu *v);
unsigned int vcpu_guest_file_id(const struct vcpu *v);
+int vimsic_make_domu_dt_node(struct kernel_info *kinfo, unsigned int *phandle);
+
#endif /* ASM_RISCV_IMSIC_H */
--
generated by git-patchbot for /home/xen/git/xen.git#master
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |