Guests require a Device Tree description of the interrupt controller
topology. Add support for creating an APLIC node when building the
guest DT.

The node is derived from the host DT and linked to the guest IMSIC
via the msi-parent property, allowing guests to discover and use the
APLIC interrupt controller.

Co-developed-by: Romain Caritey <[email protected]>
Signed-off-by: Oleksii Kurochko <[email protected]>
---
 xen/arch/riscv/aplic.c | 82 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c
index 739e8dab3498..e139946a05a0 100644
--- a/xen/arch/riscv/aplic.c
+++ b/xen/arch/riscv/aplic.c
@@ -12,8 +12,10 @@
 #include <xen/const.h>
 #include <xen/device_tree.h>
 #include <xen/errno.h>
+#include <xen/fdt-kernel.h>
 #include <xen/init.h>
 #include <xen/irq.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/mm.h>
 #include <xen/sections.h>
 #include <xen/spinlock.h>
@@ -295,6 +297,85 @@ static void cf_check aplic_set_irq_type(struct irq_desc 
*desc,
     spin_unlock(&aplic.lock);
 }
 
+static int __init cf_check aplic_make_dom_dt_node(
+                                    const struct kernel_info *kinfo,
+                                    const struct dt_device_node *aplic_node)
+{
+    uint32_t len;
+    const __be32 *regs;
+    const void *data = NULL;
+    int res = 0;
+    void *fdt = kinfo->fdt;
+
+    res = imsic_make_dt_node(kinfo);
+    if ( res )
+        return res;
+
+    res = fdt_begin_node(fdt, aplic_node->full_name);
+    if (res)
+        return res;
+
+    data = dt_get_property(aplic_node, "#interrupt-cells", &len);
+    if ( !data )
+    {
+        printk("%s: Can't find '#interrupt-cells' property\n",
+               aplic_node->full_name);
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    res = fdt_property(fdt, "#interrupt-cells", data, len);
+    if ( res )
+        return res;
+
+    regs = dt_get_property(aplic_node, "reg", &len);
+    if ( !regs )
+    {
+        printk("%s: Can't find 'reg' property\n", aplic_node->full_name);
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    res = fdt_property(fdt, "reg", regs, len);
+    if ( res )
+        return res;
+
+    data = dt_get_property(aplic_node, "riscv,num-sources", &len);
+    if ( !data )
+    {
+        printk("%s: Can't find 'riscv,num-sources' property\n",
+                aplic_node->full_name);
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    res = fdt_property(fdt, "riscv,num-sources", data, len);
+    if ( res )
+        return res;
+
+    res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+    if ( res )
+        return res;
+
+    data = dt_get_property(aplic_node, "compatible", &len);
+    if ( !data )
+    {
+        printk("%s: Can't find 'compatible' property\n", 
aplic_node->full_name);
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    res = fdt_property(fdt, "compatible", data, len);
+    if ( res )
+        return res;
+
+    res = fdt_property_cell(fdt, "msi-parent", aplic.imsic_cfg->phandle);
+    if ( res )
+        return res;
+
+    res = fdt_property_cell(fdt, "phandle", kinfo->phandle_intc);
+    if ( res )
+        return res;
+
+    return fdt_end_node(fdt);
+}
+
 static const hw_irq_controller aplic_xen_irq_type = {
     .typename     = "aplic",
     .startup      = aplic_irq_startup,
@@ -310,6 +391,7 @@ static const struct intc_hw_operations aplic_ops = {
     .host_irq_type       = &aplic_xen_irq_type,
     .handle_interrupt    = aplic_handle_interrupt,
     .set_irq_type        = aplic_set_irq_type,
+    .make_dom_dt_node    = aplic_make_dom_dt_node,
 };
 
 static int cf_check aplic_irq_xlate(const uint32_t *intspec,
-- 
2.53.0


Reply via email to