[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