[PATCH 6/6] lib: sbi_irqchip: Add support for registering MSI handlers

Anup Patel anup.patel at oss.qualcomm.com
Wed Apr 22 22:23:39 PDT 2026


Some of the drivers (such as APLIC) require capability to registers
MSI handlers from the parent interrupt controller (such as IMSIC)
so add sbi_irqchip_register_msi_handler() for this purpose.

Signed-off-by: Anup Patel <anup at brainfault.org>
---
 include/sbi/sbi_irqchip.h | 19 +++++++++++
 lib/sbi/sbi_irqchip.c     | 71 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
index 03a01038..8e7ff573 100644
--- a/include/sbi/sbi_irqchip.h
+++ b/include/sbi/sbi_irqchip.h
@@ -16,6 +16,13 @@
 
 struct sbi_scratch;
 
+/** irqchip message signalled interrupt (MSI) */
+struct sbi_irqchip_msi_msg {
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
+};
+
 /** irqchip hardware device */
 struct sbi_irqchip_device {
 	/** Node in the list of irqchip devices (private) */
@@ -109,6 +116,18 @@ int sbi_irqchip_get_affinity(struct sbi_irqchip_device *chip, u32 hwirq,
 /** Set hardware interrupt affinity */
 int sbi_irqchip_set_affinity(struct sbi_irqchip_device *chip, u32 hwirq, u32 hart_index);
 
+/** Write MSI message to the hardware interrupt handler */
+int sbi_irqchip_write_msi(struct sbi_irqchip_device *chip, u32 hwirq,
+			  const struct sbi_irqchip_msi_msg *msg);
+
+/** Register a hardware MSI handler */
+int sbi_irqchip_register_msi(struct sbi_irqchip_device *chip, u32 num_hwirq,
+			     void (*write_msi)(u32 hwirq,
+					       const struct sbi_irqchip_msi_msg *msg,
+					       void *priv),
+			     int (*callback)(u32 hwirq, void *priv), void *priv,
+			     u32 *out_first_hwirq);
+
 /** Register a hardware interrupt handler */
 int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
 				 u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 386dfd87..5880872c 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -35,6 +35,9 @@ struct sbi_irqchip_handler {
 	/** Number of consecutive hardware IRQs handled by this handler */
 	u32 num_hwirq;
 
+	/** Write MSI function of this handler */
+	void (*write_msi)(u32 hwirq, const struct sbi_irqchip_msi_msg *msg, void *priv);
+
 	/** Callback function of this handler */
 	int (*callback)(u32 hwirq, void *priv);
 
@@ -141,6 +144,24 @@ int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
 	return 0;
 }
 
+int sbi_irqchip_write_msi(struct sbi_irqchip_device *chip, u32 hwirq,
+			  const struct sbi_irqchip_msi_msg *msg)
+{
+	struct sbi_irqchip_handler *h;
+
+	if (!chip || chip->num_hwirq <= hwirq || !msg)
+		return SBI_EINVAL;
+
+	h = sbi_irqchip_find_handler(chip, hwirq);
+	if (!h)
+		return SBI_EFAIL;
+	if (!h->write_msi)
+		return SBI_ENOTSUPP;
+
+	h->write_msi(hwirq, msg, h->priv);
+	return 0;
+}
+
 int sbi_irqchip_get_affinity(struct sbi_irqchip_device *chip, u32 hwirq,
 			     u32 *out_hart_index)
 {
@@ -215,6 +236,9 @@ static int __sbi_irqchip_handler_set_affinity(struct sbi_irqchip_device *chip,
 
 static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
 					  u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
+					  void (*write_msi)(u32 hwirq,
+							    const struct sbi_irqchip_msi_msg *msg,
+							    void *priv),
 					  int (*callback)(u32 hwirq, void *priv), void *priv)
 {
 	struct sbi_irqchip_handler *h, *th, *nh;
@@ -232,6 +256,7 @@ static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
 		return SBI_ENOMEM;
 	h->first_hwirq = first_hwirq;
 	h->num_hwirq = num_hwirq;
+	h->write_msi = write_msi;
 	h->callback = callback;
 	h->priv = priv;
 
@@ -281,6 +306,48 @@ static int __sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
 	return 0;
 }
 
+int sbi_irqchip_register_msi(struct sbi_irqchip_device *chip, u32 num_hwirq,
+			     void (*write_msi)(u32 hwirq,
+					       const struct sbi_irqchip_msi_msg *msg,
+					       void *priv),
+			     int (*callback)(u32 hwirq, void *priv), void *priv,
+			     u32 *out_first_hwirq)
+{
+	struct sbi_irqchip_handler *h;
+	bool found;
+	u32 hwirq;
+
+	if (!chip || !chip->hwirq_set_affinity || !num_hwirq ||
+	    !write_msi || !callback || !out_first_hwirq)
+		return SBI_EINVAL;
+	if (chip->num_hwirq < num_hwirq)
+		return SBI_EBAD_RANGE;
+
+	hwirq = 0;
+	found = false;
+	sbi_list_for_each_entry(h, &chip->handler_list, node) {
+		if (h->first_hwirq <= hwirq && hwirq < (h->first_hwirq + h->num_hwirq)) {
+			hwirq = h->first_hwirq + h->num_hwirq;
+		} else if (hwirq < h->first_hwirq) {
+			if (h->first_hwirq - hwirq < num_hwirq) {
+				found = true;
+				break;
+			} else {
+				hwirq = h->first_hwirq + h->num_hwirq;
+			}
+		}
+	}
+	if (!found && !hwirq)
+		found = true;
+	if (!found)
+		return SBI_ENOSPC;
+	*out_first_hwirq = hwirq;
+
+	return __sbi_irqchip_register_handler(chip, *out_first_hwirq,
+					      num_hwirq, SBI_HWIRQ_FLAGS_NONE,
+					      write_msi, callback, priv);
+}
+
 int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
 				 u32 first_hwirq, u32 num_hwirq, u32 hwirq_flags,
 				 int (*callback)(u32 hwirq, void *priv), void *priv)
@@ -292,7 +359,7 @@ int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
 		return SBI_EBAD_RANGE;
 
 	return __sbi_irqchip_register_handler(chip, first_hwirq, num_hwirq, hwirq_flags,
-					      callback, priv);
+					      NULL, callback, priv);
 }
 
 int sbi_irqchip_register_reserved(struct sbi_irqchip_device *chip,
@@ -305,7 +372,7 @@ int sbi_irqchip_register_reserved(struct sbi_irqchip_device *chip,
 		return SBI_EBAD_RANGE;
 
 	return __sbi_irqchip_register_handler(chip, first_hwirq, num_hwirq,
-					      SBI_HWIRQ_FLAGS_NONE, NULL, NULL);
+					      SBI_HWIRQ_FLAGS_NONE, NULL, NULL, NULL);
 }
 
 int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
-- 
2.43.0




More information about the opensbi mailing list