[PATCH 06/10] lib: utils: fdt: parse sysirq routing from DT

Raymond Mao raymondmaoca at gmail.com
Thu May 14 15:57:52 PDT 2026


From: Raymond Mao <raymond.mao at riscstar.com>

Init VIRQ and parse mpxy-sysirq nodes under /chosen/opensbi-domains,
pre-size per-channel VIRQ maps, and add HWIRQ routes from
interrupts-extended.
Mark sysirq domains to allow SEIP-based VIRQ notification.

Signed-off-by: Raymond Mao <raymond.mao at riscstar.com>
---
 include/sbi_utils/fdt/fdt_helper.h |  17 +++++
 lib/utils/fdt/fdt_domain.c         | 119 ++++++++++++++++++++++++++++-
 lib/utils/fdt/fdt_helper.c         |  49 ++++++++++++
 3 files changed, 183 insertions(+), 2 deletions(-)

diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 04c850cc..e49a5bca 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -12,6 +12,7 @@
 
 #include <sbi/sbi_types.h>
 #include <sbi/sbi_domain.h>
+#include <sbi/sbi_irqchip.h>
 
 struct fdt_match {
 	const char *compatible;
@@ -38,6 +39,22 @@ int fdt_parse_phandle_with_args(const void *fdt, int nodeoff,
 				const char *prop, const char *cells_prop,
 				int index, struct fdt_phandle_args *out_args);
 
+/*
+ * Parse one entry from "interrupts-extended" and return irqchip device,
+ * hwirq, and optional flags.
+ *
+ * @index: entry index within interrupts-extended
+ * @out_flags_count: in/out, on input capacity of out_flags array;
+ *                   on output number of flags returned (or total flags
+ *                   if out_flags is NULL).
+ */
+int fdt_parse_interrupts_extended_entry(const void *fdt, int nodeoff,
+					int index,
+					struct sbi_irqchip_device **out_chip,
+					u32 *out_hwirq,
+					u32 *out_flags,
+					u32 *out_flags_count);
+
 int fdt_get_node_addr_size(const void *fdt, int node, int index,
 			   uint64_t *addr, uint64_t *size);
 
diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c
index b2fa8633..4a75f25a 100644
--- a/lib/utils/fdt/fdt_domain.c
+++ b/lib/utils/fdt/fdt_domain.c
@@ -10,11 +10,14 @@
 
 #include <libfdt.h>
 #include <libfdt_env.h>
+#include <sbi/sbi_console.h>
 #include <sbi/sbi_domain.h>
 #include <sbi/sbi_error.h>
 #include <sbi/sbi_hartmask.h>
 #include <sbi/sbi_heap.h>
+#include <sbi/sbi_irqchip.h>
 #include <sbi/sbi_scratch.h>
+#include <sbi/sbi_virq.h>
 #include <sbi_utils/fdt/fdt_domain.h>
 #include <sbi_utils/fdt/fdt_helper.h>
 
@@ -304,6 +307,7 @@ static int __fdt_parse_region(const void *fdt, int domain_offset,
 	return 0;
 }
 
+
 static int __fdt_parse_domain(const void *fdt, int domain_offset, void *opaque)
 {
 	u32 val32;
@@ -511,6 +515,113 @@ fail_free_domain:
 	return err;
 }
 
+static int __fdt_parse_mpxy_sysirq_node(const void *fdt, int nodeoff)
+{
+	const fdt32_t *val;
+	int len, rc, doff;
+	u32 channel_id;
+	u32 index;
+	struct sbi_domain *dom;
+
+	if (!fdt || nodeoff < 0)
+		return SBI_EINVAL;
+
+	val = fdt_getprop(fdt, nodeoff, "opensbi,mpxy-channel-id", &len);
+	if (!val || len < (int)sizeof(fdt32_t)) {
+		sbi_printf("[SYSIRQ] missing opensbi,mpxy-channel-id\n");
+		return SBI_EINVAL;
+	}
+	channel_id = fdt32_to_cpu(*val);
+
+	val = fdt_getprop(fdt, nodeoff, "opensbi,domain", &len);
+	if (!val || len < (int)sizeof(fdt32_t)) {
+		sbi_printf("[SYSIRQ] missing opensbi,domain\n");
+		return SBI_EINVAL;
+	}
+
+	doff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val));
+	if (doff < 0)
+		return doff;
+
+	dom = sbi_domain_find_by_name(fdt_get_name(fdt, doff, NULL));
+	if (!dom) {
+		sbi_printf("[SYSIRQ] domain not found for node %s\n",
+			   fdt_get_name(fdt, doff, NULL));
+		return SBI_ENOENT;
+	}
+	dom->virq_seip_notify = true;
+
+	/* Pre-allocate VIRQ map based on interrupts-extended count */
+	for (index = 0; ; index++) {
+		rc = fdt_parse_interrupts_extended_entry(fdt, nodeoff, index,
+							 NULL, NULL,
+							 NULL, NULL);
+		if (rc == SBI_ENOENT)
+			break;
+		if (rc)
+			return rc;
+	}
+
+	if (!sbi_virq_is_inited())
+		rc = sbi_virq_init(index);
+	else
+		rc = sbi_virq_map_ensure_cap(channel_id, index);
+	if (rc)
+		return rc;
+
+	for (index = 0; ; index++) {
+		struct sbi_irqchip_device *chip = NULL;
+		u32 hwirq = 0;
+
+		rc = fdt_parse_interrupts_extended_entry(fdt, nodeoff, index,
+							 &chip, &hwirq,
+							 NULL, NULL);
+		if (rc == SBI_ENOENT)
+			break;
+		if (rc)
+			return rc;
+		if (!chip)
+			return SBI_ENODEV;
+
+		rc = sbi_virq_map_set(channel_id, chip->id, hwirq, index);
+		if (rc)
+			return rc;
+
+		rc = sbi_virq_route_add(dom, hwirq, channel_id);
+		if (rc)
+			return rc;
+	}
+
+	return SBI_OK;
+}
+
+static int __fdt_parse_mpxy_sysirq_nodes(const void *fdt)
+{
+	int poffset, noff, rc;
+
+	if (!fdt)
+		return SBI_EINVAL;
+
+	poffset = fdt_path_offset(fdt, "/chosen");
+	if (poffset < 0)
+		return 0;
+	poffset = fdt_node_offset_by_compatible(fdt, poffset,
+						"opensbi,domain,config");
+	if (poffset < 0)
+		return 0;
+
+	fdt_for_each_subnode(noff, fdt, poffset) {
+		if (fdt_node_check_compatible(fdt, noff,
+					      "opensbi,mpxy-sysirq"))
+			continue;
+		rc = __fdt_parse_mpxy_sysirq_node(fdt, noff);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
 int fdt_domains_populate(const void *fdt)
 {
 	const u32 *val;
@@ -550,6 +661,10 @@ int fdt_domains_populate(const void *fdt)
 	}
 
 	/* Iterate over each domain in FDT and populate details */
-	return fdt_iterate_each_domain_ro(fdt, &cold_domain_offset,
-					  __fdt_parse_domain);
+	err = fdt_iterate_each_domain_ro(fdt, &cold_domain_offset,
+					 __fdt_parse_domain);
+	if (err)
+		return err;
+
+	return __fdt_parse_mpxy_sysirq_nodes(fdt);
 }
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index b57eae1a..3d7c4eec 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -10,6 +10,7 @@
 #include <sbi/riscv_asm.h>
 #include <sbi/sbi_console.h>
 #include <sbi/sbi_hartmask.h>
+#include <sbi/sbi_irqchip.h>
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_scratch.h>
 #include <sbi/sbi_hart.h>
@@ -80,6 +81,54 @@ int fdt_parse_phandle_with_args(const void *fdt, int nodeoff,
 	return SBI_ENOENT;
 }
 
+int fdt_parse_interrupts_extended_entry(const void *fdt, int nodeoff,
+					int index,
+					struct sbi_irqchip_device **out_chip,
+					u32 *out_hwirq,
+					u32 *out_flags,
+					u32 *out_flags_count)
+{
+	struct fdt_phandle_args args;
+	struct sbi_irqchip_device *chip;
+	u32 flags_cap = 0, flags_cnt = 0;
+	int rc, i;
+
+	if (!fdt || nodeoff < 0)
+		return SBI_EINVAL;
+
+	rc = fdt_parse_phandle_with_args(fdt, nodeoff, "interrupts-extended",
+					 "#interrupt-cells", index, &args);
+	if (rc)
+		return rc;
+
+	if (args.args_count < 1)
+		return SBI_EINVAL;
+
+	if (out_hwirq)
+		*out_hwirq = args.args[0];
+
+	if (out_flags_count) {
+		flags_cap = *out_flags_count;
+		flags_cnt = (args.args_count > 1) ? (args.args_count - 1) : 0;
+		if (out_flags && flags_cap < flags_cnt)
+			flags_cnt = flags_cap;
+		if (out_flags) {
+			for (i = 0; i < (int)flags_cnt; i++)
+				out_flags[i] = args.args[i + 1];
+		}
+		*out_flags_count = flags_cnt;
+	}
+
+	if (out_chip) {
+		chip = sbi_irqchip_find_device((u32)args.node_offset);
+		if (!chip)
+			return SBI_ENODEV;
+		*out_chip = chip;
+	}
+
+	return 0;
+}
+
 static int fdt_translate_address(const void *fdt, uint64_t reg, int parent,
 				 uint64_t *addr)
 {
-- 
2.25.1




More information about the opensbi mailing list