|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 19/25] 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>
---
Changes in v4:
- Add a comment for guest_num_msis explaining that it is host-dependent
and therefore identical for every domain, which is why a single global
is used instead of a per-domain value.
- Reduce vimsic_name[] from 128 to 32 bytes, which is enough to hold
"/soc/imsic@" plus a 64-bit hex address.
- Add a comment before GUEST_IMSIC_S_BASE noting that the value is the
address typically used for IMSIC by QEMU.
- s/__ULL/_UL for defintion of GUEST_IMSIC_S_BASE.
---
Changes in v3:
- s/__ro_after_init/__read_mostly for guest_num_msis.
- Use IMSIC_MAX_ID as default for guest_num_msis instead of imsic_cfg.nr_ids.
- Drop base_addr local variable in guest_imsic_make_reg_property(); use
GUEST_IMSIC_S_BASE directly and introduce size to avoid spelling
IMSIC_MMIO_PAGE_SZ * d->max_vcpus twice.
- Change irq_ext type from uint32_t * to __be32 * in
guest_imsic_set_interrupt_extended_prop().
- Move phandle declaration into the loop body.
- Extend commit message to explain why __init is used for DT-building
functions: libxl creates the interrupt controller node before handing
the FDT to Xen, so these functions are only invoked during boot-time
domain construction.
- Re-order patch before APLIC DT node creation patch.
- Update commit message.
---
Changes in v2:
- s/imsic_make_reg_property/guest_imsic_make_reg_property.
- s/imsic_set_interrupt_extended_prop/guest_imsic_set_interrupt_extended_prop.
- Use initalizer for regs[] array in imsic_make_reg_property().
- Move buf[] insde the for() loop.
- Correct check of returned phandle.
- Drop local variable len.
- /s/XVFREE/xvfree in imsic_set_interrupt_extended_prop().
- Drop initializer for local variable data.
- s/uint32_t/unsinged int for pos and cpu in
imsic_set_interrupt_extended_prop().
- Drop next_phandle as it is now in common code.
- Introduce vcpu_imsic_deinit.
- Refactor vimsic_make_domu_dt_node() to avoid usage of host IMSIC dt node.
---
---
xen/arch/riscv/imsic.c | 137 ++++++++++++++++++++++
xen/arch/riscv/include/asm/guest-layout.h | 6 +
2 files changed, 143 insertions(+)
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index 7068d6a7fef1..e6919f491193 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,16 @@ 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 __read_mostly guest_num_msis;
+
+#define GUEST_IMSIC_COMPATIBLE "riscv,imsics"
+#define GUEST_IMSIC_NUM_MSIS 255
+
#define IMSIC_DISABLE_EIDELIVERY 0
#define IMSIC_ENABLE_EIDELIVERY 1
#define IMSIC_DISABLE_EITHRESHOLD 1
@@ -285,6 +299,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 = tmp;
+ else
+ guest_num_msis = IMSIC_MAX_ID;
+
if ( (imsic_cfg.nr_ids < IMSIC_MIN_ID) ||
(imsic_cfg.nr_ids > IMSIC_MAX_ID) )
{
@@ -522,3 +541,121 @@ 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, sizeof(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;
+ unsigned int num_msis = min(GUEST_IMSIC_NUM_MSIS + 0U, guest_num_msis);
+
+ res = snprintf(vimsic_name, sizeof(vimsic_name), "/soc/imsic@%lx",
+ GUEST_IMSIC_S_BASE);
+ if ( res >= sizeof(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", 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 68d95a09394c..5e566450bdfa 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
/*
--
2.54.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |