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

Raymond Mao raymondmaoca at gmail.com
Thu Oct 29 08:59:27 PDT 2026


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

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

Initialize VIRQ on demand and register each domain-owned RPMI
SYSTEM_IRQ channel using its channel ID and interrupt entry count.
Store the physical controller, HWIRQ and IRQ flags in each route.
Activate courier handlers during domain finalization after boot HART
selection, setting affinity to the destination domain's final boot HART.
Complete mapping and channel setup before activating physical sources.

Reject malformed phandle argument lists and insufficient IRQ flag
buffers instead of truncating interrupt specifiers. Require one HWIRQ
cell and one flags cell for SYSIRQ sources, and validate scalar
channel and domain properties.

Signed-off-by: Raymond Mao <raymond.mao at riscstar.com>
---
 include/sbi_utils/fdt/fdt_helper.h |   8 ++
 lib/sbi/sbi_domain.c               |   3 +
 lib/utils/fdt/fdt_domain.c         | 116 ++++++++++++++++++++++++++++-
 lib/utils/fdt/fdt_helper.c         |  57 +++++++++++++-
 4 files changed, 179 insertions(+), 5 deletions(-)

diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 75a564d1..342cf738 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,13 @@ 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);
 
+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/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 16df5533..36b64b32 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -930,6 +930,9 @@ int sbi_domain_finalize(struct sbi_scratch *scratch)
 
 	/* Select stable boot HARTs before programming physical IRQ targets. */
 	domain_select_boot_harts();
+	rc = sbi_virq_setup_couriers();
+	if (rc)
+		return rc;
 
 	/*
 	 * Set the finalized flag so that the root domain
diff --git a/lib/utils/fdt/fdt_domain.c b/lib/utils/fdt/fdt_domain.c
index 575fbdf0..4d38d402 100644
--- a/lib/utils/fdt/fdt_domain.c
+++ b/lib/utils/fdt/fdt_domain.c
@@ -15,7 +15,9 @@
 #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>
 
@@ -291,7 +293,6 @@ 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;
@@ -488,12 +489,123 @@ 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, num_irqs;
+	struct sbi_domain *dom;
+
+	if (!fdt || nodeoff < 0)
+		return SBI_EINVAL;
+
+	val = fdt_getprop(fdt, nodeoff, "opensbi,mpxy-channel-id", &len);
+	if (!val || len != sizeof(*val))
+		return SBI_EINVAL;
+	channel_id = fdt32_to_cpu(*val);
+
+	val = fdt_getprop(fdt, nodeoff, "opensbi,domain", &len);
+	if (!val || len != sizeof(*val))
+		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)
+		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);
+		if (rc)
+			return rc;
+	}
+	rc = sbi_virq_map_ensure_cap(channel_id, index);
+	if (rc)
+		return rc;
+	num_irqs = index;
+
+	for (index = 0; ; index++) {
+		struct sbi_irqchip_device *chip = NULL;
+		u32 hwirq = 0, flags, flags_count = 1;
+
+		rc = fdt_parse_interrupts_extended_entry(fdt, nodeoff, index,
+							 &chip, &hwirq,
+							 &flags, &flags_count);
+		if (rc == SBI_ENOENT)
+			break;
+		if (rc)
+			return rc;
+		if (!chip)
+			return SBI_ENODEV;
+		if (flags_count != 1)
+			return SBI_ENOTSUPP;
+
+		rc = sbi_virq_map_set(channel_id, chip->id, hwirq, index);
+		if (rc)
+			return rc;
+
+		rc = sbi_virq_route_add(dom, chip->id, hwirq, flags, channel_id);
+		if (rc)
+			return rc;
+	}
+
+	return sbi_virq_sysirq_add_channel(dom, channel_id, num_irqs);
+}
+
+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)
 {
+	int err;
+
 	/* Sanity checks */
 	if (!fdt)
 		return SBI_EINVAL;
 
 	/* Iterate over each domain in FDT and populate details */
-	return fdt_iterate_each_domain_ro(fdt, NULL, __fdt_parse_domain);
+	err = fdt_iterate_each_domain_ro(fdt, NULL, __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 747ba028..21c78279 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>
@@ -47,6 +48,8 @@ int fdt_parse_phandle_with_args(const void *fdt, int nodeoff,
 	list = fdt_getprop(fdt, nodeoff, prop, &len);
 	if (!list)
 		return SBI_ENOENT;
+	if (len % sizeof(*list))
+		return SBI_EINVAL;
 	list_end = list + (len / sizeof(*list));
 
 	while (list < list_end) {
@@ -57,13 +60,13 @@ int fdt_parse_phandle_with_args(const void *fdt, int nodeoff,
 		list++;
 
 		val = fdt_getprop(fdt, pnodeoff, cells_prop, &len);
-		if (!val)
-			return SBI_ENOENT;
+		if (!val || len != sizeof(*val))
+			return SBI_EINVAL;
 		pcells = fdt32_to_cpu(*val);
 		if (FDT_MAX_PHANDLE_ARGS < pcells)
 			return SBI_EINVAL;
 		if (list + pcells > list_end)
-			return SBI_ENOENT;
+			return SBI_EINVAL;
 
 		if (index > 0) {
 			list += pcells;
@@ -80,6 +83,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;
+		*out_flags_count = flags_cnt;
+		if (out_flags && flags_cap < flags_cnt)
+			return SBI_EBAD_RANGE;
+		if (out_flags) {
+			for (i = 0; i < (int)flags_cnt; i++)
+				out_flags[i] = args.args[i + 1];
+		}
+	}
+
+	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