public inbox for opensbi@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Extend irqchip framework for M-mode interrupts
@ 2026-02-07 10:25 Anup Patel
  2026-02-07 10:25 ` [PATCH 1/8] lib: sbi_irqchip: Use chip as variable name for irqchip device Anup Patel
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:25 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

To handle interrupts in M-mode, the OpenSBI irqchip framework
needs to support:
1) Multiple interrupt controllers where each targets a
   subset of harts
2) Hierarchical interrupt controllers (e.g. APLIC + IMSIC)
3) Registering handler for hardware interrupt of a
   particular interrupt controller out of multiple
   multiple interrupt controllers

The needs to be achieved without over-consuming memory.

These patches can also be found in irqchip_imp_v1 branch
at: https://github.com/avpatel/opensbi.git

Anup Patel (8):
  lib: sbi_irqchip: Use chip as variable name for irqchip device
  lib: sbi_irqchip: Rename irq_handle() callback to process_hwirqs()
  lib: utils/irqchip: Fix context_map init in
    irqchip_plic_update_context_map()
  lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data
  lib: sbi_irqchip: Support irqchip device targetting subset of harts
  lib: utils/irqchip: Add unique_id to plic, aplic, and imsic data
  lib: sbi_irqchip: Associate 32-bit unique ID for each irqchip device
  lib: sbi_irqchip: Allow registering interrupt handlers

 include/sbi/sbi_irqchip.h                |  74 ++++++-
 include/sbi_utils/irqchip/aplic.h        |   2 +
 include/sbi_utils/irqchip/imsic.h        |   1 +
 include/sbi_utils/irqchip/plic.h         |   1 +
 lib/sbi/sbi_irqchip.c                    | 267 +++++++++++++++++++++--
 lib/utils/fdt/fdt_helper.c               |   3 +
 lib/utils/irqchip/aplic.c                |  14 +-
 lib/utils/irqchip/fdt_irqchip_aplic.c    |  54 ++++-
 lib/utils/irqchip/fdt_irqchip_plic.c     |   5 +
 lib/utils/irqchip/imsic.c                |  19 +-
 lib/utils/irqchip/plic.c                 |   7 +-
 platform/generic/openhwgroup/ariane.c    |   1 +
 platform/generic/openhwgroup/openpiton.c |   1 +
 platform/kendryte/k210/platform.c        |   1 +
 platform/nuclei/ux600/platform.c         |   1 +
 platform/template/platform.c             |   1 +
 16 files changed, 424 insertions(+), 28 deletions(-)

-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 1/8] lib: sbi_irqchip: Use chip as variable name for irqchip device
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
@ 2026-02-07 10:25 ` Anup Patel
  2026-02-07 10:25 ` [PATCH 2/8] lib: sbi_irqchip: Rename irq_handle() callback to process_hwirqs() Anup Patel
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:25 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

The irqchip device represents an interrupt controller so use chip
as variable name instead of dev. This will avoid confusion as the
sbi_irqchip framework grows.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi/sbi_irqchip.h |  4 ++--
 lib/sbi/sbi_irqchip.c     | 16 ++++++++--------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
index e0ae12f5..97332248 100644
--- a/include/sbi/sbi_irqchip.h
+++ b/include/sbi/sbi_irqchip.h
@@ -21,7 +21,7 @@ struct sbi_irqchip_device {
 	struct sbi_dlist node;
 
 	/** Initialize per-hart state for the current hart */
-	int (*warm_init)(struct sbi_irqchip_device *dev);
+	int (*warm_init)(struct sbi_irqchip_device *chip);
 
 	/** Handle an IRQ from this irqchip */
 	int (*irq_handle)(void);
@@ -38,7 +38,7 @@ struct sbi_irqchip_device {
 int sbi_irqchip_process(void);
 
 /** Register an irqchip device to receive callbacks */
-void sbi_irqchip_add_device(struct sbi_irqchip_device *dev);
+void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
 
 /** Initialize interrupt controllers */
 int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 0594e05a..8a71b88f 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -25,19 +25,19 @@ int sbi_irqchip_process(void)
 	return ext_irqfn();
 }
 
-void sbi_irqchip_add_device(struct sbi_irqchip_device *dev)
+void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 {
-	sbi_list_add_tail(&dev->node, &irqchip_list);
+	sbi_list_add_tail(&chip->node, &irqchip_list);
 
-	if (dev->irq_handle)
-		ext_irqfn = dev->irq_handle;
+	if (chip->irq_handle)
+		ext_irqfn = chip->irq_handle;
 }
 
 int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
 {
 	int rc;
 	const struct sbi_platform *plat = sbi_platform_ptr(scratch);
-	struct sbi_irqchip_device *dev;
+	struct sbi_irqchip_device *chip;
 
 	if (cold_boot) {
 		rc = sbi_platform_irqchip_init(plat);
@@ -45,10 +45,10 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
 			return rc;
 	}
 
-	sbi_list_for_each_entry(dev, &irqchip_list, node) {
-		if (!dev->warm_init)
+	sbi_list_for_each_entry(chip, &irqchip_list, node) {
+		if (!chip->warm_init)
 			continue;
-		rc = dev->warm_init(dev);
+		rc = chip->warm_init(chip);
 		if (rc)
 			return rc;
 	}
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 2/8] lib: sbi_irqchip: Rename irq_handle() callback to process_hwirqs()
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
  2026-02-07 10:25 ` [PATCH 1/8] lib: sbi_irqchip: Use chip as variable name for irqchip device Anup Patel
@ 2026-02-07 10:25 ` Anup Patel
  2026-02-07 10:25 ` [PATCH 3/8] lib: utils/irqchip: Fix context_map init in irqchip_plic_update_context_map() Anup Patel
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:25 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

The irq_handle() callback of irqchip device is meant to process
hardware interrupt of the irqchip hence rename it accordingly.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi/sbi_irqchip.h | 4 ++--
 lib/sbi/sbi_irqchip.c     | 4 ++--
 lib/utils/irqchip/imsic.c | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
index 97332248..cda1e50f 100644
--- a/include/sbi/sbi_irqchip.h
+++ b/include/sbi/sbi_irqchip.h
@@ -23,8 +23,8 @@ struct sbi_irqchip_device {
 	/** Initialize per-hart state for the current hart */
 	int (*warm_init)(struct sbi_irqchip_device *chip);
 
-	/** Handle an IRQ from this irqchip */
-	int (*irq_handle)(void);
+	/** Process hardware interrupts from this irqchip */
+	int (*process_hwirqs)(void);
 };
 
 /**
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 8a71b88f..3b970527 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -29,8 +29,8 @@ void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 {
 	sbi_list_add_tail(&chip->node, &irqchip_list);
 
-	if (chip->irq_handle)
-		ext_irqfn = chip->irq_handle;
+	if (chip->process_hwirqs)
+		ext_irqfn = chip->process_hwirqs;
 }
 
 int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
index d72ef794..0e9917da 100644
--- a/lib/utils/irqchip/imsic.c
+++ b/lib/utils/irqchip/imsic.c
@@ -147,7 +147,7 @@ int imsic_get_target_file(u32 hartindex)
 	return imsic_get_hart_file(scratch);
 }
 
-static int imsic_external_irqfn(void)
+static int imsic_process_hwirqs(void)
 {
 	ulong mirq;
 
@@ -348,7 +348,7 @@ int imsic_data_check(struct imsic_data *imsic)
 
 static struct sbi_irqchip_device imsic_device = {
 	.warm_init	= imsic_warm_irqchip_init,
-	.irq_handle	= imsic_external_irqfn,
+	.process_hwirqs	= imsic_process_hwirqs,
 };
 
 int imsic_cold_irqchip_init(struct imsic_data *imsic)
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 3/8] lib: utils/irqchip: Fix context_map init in irqchip_plic_update_context_map()
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
  2026-02-07 10:25 ` [PATCH 1/8] lib: sbi_irqchip: Use chip as variable name for irqchip device Anup Patel
  2026-02-07 10:25 ` [PATCH 2/8] lib: sbi_irqchip: Rename irq_handle() callback to process_hwirqs() Anup Patel
@ 2026-02-07 10:25 ` Anup Patel
  2026-02-07 10:25 ` [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data Anup Patel
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:25 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

The context_map[][] elements should be initialized with negative
value so that context_map does not point to anything for non-existent
PLIC contexts.

Fixes: 69448a079065 ("lib: utils/irqchip: plic: Provide a hartindex to context map")
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 lib/utils/irqchip/fdt_irqchip_plic.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/utils/irqchip/fdt_irqchip_plic.c b/lib/utils/irqchip/fdt_irqchip_plic.c
index 65a9de15..61c68ac9 100644
--- a/lib/utils/irqchip/fdt_irqchip_plic.c
+++ b/lib/utils/irqchip/fdt_irqchip_plic.c
@@ -24,6 +24,11 @@ static int irqchip_plic_update_context_map(const void *fdt, int nodeoff,
 	u32 phandle, hwirq, hartid, hartindex;
 	int i, err, count, cpu_offset, cpu_intc_offset;
 
+	for (i = 0; i < sbi_hart_count(); i++) {
+		pd->context_map[i][PLIC_M_CONTEXT] = -1;
+		pd->context_map[i][PLIC_S_CONTEXT] = -1;
+	}
+
 	val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
 	if (!val || count < sizeof(fdt32_t))
 		return SBI_EINVAL;
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
                   ` (2 preceding siblings ...)
  2026-02-07 10:25 ` [PATCH 3/8] lib: utils/irqchip: Fix context_map init in irqchip_plic_update_context_map() Anup Patel
@ 2026-02-07 10:25 ` Anup Patel
  2026-02-09 16:50   ` Andrew Jones
  2026-02-07 10:25 ` [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts Anup Patel
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:25 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

A platform can have multiple APLICs in direct-mode targetting
different subset of harts. Add APLIC ID to hartindex map in
struct aplic_data to capture the set of harts targed by a
given APLIC in direct-mode.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi_utils/irqchip/aplic.h     |  1 +
 lib/utils/irqchip/fdt_irqchip_aplic.c | 54 ++++++++++++++++++++++++++-
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h
index cbfcd3fd..ad613778 100644
--- a/include/sbi_utils/irqchip/aplic.h
+++ b/include/sbi_utils/irqchip/aplic.h
@@ -45,6 +45,7 @@ struct aplic_data {
 	bool has_msicfg_smode;
 	struct aplic_msicfg_data msicfg_smode;
 	struct aplic_delegate_data delegate[APLIC_MAX_DELEGATE];
+	u32 *idc_map;
 };
 
 int aplic_cold_irqchip_init(struct aplic_data *aplic);
diff --git a/lib/utils/irqchip/fdt_irqchip_aplic.c b/lib/utils/irqchip/fdt_irqchip_aplic.c
index 81ebe67d..4d7b1e77 100644
--- a/lib/utils/irqchip/fdt_irqchip_aplic.c
+++ b/lib/utils/irqchip/fdt_irqchip_aplic.c
@@ -16,6 +16,43 @@
 #include <sbi_utils/irqchip/fdt_irqchip.h>
 #include <sbi_utils/irqchip/aplic.h>
 
+static int irqchip_aplic_update_idc_map(const void *fdt, int nodeoff,
+					struct aplic_data *pd)
+{
+	int i, err, count, cpu_offset, cpu_intc_offset;
+	u32 phandle, hartid, hartindex;
+	const fdt32_t *val;
+
+	val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &count);
+	if (!val || count < sizeof(fdt32_t))
+		return SBI_EINVAL;
+	count = count / sizeof(fdt32_t);
+
+	for (i = 0; i < count; i += 2) {
+		phandle = fdt32_to_cpu(val[i]);
+
+		cpu_intc_offset = fdt_node_offset_by_phandle(fdt, phandle);
+		if (cpu_intc_offset < 0)
+			continue;
+
+		cpu_offset = fdt_parent_offset(fdt, cpu_intc_offset);
+		if (cpu_offset < 0)
+			continue;
+
+		err = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+		if (err)
+			continue;
+
+		hartindex = sbi_hartid_to_hartindex(hartid);
+		if (hartindex == -1U)
+			continue;
+
+		pd->idc_map[i / 2] = hartindex;
+	}
+
+	return 0;
+}
+
 static int irqchip_aplic_cold_init(const void *fdt, int nodeoff,
 				   const struct fdt_match *match)
 {
@@ -30,12 +67,27 @@ static int irqchip_aplic_cold_init(const void *fdt, int nodeoff,
 	if (rc)
 		goto fail_free_data;
 
+	if (pd->num_idc) {
+		pd->idc_map = sbi_zalloc(sizeof(*pd->idc_map) * pd->num_idc);
+		if (!pd->idc_map) {
+			rc = SBI_ENOMEM;
+			goto fail_free_data;
+		}
+
+		rc = irqchip_aplic_update_idc_map(fdt, nodeoff, pd);
+		if (rc)
+			goto fail_free_idc_map;
+	}
+
 	rc = aplic_cold_irqchip_init(pd);
 	if (rc)
-		goto fail_free_data;
+		goto fail_free_idc_map;
 
 	return 0;
 
+fail_free_idc_map:
+	if (pd->num_idc)
+		sbi_free(pd->idc_map);
 fail_free_data:
 	sbi_free(pd);
 	return rc;
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
                   ` (3 preceding siblings ...)
  2026-02-07 10:25 ` [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data Anup Patel
@ 2026-02-07 10:25 ` Anup Patel
  2026-02-09 16:50   ` Andrew Jones
                     ` (2 more replies)
  2026-02-07 10:26 ` [PATCH 6/8] lib: utils/irqchip: Add unique_id to plic, aplic, and imsic data Anup Patel
                   ` (2 subsequent siblings)
  7 siblings, 3 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:25 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

It is possible to have platform where an irqchip device targets
a subset of harts and there are multiple irqchip devices to cover
all harts.

To support this scenario:
1) Add target_harts hartmask to struct sbi_irqchip_device which
   represents the set of harts targetted by the irqchip device
2) Call warm_init() and irq_handle() callbacks of an irqchip device
   on a hart only if irqchip device targets that particular hart

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi/sbi_irqchip.h |  8 +++++--
 lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
 lib/utils/irqchip/aplic.c | 12 +++++++++-
 lib/utils/irqchip/imsic.c |  7 ++++--
 lib/utils/irqchip/plic.c  |  5 ++--
 5 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
index cda1e50f..c3ded271 100644
--- a/include/sbi/sbi_irqchip.h
+++ b/include/sbi/sbi_irqchip.h
@@ -10,6 +10,7 @@
 #ifndef __SBI_IRQCHIP_H__
 #define __SBI_IRQCHIP_H__
 
+#include <sbi/sbi_hartmask.h>
 #include <sbi/sbi_list.h>
 #include <sbi/sbi_types.h>
 
@@ -20,11 +21,14 @@ struct sbi_irqchip_device {
 	/** Node in the list of irqchip devices */
 	struct sbi_dlist node;
 
+	/** Set of harts targetted by this irqchip */
+	struct sbi_hartmask target_harts;
+
 	/** Initialize per-hart state for the current hart */
 	int (*warm_init)(struct sbi_irqchip_device *chip);
 
 	/** Process hardware interrupts from this irqchip */
-	int (*process_hwirqs)(void);
+	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
 };
 
 /**
@@ -38,7 +42,7 @@ struct sbi_irqchip_device {
 int sbi_irqchip_process(void);
 
 /** Register an irqchip device to receive callbacks */
-void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
+int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
 
 /** Initialize interrupt controllers */
 int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 3b970527..77ec05af 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -13,24 +13,44 @@
 
 static SBI_LIST_HEAD(irqchip_list);
 
-static int default_irqfn(void)
+int sbi_irqchip_process(void)
 {
-	return SBI_ENODEV;
-}
+	struct sbi_irqchip_device *chip;
+	int rc = SBI_ENODEV;
 
-static int (*ext_irqfn)(void) = default_irqfn;
+	sbi_list_for_each_entry(chip, &irqchip_list, node) {
+		if (!chip->process_hwirqs)
+			continue;
+		if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
+			continue;
+		rc = chip->process_hwirqs(chip);
+		if (rc)
+			break;
+	}
 
-int sbi_irqchip_process(void)
-{
-	return ext_irqfn();
+	return rc;
 }
 
-void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
+int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 {
-	sbi_list_add_tail(&chip->node, &irqchip_list);
+	struct sbi_irqchip_device *c;
+	struct sbi_hartmask hm;
+
+	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
+		return SBI_EINVAL;
+
+	if (chip->process_hwirqs) {
+		sbi_list_for_each_entry(c, &irqchip_list, node) {
+			if (!c->process_hwirqs)
+				continue;
+			sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
+			if (sbi_hartmask_weight(&hm))
+				return SBI_EINVAL;
+		}
+	}
 
-	if (chip->process_hwirqs)
-		ext_irqfn = chip->process_hwirqs;
+	sbi_list_add_tail(&chip->node, &irqchip_list);
+	return 0;
 }
 
 int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
@@ -48,12 +68,14 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
 	sbi_list_for_each_entry(chip, &irqchip_list, node) {
 		if (!chip->warm_init)
 			continue;
+		if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
+			continue;
 		rc = chip->warm_init(chip);
 		if (rc)
 			return rc;
 	}
 
-	if (ext_irqfn != default_irqfn)
+	if (!sbi_list_empty(&irqchip_list))
 		csr_set(CSR_MIE, MIP_MEIP);
 
 	return 0;
@@ -61,6 +83,6 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
 
 void sbi_irqchip_exit(struct sbi_scratch *scratch)
 {
-	if (ext_irqfn != default_irqfn)
+	if (!sbi_list_empty(&irqchip_list))
 		csr_clear(CSR_MIE, MIP_MEIP);
 }
diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index 8d0db168..ea5cb7c4 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -297,8 +297,18 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 			return rc;
 	}
 
+	if (aplic->num_idc) {
+		for (i = 0; i < aplic->num_idc; i++)
+			sbi_hartmask_set_hartindex(aplic->idc_map[i],
+						   &aplic->irqchip.target_harts);
+	} else {
+		sbi_hartmask_set_all(&aplic->irqchip.target_harts);
+	}
+
 	/* Register irqchip device */
-	sbi_irqchip_add_device(&aplic->irqchip);
+	rc = sbi_irqchip_add_device(&aplic->irqchip);
+	if (rc)
+		return rc;
 
 	/* Attach to the aplic list */
 	sbi_list_add_tail(&aplic->node, &aplic_list);
diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
index 0e9917da..5ec9dff4 100644
--- a/lib/utils/irqchip/imsic.c
+++ b/lib/utils/irqchip/imsic.c
@@ -147,7 +147,7 @@ int imsic_get_target_file(u32 hartindex)
 	return imsic_get_hart_file(scratch);
 }
 
-static int imsic_process_hwirqs(void)
+static int imsic_process_hwirqs(struct sbi_irqchip_device *chip)
 {
 	ulong mirq;
 
@@ -391,7 +391,10 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
 	}
 
 	/* Register irqchip device */
-	sbi_irqchip_add_device(&imsic_device);
+	sbi_hartmask_set_all(&imsic_device.target_harts);
+	rc = sbi_irqchip_add_device(&imsic_device);
+	if (rc)
+		return rc;
 
 	/* Register IPI device */
 	sbi_ipi_add_device(&imsic_ipi_device);
diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
index 7989a962..25cc2787 100644
--- a/lib/utils/irqchip/plic.c
+++ b/lib/utils/irqchip/plic.c
@@ -276,11 +276,10 @@ int plic_cold_irqchip_init(struct plic_data *plic)
 			continue;
 
 		plic_set_hart_data_ptr(sbi_hartindex_to_scratch(i), plic);
+		sbi_hartmask_set_hartindex(i, &plic->irqchip.target_harts);
 	}
 
 	/* Register irqchip device */
 	plic->irqchip.warm_init = plic_warm_irqchip_init;
-	sbi_irqchip_add_device(&plic->irqchip);
-
-	return 0;
+	return sbi_irqchip_add_device(&plic->irqchip);
 }
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 6/8] lib: utils/irqchip: Add unique_id to plic, aplic, and imsic data
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
                   ` (4 preceding siblings ...)
  2026-02-07 10:25 ` [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts Anup Patel
@ 2026-02-07 10:26 ` Anup Patel
  2026-02-07 10:26 ` [PATCH 7/8] lib: sbi_irqchip: Associate 32-bit unique ID for each irqchip device Anup Patel
  2026-02-07 10:26 ` [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers Anup Patel
  7 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:26 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

Add a 32-bit unique ID to plic, aplic, and imsic data which can be
used to differentiate multiple irqchip devices.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi_utils/irqchip/aplic.h        | 1 +
 include/sbi_utils/irqchip/imsic.h        | 1 +
 include/sbi_utils/irqchip/plic.h         | 1 +
 lib/utils/fdt/fdt_helper.c               | 3 +++
 platform/generic/openhwgroup/ariane.c    | 1 +
 platform/generic/openhwgroup/openpiton.c | 1 +
 platform/kendryte/k210/platform.c        | 1 +
 platform/nuclei/ux600/platform.c         | 1 +
 platform/template/platform.c             | 1 +
 9 files changed, 11 insertions(+)

diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h
index ad613778..3461d1c7 100644
--- a/include/sbi_utils/irqchip/aplic.h
+++ b/include/sbi_utils/irqchip/aplic.h
@@ -35,6 +35,7 @@ struct aplic_data {
 	struct sbi_irqchip_device irqchip;
 	struct sbi_dlist node;
 	/* Public members */
+	u32 unique_id;
 	unsigned long addr;
 	unsigned long size;
 	unsigned long num_idc;
diff --git a/include/sbi_utils/irqchip/imsic.h b/include/sbi_utils/irqchip/imsic.h
index 353cefec..88dd3cfb 100644
--- a/include/sbi_utils/irqchip/imsic.h
+++ b/include/sbi_utils/irqchip/imsic.h
@@ -24,6 +24,7 @@ struct imsic_regs {
 };
 
 struct imsic_data {
+	u32 unique_id;
 	bool targets_mmode;
 	u32 guest_index_bits;
 	u32 hart_index_bits;
diff --git a/include/sbi_utils/irqchip/plic.h b/include/sbi_utils/irqchip/plic.h
index 18aa7469..0dbf4ed3 100644
--- a/include/sbi_utils/irqchip/plic.h
+++ b/include/sbi_utils/irqchip/plic.h
@@ -17,6 +17,7 @@ struct plic_data {
 	/* Private members */
 	struct sbi_irqchip_device irqchip;
 	/* Public members */
+	u32 unique_id;
 	unsigned long addr;
 	unsigned long size;
 	unsigned long num_src;
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 799fd48d..4cd71b8f 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -673,6 +673,7 @@ int fdt_parse_aplic_node(const void *fdt, int nodeoff, struct aplic_data *aplic)
 	rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, &reg_size);
 	if (rc < 0 || !reg_addr || !reg_size)
 		return SBI_ENODEV;
+	aplic->unique_id = nodeoff;
 	aplic->addr = reg_addr;
 	aplic->size = reg_size;
 
@@ -805,6 +806,7 @@ int fdt_parse_imsic_node(const void *fdt, int nodeoff, struct imsic_data *imsic)
 	if (nodeoff < 0 || !imsic || !fdt)
 		return SBI_ENODEV;
 
+	imsic->unique_id = nodeoff;
 	imsic->targets_mmode = false;
 	val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
 	if (val && len > sizeof(fdt32_t)) {
@@ -887,6 +889,7 @@ int fdt_parse_plic_node(const void *fdt, int nodeoffset, struct plic_data *plic)
 				    &reg_addr, &reg_size);
 	if (rc < 0 || !reg_addr || !reg_size)
 		return SBI_ENODEV;
+	plic->unique_id = nodeoffset;
 	plic->addr = reg_addr;
 	plic->size = reg_size;
 
diff --git a/platform/generic/openhwgroup/ariane.c b/platform/generic/openhwgroup/ariane.c
index 70a97f38..ce2f5512 100644
--- a/platform/generic/openhwgroup/ariane.c
+++ b/platform/generic/openhwgroup/ariane.c
@@ -24,6 +24,7 @@
 						 CLINT_MTIMER_OFFSET)
 
 static struct plic_data plic = {
+	.unique_id = 0,
 	.addr = ARIANE_PLIC_ADDR,
 	.size = ARIANE_PLIC_SIZE,
 	.num_src = ARIANE_PLIC_NUM_SOURCES,
diff --git a/platform/generic/openhwgroup/openpiton.c b/platform/generic/openhwgroup/openpiton.c
index 60d719e1..1d098da7 100644
--- a/platform/generic/openhwgroup/openpiton.c
+++ b/platform/generic/openhwgroup/openpiton.c
@@ -23,6 +23,7 @@
 		(OPENPITON_DEFAULT_CLINT_ADDR + CLINT_MTIMER_OFFSET)
 
 static struct plic_data plic = {
+	.unique_id = 0,
 	.addr = (unsigned long)OPENPITON_DEFAULT_PLIC_ADDR,
 	.size = OPENPITON_DEFAULT_PLIC_SIZE,
 	.num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
diff --git a/platform/kendryte/k210/platform.c b/platform/kendryte/k210/platform.c
index 65f5d497..0b76104c 100644
--- a/platform/kendryte/k210/platform.c
+++ b/platform/kendryte/k210/platform.c
@@ -30,6 +30,7 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
 }
 
 static struct plic_data plic = {
+	.unique_id = 0,
 	.addr = K210_PLIC_BASE_ADDR,
 	.size = K210_PLIC_BASE_SIZE,
 	.num_src = K210_PLIC_NUM_SOURCES,
diff --git a/platform/nuclei/ux600/platform.c b/platform/nuclei/ux600/platform.c
index 14fbaeb6..07b27977 100644
--- a/platform/nuclei/ux600/platform.c
+++ b/platform/nuclei/ux600/platform.c
@@ -63,6 +63,7 @@
 static u32 ux600_clk_freq = 8000000;
 
 static struct plic_data plic = {
+	.unique_id = 0,
 	.addr = UX600_PLIC_ADDR,
 	.size = UX600_PLIC_SIZE,
 	.num_src = UX600_PLIC_NUM_SOURCES,
diff --git a/platform/template/platform.c b/platform/template/platform.c
index 38be1b5c..1f2a1dce 100644
--- a/platform/template/platform.c
+++ b/platform/template/platform.c
@@ -34,6 +34,7 @@
 #define PLATFORM_UART_BAUDRATE		115200
 
 static struct plic_data plic = {
+	.unique_id = 0,
 	.addr = PLATFORM_PLIC_ADDR,
 	.size = PLATFORM_PLIC_SIZE,
 	.num_src = PLATFORM_PLIC_NUM_SOURCES,
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 7/8] lib: sbi_irqchip: Associate 32-bit unique ID for each irqchip device
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
                   ` (5 preceding siblings ...)
  2026-02-07 10:26 ` [PATCH 6/8] lib: utils/irqchip: Add unique_id to plic, aplic, and imsic data Anup Patel
@ 2026-02-07 10:26 ` Anup Patel
  2026-02-07 10:26 ` [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers Anup Patel
  7 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:26 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

Allow locating irqchip device instance using a unique 32-bit ID. This
32-bit unique ID can be set by the irqchip driver at the time of adding
irqchip device.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi/sbi_irqchip.h |  6 ++++++
 lib/sbi/sbi_irqchip.c     | 15 +++++++++++++++
 lib/utils/irqchip/aplic.c |  1 +
 lib/utils/irqchip/imsic.c |  1 +
 lib/utils/irqchip/plic.c  |  1 +
 5 files changed, 24 insertions(+)

diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
index c3ded271..d2c47ae8 100644
--- a/include/sbi/sbi_irqchip.h
+++ b/include/sbi/sbi_irqchip.h
@@ -21,6 +21,9 @@ struct sbi_irqchip_device {
 	/** Node in the list of irqchip devices */
 	struct sbi_dlist node;
 
+	/** Unique ID of this irqchip */
+	u32 id;
+
 	/** Set of harts targetted by this irqchip */
 	struct sbi_hartmask target_harts;
 
@@ -41,6 +44,9 @@ struct sbi_irqchip_device {
  */
 int sbi_irqchip_process(void);
 
+/** Find an irqchip device based on unique ID */
+struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id);
+
 /** Register an irqchip device to receive callbacks */
 int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
 
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index 77ec05af..fb3357f3 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -31,6 +31,18 @@ int sbi_irqchip_process(void)
 	return rc;
 }
 
+struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id)
+{
+	struct sbi_irqchip_device *chip;
+
+	sbi_list_for_each_entry(chip, &irqchip_list, node) {
+		if (chip->id == id)
+			return chip;
+	}
+
+	return NULL;
+}
+
 int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 {
 	struct sbi_irqchip_device *c;
@@ -39,6 +51,9 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
 		return SBI_EINVAL;
 
+	if (sbi_irqchip_find_device(chip->id))
+		return SBI_EALREADY;
+
 	if (chip->process_hwirqs) {
 		sbi_list_for_each_entry(c, &irqchip_list, node) {
 			if (!c->process_hwirqs)
diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index ea5cb7c4..d47a810b 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -306,6 +306,7 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 	}
 
 	/* Register irqchip device */
+	aplic->irqchip.id = aplic->unique_id;
 	rc = sbi_irqchip_add_device(&aplic->irqchip);
 	if (rc)
 		return rc;
diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
index 5ec9dff4..0f296c89 100644
--- a/lib/utils/irqchip/imsic.c
+++ b/lib/utils/irqchip/imsic.c
@@ -391,6 +391,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
 	}
 
 	/* Register irqchip device */
+	imsic_device.id = imsic->unique_id;
 	sbi_hartmask_set_all(&imsic_device.target_harts);
 	rc = sbi_irqchip_add_device(&imsic_device);
 	if (rc)
diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
index 25cc2787..973f7c2a 100644
--- a/lib/utils/irqchip/plic.c
+++ b/lib/utils/irqchip/plic.c
@@ -280,6 +280,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
 	}
 
 	/* Register irqchip device */
+	plic->irqchip.id = plic->unique_id;
 	plic->irqchip.warm_init = plic_warm_irqchip_init;
 	return sbi_irqchip_add_device(&plic->irqchip);
 }
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
  2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
                   ` (6 preceding siblings ...)
  2026-02-07 10:26 ` [PATCH 7/8] lib: sbi_irqchip: Associate 32-bit unique ID for each irqchip device Anup Patel
@ 2026-02-07 10:26 ` Anup Patel
  2026-02-09 16:52   ` Andrew Jones
                     ` (3 more replies)
  7 siblings, 4 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-07 10:26 UTC (permalink / raw)
  To: Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

To handle external interrupts in M-mode, the sbi_irqchip framework
must allow registering interrupt handlers from device drivers.

Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 include/sbi/sbi_irqchip.h |  56 ++++++++++-
 lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
 lib/utils/irqchip/aplic.c |   1 +
 lib/utils/irqchip/imsic.c |   9 ++
 lib/utils/irqchip/plic.c  |   1 +
 5 files changed, 267 insertions(+), 2 deletions(-)

diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
index d2c47ae8..77b54110 100644
--- a/include/sbi/sbi_irqchip.h
+++ b/include/sbi/sbi_irqchip.h
@@ -18,12 +18,21 @@ struct sbi_scratch;
 
 /** irqchip hardware device */
 struct sbi_irqchip_device {
-	/** Node in the list of irqchip devices */
+	/** Node in the list of irqchip devices (private) */
 	struct sbi_dlist node;
 
+	/** Internal data of all hardware interrupts of this irqchip (private) */
+	struct sbi_irqchip_hwirq_data *hwirqs;
+
+	/** List of interrupt handlers */
+	struct sbi_dlist handler_list;
+
 	/** Unique ID of this irqchip */
 	u32 id;
 
+	/** Number of hardware IRQs of this irqchip */
+	u32 num_hwirq;
+
 	/** Set of harts targetted by this irqchip */
 	struct sbi_hartmask target_harts;
 
@@ -32,6 +41,21 @@ struct sbi_irqchip_device {
 
 	/** Process hardware interrupts from this irqchip */
 	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
+
+	/** Setup a hardware interrupt of this irqchip */
+	int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
+
+	/** Cleanup a hardware interrupt of this irqchip */
+	void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
+
+	/** End of hardware interrupt of this irqchip */
+	void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
+
+	/** Mask a hardware interrupt of this irqchip */
+	void (*hwirq_mask)(struct sbi_irqchip_device *chip, u32 hwirq);
+
+	/** Unmask a hardware interrupt of this irqchip */
+	void (*hwirq_unmask)(struct sbi_irqchip_device *chip, u32 hwirq);
 };
 
 /**
@@ -44,6 +68,36 @@ struct sbi_irqchip_device {
  */
 int sbi_irqchip_process(void);
 
+/**
+ * Process a hwirq of an irqchip device
+ *
+ * This function is called by irqchip drivers to handle hardware
+ * interrupts of the irqchip.
+ */
+int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
+
+/** Unmask a hardware interrupt */
+int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
+
+/** Mask a hardware interrupt */
+int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
+
+/** Default raw hardware interrupt handler */
+int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq);
+
+/** Set raw hardware interrupt handler */
+int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
+				int (*raw_hndl)(struct sbi_irqchip_device *, u32));
+
+/** Register a hardware interrupt handler */
+int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
+				 u32 first_hwirq, u32 num_hwirq,
+				 int (*callback)(u32 hwirq, void *opaque), void *opaque);
+
+/** Unregister a hardware interrupt handler */
+int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
+				   u32 first_hwirq, u32 num_hwirq);
+
 /** Find an irqchip device based on unique ID */
 struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id);
 
diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
index fb3357f3..736dde6c 100644
--- a/lib/sbi/sbi_irqchip.c
+++ b/lib/sbi/sbi_irqchip.c
@@ -7,10 +7,35 @@
  *   Anup Patel <apatel@ventanamicro.com>
  */
 
+#include <sbi/sbi_heap.h>
 #include <sbi/sbi_irqchip.h>
 #include <sbi/sbi_list.h>
 #include <sbi/sbi_platform.h>
 
+/** Internal irqchip hardware interrupt data */
+struct sbi_irqchip_hwirq_data {
+	/** raw hardware interrupt handler */
+	int (*raw_handler)(struct sbi_irqchip_device *chip, u32 hwirq);
+};
+
+/** Internal irqchip interrupt handler */
+struct sbi_irqchip_handler {
+	/** Node in the list of irqchip handlers (private) */
+	struct sbi_dlist node;
+
+	/** First hardware IRQ handled by this handler */
+	u32 first_hwirq;
+
+	/** Number of consecutive hardware IRQs handled by this handler */
+	u32 num_hwirq;
+
+	/** Callback function of this handler */
+	int (*callback)(u32 hwirq, void *priv);
+
+	/** Callback private data */
+	void *priv;
+};
+
 static SBI_LIST_HEAD(irqchip_list);
 
 int sbi_irqchip_process(void)
@@ -31,6 +56,172 @@ int sbi_irqchip_process(void)
 	return rc;
 }
 
+int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
+{
+	struct sbi_irqchip_hwirq_data *data;
+
+	if (!chip || chip->num_hwirq <= hwirq)
+		return SBI_EINVAL;
+
+	data = &chip->hwirqs[hwirq];
+	if (!data->raw_handler)
+		return SBI_ENOENT;
+
+	return data->raw_handler(chip, hwirq);
+}
+
+int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
+{
+	if (!chip || chip->num_hwirq <= hwirq)
+		return SBI_EINVAL;
+
+	if (chip->hwirq_unmask)
+		chip->hwirq_unmask(chip, hwirq);
+	return 0;
+}
+
+int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
+{
+	if (!chip || chip->num_hwirq <= hwirq)
+		return SBI_EINVAL;
+
+	if (chip->hwirq_mask)
+		chip->hwirq_mask(chip, hwirq);
+	return 0;
+}
+
+static struct sbi_irqchip_handler *sbi_irqchip_find_handler(struct sbi_irqchip_device *chip,
+							    u32 hwirq)
+{
+	struct sbi_irqchip_handler *h;
+
+	if (!chip || chip->num_hwirq <= hwirq)
+		return NULL;
+
+	sbi_list_for_each_entry(h, &chip->handler_list, node) {
+		if (h->first_hwirq <= hwirq && hwirq < (h->first_hwirq + h->num_hwirq))
+			return h;
+	}
+
+	return NULL;
+}
+
+int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq)
+{
+	struct sbi_irqchip_handler *h;
+	int rc;
+
+	if (!chip || chip->num_hwirq <= hwirq)
+		return SBI_EINVAL;
+
+	h = sbi_irqchip_find_handler(chip, hwirq);
+	rc = h->callback(hwirq, h->priv);
+
+	if (chip->hwirq_eoi)
+		chip->hwirq_eoi(chip, hwirq);
+
+	return rc;
+}
+
+int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
+				int (*raw_hndl)(struct sbi_irqchip_device *, u32))
+{
+	struct sbi_irqchip_hwirq_data *data;
+
+	if (!chip || chip->num_hwirq <= hwirq)
+		return SBI_EINVAL;
+
+	data = &chip->hwirqs[hwirq];
+	data->raw_handler = raw_hndl;
+	return 0;
+}
+
+int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
+				 u32 first_hwirq, u32 num_hwirq,
+				 int (*callback)(u32 hwirq, void *opaque), void *priv)
+{
+	struct sbi_irqchip_handler *h;
+	u32 i, j;
+	int rc;
+
+	if (!chip || !num_hwirq || !callback)
+		return SBI_EINVAL;
+	if (chip->num_hwirq <= first_hwirq ||
+	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
+		return SBI_EBAD_RANGE;
+
+	h = sbi_irqchip_find_handler(chip, first_hwirq);
+	if (h)
+		return SBI_EALREADY;
+	h = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
+	if (h)
+		return SBI_EALREADY;
+
+	h = sbi_zalloc(sizeof(*h));
+	if (!h)
+		return SBI_ENOMEM;
+	h->first_hwirq = first_hwirq;
+	h->num_hwirq = num_hwirq;
+	h->callback = callback;
+	h->priv = priv;
+	sbi_list_add_tail(&h->node, &chip->handler_list);
+
+	if (chip->hwirq_setup) {
+		for (i = 0; i < h->num_hwirq; i++) {
+			rc = chip->hwirq_setup(chip, h->first_hwirq + i);
+			if (rc) {
+				if (chip->hwirq_cleanup) {
+					for (j = 0; j < i; j++)
+						chip->hwirq_cleanup(chip, h->first_hwirq + j);
+				}
+				sbi_list_del(&h->node);
+				sbi_free(h);
+				return rc;
+			}
+		}
+	}
+
+	if (chip->hwirq_unmask) {
+		for (i = 0; i < h->num_hwirq; i++)
+			chip->hwirq_unmask(chip, h->first_hwirq + i);
+	}
+
+	return 0;
+}
+
+int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
+				   u32 first_hwirq, u32 num_hwirq)
+{
+	struct sbi_irqchip_handler *fh, *lh;
+	u32 i;
+
+	if (!chip || !num_hwirq)
+		return SBI_EINVAL;
+	if (chip->num_hwirq <= first_hwirq ||
+	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
+		return SBI_EBAD_RANGE;
+
+	fh = sbi_irqchip_find_handler(chip, first_hwirq);
+	if (!fh || fh->first_hwirq != first_hwirq || fh->num_hwirq != num_hwirq)
+		return SBI_ENODEV;
+	lh = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
+	if (!lh || lh != fh)
+		return SBI_ENODEV;
+
+	if (chip->hwirq_mask) {
+		for (i = 0; i < fh->num_hwirq; i++)
+			chip->hwirq_mask(chip, fh->first_hwirq + i);
+	}
+
+	if (chip->hwirq_cleanup) {
+		for (i = 0; i < fh->num_hwirq; i++)
+			chip->hwirq_cleanup(chip, fh->first_hwirq + i);
+	}
+
+	sbi_list_del(&fh->node);
+	return 0;
+}
+
 struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id)
 {
 	struct sbi_irqchip_device *chip;
@@ -47,8 +238,9 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 {
 	struct sbi_irqchip_device *c;
 	struct sbi_hartmask hm;
+	u32 i;
 
-	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
+	if (!chip || !chip->num_hwirq || !sbi_hartmask_weight(&chip->target_harts))
 		return SBI_EINVAL;
 
 	if (sbi_irqchip_find_device(chip->id))
@@ -64,6 +256,14 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
 		}
 	}
 
+	chip->hwirqs = sbi_zalloc(sizeof(*chip->hwirqs) * chip->num_hwirq);
+	if (!chip->hwirqs)
+		return SBI_ENOMEM;
+	for (i = 0; i < chip->num_hwirq; i++)
+		sbi_irqchip_set_raw_handler(chip, i, sbi_irqchip_raw_handler_default);
+
+	SBI_INIT_LIST_HEAD(&chip->handler_list);
+
 	sbi_list_add_tail(&chip->node, &irqchip_list);
 	return 0;
 }
diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index d47a810b..ec69c82b 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -307,6 +307,7 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 
 	/* Register irqchip device */
 	aplic->irqchip.id = aplic->unique_id;
+	aplic->irqchip.num_hwirq = aplic->num_source + 1;
 	rc = sbi_irqchip_add_device(&aplic->irqchip);
 	if (rc)
 		return rc;
diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
index 0f296c89..7559a069 100644
--- a/lib/utils/irqchip/imsic.c
+++ b/lib/utils/irqchip/imsic.c
@@ -346,9 +346,17 @@ int imsic_data_check(struct imsic_data *imsic)
 	return 0;
 }
 
+static int imsic_hwirq_setup(struct sbi_irqchip_device *chip, u32 hwirq)
+{
+	if (!hwirq || hwirq == IMSIC_IPI_ID)
+		return SBI_ENOTSUPP;
+	return 0;
+}
+
 static struct sbi_irqchip_device imsic_device = {
 	.warm_init	= imsic_warm_irqchip_init,
 	.process_hwirqs	= imsic_process_hwirqs,
+	.hwirq_setup	= imsic_hwirq_setup,
 };
 
 int imsic_cold_irqchip_init(struct imsic_data *imsic)
@@ -392,6 +400,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
 
 	/* Register irqchip device */
 	imsic_device.id = imsic->unique_id;
+	imsic_device.num_hwirq = imsic->num_ids + 1;
 	sbi_hartmask_set_all(&imsic_device.target_harts);
 	rc = sbi_irqchip_add_device(&imsic_device);
 	if (rc)
diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
index 973f7c2a..2d721724 100644
--- a/lib/utils/irqchip/plic.c
+++ b/lib/utils/irqchip/plic.c
@@ -281,6 +281,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
 
 	/* Register irqchip device */
 	plic->irqchip.id = plic->unique_id;
+	plic->irqchip.num_hwirq = plic->num_src + 1;
 	plic->irqchip.warm_init = plic_warm_irqchip_init;
 	return sbi_irqchip_add_device(&plic->irqchip);
 }
-- 
2.43.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data
  2026-02-07 10:25 ` [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data Anup Patel
@ 2026-02-09 16:50   ` Andrew Jones
  2026-02-13  3:57     ` Anup Patel
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Jones @ 2026-02-09 16:50 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi

On Sat, Feb 07, 2026 at 03:55:58PM +0530, Anup Patel wrote:
> A platform can have multiple APLICs in direct-mode targetting
> different subset of harts. Add APLIC ID to hartindex map in
> struct aplic_data to capture the set of harts targed by a

/targed/targeted/

Thanks,
drew

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-07 10:25 ` [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts Anup Patel
@ 2026-02-09 16:50   ` Andrew Jones
  2026-02-13  3:59     ` Anup Patel
  2026-02-09 17:03   ` Samuel Holland
  2026-02-09 20:25   ` Raymond Mao
  2 siblings, 1 reply; 26+ messages in thread
From: Andrew Jones @ 2026-02-09 16:50 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi

On Sat, Feb 07, 2026 at 03:55:59PM +0530, Anup Patel wrote:
> It is possible to have platform where an irqchip device targets
> a subset of harts and there are multiple irqchip devices to cover
> all harts.
> 
> To support this scenario:
> 1) Add target_harts hartmask to struct sbi_irqchip_device which
>    represents the set of harts targetted by the irqchip device
> 2) Call warm_init() and irq_handle() callbacks of an irqchip device

/irq_handle/process_hwirqs/

Thanks,
drew

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
  2026-02-07 10:26 ` [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers Anup Patel
@ 2026-02-09 16:52   ` Andrew Jones
  2026-02-09 17:19   ` Samuel Holland
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 26+ messages in thread
From: Andrew Jones @ 2026-02-09 16:52 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi

On Sat, Feb 07, 2026 at 03:56:02PM +0530, Anup Patel wrote:
> To handle external interrupts in M-mode, the sbi_irqchip framework
> must allow registering interrupt handlers from device drivers.
> 
> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
> ---
>  include/sbi/sbi_irqchip.h |  56 ++++++++++-
>  lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
>  lib/utils/irqchip/aplic.c |   1 +
>  lib/utils/irqchip/imsic.c |   9 ++
>  lib/utils/irqchip/plic.c  |   1 +
>  5 files changed, 267 insertions(+), 2 deletions(-)
> 
> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> index d2c47ae8..77b54110 100644
> --- a/include/sbi/sbi_irqchip.h
> +++ b/include/sbi/sbi_irqchip.h
> @@ -18,12 +18,21 @@ struct sbi_scratch;
>  
>  /** irqchip hardware device */
>  struct sbi_irqchip_device {
> -	/** Node in the list of irqchip devices */
> +	/** Node in the list of irqchip devices (private) */
>  	struct sbi_dlist node;
>  
> +	/** Internal data of all hardware interrupts of this irqchip (private) */
> +	struct sbi_irqchip_hwirq_data *hwirqs;
> +
> +	/** List of interrupt handlers */
> +	struct sbi_dlist handler_list;
> +
>  	/** Unique ID of this irqchip */
>  	u32 id;
>  
> +	/** Number of hardware IRQs of this irqchip */
> +	u32 num_hwirq;
> +
>  	/** Set of harts targetted by this irqchip */
>  	struct sbi_hartmask target_harts;
>  
> @@ -32,6 +41,21 @@ struct sbi_irqchip_device {
>  
>  	/** Process hardware interrupts from this irqchip */
>  	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> +
> +	/** Setup a hardware interrupt of this irqchip */
> +	int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Cleanup a hardware interrupt of this irqchip */
> +	void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** End of hardware interrupt of this irqchip */
> +	void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Mask a hardware interrupt of this irqchip */
> +	void (*hwirq_mask)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Unmask a hardware interrupt of this irqchip */
> +	void (*hwirq_unmask)(struct sbi_irqchip_device *chip, u32 hwirq);
>  };
>  
>  /**
> @@ -44,6 +68,36 @@ struct sbi_irqchip_device {
>   */
>  int sbi_irqchip_process(void);
>  
> +/**
> + * Process a hwirq of an irqchip device
> + *
> + * This function is called by irqchip drivers to handle hardware
> + * interrupts of the irqchip.
> + */
> +int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Unmask a hardware interrupt */
> +int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Mask a hardware interrupt */
> +int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Default raw hardware interrupt handler */
> +int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Set raw hardware interrupt handler */
> +int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
> +				int (*raw_hndl)(struct sbi_irqchip_device *, u32));
> +
> +/** Register a hardware interrupt handler */
> +int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
> +				 u32 first_hwirq, u32 num_hwirq,
> +				 int (*callback)(u32 hwirq, void *opaque), void *opaque);
> +
> +/** Unregister a hardware interrupt handler */
> +int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
> +				   u32 first_hwirq, u32 num_hwirq);
> +
>  /** Find an irqchip device based on unique ID */
>  struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id);
>  
> diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> index fb3357f3..736dde6c 100644
> --- a/lib/sbi/sbi_irqchip.c
> +++ b/lib/sbi/sbi_irqchip.c
> @@ -7,10 +7,35 @@
>   *   Anup Patel <apatel@ventanamicro.com>
>   */
>  
> +#include <sbi/sbi_heap.h>
>  #include <sbi/sbi_irqchip.h>
>  #include <sbi/sbi_list.h>
>  #include <sbi/sbi_platform.h>
>  
> +/** Internal irqchip hardware interrupt data */
> +struct sbi_irqchip_hwirq_data {
> +	/** raw hardware interrupt handler */
> +	int (*raw_handler)(struct sbi_irqchip_device *chip, u32 hwirq);
> +};
> +
> +/** Internal irqchip interrupt handler */
> +struct sbi_irqchip_handler {
> +	/** Node in the list of irqchip handlers (private) */
> +	struct sbi_dlist node;
> +
> +	/** First hardware IRQ handled by this handler */
> +	u32 first_hwirq;
> +
> +	/** Number of consecutive hardware IRQs handled by this handler */
> +	u32 num_hwirq;
> +
> +	/** Callback function of this handler */
> +	int (*callback)(u32 hwirq, void *priv);
> +
> +	/** Callback private data */
> +	void *priv;
> +};
> +
>  static SBI_LIST_HEAD(irqchip_list);
>  
>  int sbi_irqchip_process(void)
> @@ -31,6 +56,172 @@ int sbi_irqchip_process(void)
>  	return rc;
>  }
>  
> +int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	struct sbi_irqchip_hwirq_data *data;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	data = &chip->hwirqs[hwirq];
> +	if (!data->raw_handler)
> +		return SBI_ENOENT;
> +
> +	return data->raw_handler(chip, hwirq);
> +}
> +
> +int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	if (chip->hwirq_unmask)
> +		chip->hwirq_unmask(chip, hwirq);
> +	return 0;
> +}
> +
> +int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	if (chip->hwirq_mask)
> +		chip->hwirq_mask(chip, hwirq);
> +	return 0;
> +}
> +
> +static struct sbi_irqchip_handler *sbi_irqchip_find_handler(struct sbi_irqchip_device *chip,
> +							    u32 hwirq)
> +{
> +	struct sbi_irqchip_handler *h;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return NULL;
> +
> +	sbi_list_for_each_entry(h, &chip->handler_list, node) {
> +		if (h->first_hwirq <= hwirq && hwirq < (h->first_hwirq + h->num_hwirq))
> +			return h;
> +	}
> +
> +	return NULL;
> +}
> +
> +int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	struct sbi_irqchip_handler *h;
> +	int rc;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	h = sbi_irqchip_find_handler(chip, hwirq);
> +	rc = h->callback(hwirq, h->priv);
> +
> +	if (chip->hwirq_eoi)
> +		chip->hwirq_eoi(chip, hwirq);
> +
> +	return rc;
> +}
> +
> +int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
> +				int (*raw_hndl)(struct sbi_irqchip_device *, u32))
> +{
> +	struct sbi_irqchip_hwirq_data *data;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	data = &chip->hwirqs[hwirq];
> +	data->raw_handler = raw_hndl;
> +	return 0;
> +}
> +
> +int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
> +				 u32 first_hwirq, u32 num_hwirq,
> +				 int (*callback)(u32 hwirq, void *opaque), void *priv)
> +{
> +	struct sbi_irqchip_handler *h;
> +	u32 i, j;
> +	int rc;
> +
> +	if (!chip || !num_hwirq || !callback)
> +		return SBI_EINVAL;
> +	if (chip->num_hwirq <= first_hwirq ||
> +	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
> +		return SBI_EBAD_RANGE;
> +
> +	h = sbi_irqchip_find_handler(chip, first_hwirq);
> +	if (h)
> +		return SBI_EALREADY;
> +	h = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
> +	if (h)
> +		return SBI_EALREADY;

We should loop over all hwirq numbers from first to the end to ensure no
other handler is already registered for numbers inside the range. Same
comment for sbi_irqchip_unregister_handler() below.

Thanks,
drew

> +
> +	h = sbi_zalloc(sizeof(*h));
> +	if (!h)
> +		return SBI_ENOMEM;
> +	h->first_hwirq = first_hwirq;
> +	h->num_hwirq = num_hwirq;
> +	h->callback = callback;
> +	h->priv = priv;
> +	sbi_list_add_tail(&h->node, &chip->handler_list);
> +
> +	if (chip->hwirq_setup) {
> +		for (i = 0; i < h->num_hwirq; i++) {
> +			rc = chip->hwirq_setup(chip, h->first_hwirq + i);
> +			if (rc) {
> +				if (chip->hwirq_cleanup) {
> +					for (j = 0; j < i; j++)
> +						chip->hwirq_cleanup(chip, h->first_hwirq + j);
> +				}
> +				sbi_list_del(&h->node);
> +				sbi_free(h);
> +				return rc;
> +			}
> +		}
> +	}
> +
> +	if (chip->hwirq_unmask) {
> +		for (i = 0; i < h->num_hwirq; i++)
> +			chip->hwirq_unmask(chip, h->first_hwirq + i);
> +	}
> +
> +	return 0;
> +}
> +
> +int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
> +				   u32 first_hwirq, u32 num_hwirq)
> +{
> +	struct sbi_irqchip_handler *fh, *lh;
> +	u32 i;
> +
> +	if (!chip || !num_hwirq)
> +		return SBI_EINVAL;
> +	if (chip->num_hwirq <= first_hwirq ||
> +	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
> +		return SBI_EBAD_RANGE;
> +
> +	fh = sbi_irqchip_find_handler(chip, first_hwirq);
> +	if (!fh || fh->first_hwirq != first_hwirq || fh->num_hwirq != num_hwirq)
> +		return SBI_ENODEV;
> +	lh = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
> +	if (!lh || lh != fh)
> +		return SBI_ENODEV;
> +
> +	if (chip->hwirq_mask) {
> +		for (i = 0; i < fh->num_hwirq; i++)
> +			chip->hwirq_mask(chip, fh->first_hwirq + i);
> +	}
> +
> +	if (chip->hwirq_cleanup) {
> +		for (i = 0; i < fh->num_hwirq; i++)
> +			chip->hwirq_cleanup(chip, fh->first_hwirq + i);
> +	}
> +
> +	sbi_list_del(&fh->node);
> +	return 0;
> +}
> +
>  struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id)
>  {
>  	struct sbi_irqchip_device *chip;
> @@ -47,8 +238,9 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>  {
>  	struct sbi_irqchip_device *c;
>  	struct sbi_hartmask hm;
> +	u32 i;
>  
> -	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> +	if (!chip || !chip->num_hwirq || !sbi_hartmask_weight(&chip->target_harts))
>  		return SBI_EINVAL;
>  
>  	if (sbi_irqchip_find_device(chip->id))
> @@ -64,6 +256,14 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>  		}
>  	}
>  
> +	chip->hwirqs = sbi_zalloc(sizeof(*chip->hwirqs) * chip->num_hwirq);
> +	if (!chip->hwirqs)
> +		return SBI_ENOMEM;
> +	for (i = 0; i < chip->num_hwirq; i++)
> +		sbi_irqchip_set_raw_handler(chip, i, sbi_irqchip_raw_handler_default);
> +
> +	SBI_INIT_LIST_HEAD(&chip->handler_list);
> +
>  	sbi_list_add_tail(&chip->node, &irqchip_list);
>  	return 0;
>  }
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> index d47a810b..ec69c82b 100644
> --- a/lib/utils/irqchip/aplic.c
> +++ b/lib/utils/irqchip/aplic.c
> @@ -307,6 +307,7 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
>  
>  	/* Register irqchip device */
>  	aplic->irqchip.id = aplic->unique_id;
> +	aplic->irqchip.num_hwirq = aplic->num_source + 1;
>  	rc = sbi_irqchip_add_device(&aplic->irqchip);
>  	if (rc)
>  		return rc;
> diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
> index 0f296c89..7559a069 100644
> --- a/lib/utils/irqchip/imsic.c
> +++ b/lib/utils/irqchip/imsic.c
> @@ -346,9 +346,17 @@ int imsic_data_check(struct imsic_data *imsic)
>  	return 0;
>  }
>  
> +static int imsic_hwirq_setup(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!hwirq || hwirq == IMSIC_IPI_ID)
> +		return SBI_ENOTSUPP;
> +	return 0;
> +}
> +
>  static struct sbi_irqchip_device imsic_device = {
>  	.warm_init	= imsic_warm_irqchip_init,
>  	.process_hwirqs	= imsic_process_hwirqs,
> +	.hwirq_setup	= imsic_hwirq_setup,
>  };
>  
>  int imsic_cold_irqchip_init(struct imsic_data *imsic)
> @@ -392,6 +400,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
>  
>  	/* Register irqchip device */
>  	imsic_device.id = imsic->unique_id;
> +	imsic_device.num_hwirq = imsic->num_ids + 1;
>  	sbi_hartmask_set_all(&imsic_device.target_harts);
>  	rc = sbi_irqchip_add_device(&imsic_device);
>  	if (rc)
> diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
> index 973f7c2a..2d721724 100644
> --- a/lib/utils/irqchip/plic.c
> +++ b/lib/utils/irqchip/plic.c
> @@ -281,6 +281,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
>  
>  	/* Register irqchip device */
>  	plic->irqchip.id = plic->unique_id;
> +	plic->irqchip.num_hwirq = plic->num_src + 1;
>  	plic->irqchip.warm_init = plic_warm_irqchip_init;
>  	return sbi_irqchip_add_device(&plic->irqchip);
>  }
> -- 
> 2.43.0
> 

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-07 10:25 ` [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts Anup Patel
  2026-02-09 16:50   ` Andrew Jones
@ 2026-02-09 17:03   ` Samuel Holland
  2026-02-13  4:01     ` Anup Patel
  2026-02-09 20:25   ` Raymond Mao
  2 siblings, 1 reply; 26+ messages in thread
From: Samuel Holland @ 2026-02-09 17:03 UTC (permalink / raw)
  To: Anup Patel, Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Anup Patel, opensbi

Hi Anup,

On 2026-02-07 4:25 AM, Anup Patel wrote:
> It is possible to have platform where an irqchip device targets
> a subset of harts and there are multiple irqchip devices to cover
> all harts.
> 
> To support this scenario:
> 1) Add target_harts hartmask to struct sbi_irqchip_device which
>    represents the set of harts targetted by the irqchip device
> 2) Call warm_init() and irq_handle() callbacks of an irqchip device
>    on a hart only if irqchip device targets that particular hart
> 
> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
> ---
>  include/sbi/sbi_irqchip.h |  8 +++++--
>  lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
>  lib/utils/irqchip/aplic.c | 12 +++++++++-
>  lib/utils/irqchip/imsic.c |  7 ++++--
>  lib/utils/irqchip/plic.c  |  5 ++--
>  5 files changed, 59 insertions(+), 21 deletions(-)
> 
> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> index cda1e50f..c3ded271 100644
> --- a/include/sbi/sbi_irqchip.h
> +++ b/include/sbi/sbi_irqchip.h
> @@ -10,6 +10,7 @@
>  #ifndef __SBI_IRQCHIP_H__
>  #define __SBI_IRQCHIP_H__
>  
> +#include <sbi/sbi_hartmask.h>
>  #include <sbi/sbi_list.h>
>  #include <sbi/sbi_types.h>
>  
> @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
>  	/** Node in the list of irqchip devices */
>  	struct sbi_dlist node;
>  
> +	/** Set of harts targetted by this irqchip */
> +	struct sbi_hartmask target_harts;
> +
>  	/** Initialize per-hart state for the current hart */
>  	int (*warm_init)(struct sbi_irqchip_device *chip);
>  
>  	/** Process hardware interrupts from this irqchip */
> -	int (*process_hwirqs)(void);
> +	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
>  };
>  
>  /**
> @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
>  int sbi_irqchip_process(void);
>  
>  /** Register an irqchip device to receive callbacks */
> -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
>  
>  /** Initialize interrupt controllers */
>  int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> index 3b970527..77ec05af 100644
> --- a/lib/sbi/sbi_irqchip.c
> +++ b/lib/sbi/sbi_irqchip.c
> @@ -13,24 +13,44 @@
>  
>  static SBI_LIST_HEAD(irqchip_list);
>  
> -static int default_irqfn(void)
> +int sbi_irqchip_process(void)
>  {
> -	return SBI_ENODEV;
> -}
> +	struct sbi_irqchip_device *chip;
> +	int rc = SBI_ENODEV;
>  
> -static int (*ext_irqfn)(void) = default_irqfn;
> +	sbi_list_for_each_entry(chip, &irqchip_list, node) {
> +		if (!chip->process_hwirqs)
> +			continue;
> +		if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> +			continue;
> +		rc = chip->process_hwirqs(chip);
> +		if (rc)
> +			break;

This is a hot path (used for IPIs already), so I would recommend using a
per-hart pointer to the top-level chip that gets set in
sbi_irqchip_add_device(), so there is no lookup needed here.

> +	}
>  
> -int sbi_irqchip_process(void)
> -{
> -	return ext_irqfn();
> +	return rc;
>  }
>  
> -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>  {
> -	sbi_list_add_tail(&chip->node, &irqchip_list);
> +	struct sbi_irqchip_device *c;
> +	struct sbi_hartmask hm;
> +
> +	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> +		return SBI_EINVAL;
> +
> +	if (chip->process_hwirqs) {
> +		sbi_list_for_each_entry(c, &irqchip_list, node) {
> +			if (!c->process_hwirqs)
> +				continue;
> +			sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> +			if (sbi_hartmask_weight(&hm))
> +				return SBI_EINVAL;
> +		}
> +	}
>  
> -	if (chip->process_hwirqs)
> -		ext_irqfn = chip->process_hwirqs;
> +	sbi_list_add_tail(&chip->node, &irqchip_list);
> +	return 0;
>  }
>  
>  int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
> @@ -48,12 +68,14 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
>  	sbi_list_for_each_entry(chip, &irqchip_list, node) {
>  		if (!chip->warm_init)
>  			continue;
> +		if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> +			continue;
>  		rc = chip->warm_init(chip);
>  		if (rc)
>  			return rc;
>  	}
>  
> -	if (ext_irqfn != default_irqfn)
> +	if (!sbi_list_empty(&irqchip_list))
>  		csr_set(CSR_MIE, MIP_MEIP);

This should only enable interrupts if there is an irqchip targeting the current
hart.

Regards,
Samuel

>  
>  	return 0;
> @@ -61,6 +83,6 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
>  
>  void sbi_irqchip_exit(struct sbi_scratch *scratch)
>  {
> -	if (ext_irqfn != default_irqfn)
> +	if (!sbi_list_empty(&irqchip_list))
>  		csr_clear(CSR_MIE, MIP_MEIP);
>  }
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> index 8d0db168..ea5cb7c4 100644
> --- a/lib/utils/irqchip/aplic.c
> +++ b/lib/utils/irqchip/aplic.c
> @@ -297,8 +297,18 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
>  			return rc;
>  	}
>  
> +	if (aplic->num_idc) {
> +		for (i = 0; i < aplic->num_idc; i++)
> +			sbi_hartmask_set_hartindex(aplic->idc_map[i],
> +						   &aplic->irqchip.target_harts);
> +	} else {
> +		sbi_hartmask_set_all(&aplic->irqchip.target_harts);
> +	}
> +
>  	/* Register irqchip device */
> -	sbi_irqchip_add_device(&aplic->irqchip);
> +	rc = sbi_irqchip_add_device(&aplic->irqchip);
> +	if (rc)
> +		return rc;
>  
>  	/* Attach to the aplic list */
>  	sbi_list_add_tail(&aplic->node, &aplic_list);
> diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
> index 0e9917da..5ec9dff4 100644
> --- a/lib/utils/irqchip/imsic.c
> +++ b/lib/utils/irqchip/imsic.c
> @@ -147,7 +147,7 @@ int imsic_get_target_file(u32 hartindex)
>  	return imsic_get_hart_file(scratch);
>  }
>  
> -static int imsic_process_hwirqs(void)
> +static int imsic_process_hwirqs(struct sbi_irqchip_device *chip)
>  {
>  	ulong mirq;
>  
> @@ -391,7 +391,10 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
>  	}
>  
>  	/* Register irqchip device */
> -	sbi_irqchip_add_device(&imsic_device);
> +	sbi_hartmask_set_all(&imsic_device.target_harts);
> +	rc = sbi_irqchip_add_device(&imsic_device);
> +	if (rc)
> +		return rc;
>  
>  	/* Register IPI device */
>  	sbi_ipi_add_device(&imsic_ipi_device);
> diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
> index 7989a962..25cc2787 100644
> --- a/lib/utils/irqchip/plic.c
> +++ b/lib/utils/irqchip/plic.c
> @@ -276,11 +276,10 @@ int plic_cold_irqchip_init(struct plic_data *plic)
>  			continue;
>  
>  		plic_set_hart_data_ptr(sbi_hartindex_to_scratch(i), plic);
> +		sbi_hartmask_set_hartindex(i, &plic->irqchip.target_harts);
>  	}
>  
>  	/* Register irqchip device */
>  	plic->irqchip.warm_init = plic_warm_irqchip_init;
> -	sbi_irqchip_add_device(&plic->irqchip);
> -
> -	return 0;
> +	return sbi_irqchip_add_device(&plic->irqchip);
>  }


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
  2026-02-07 10:26 ` [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers Anup Patel
  2026-02-09 16:52   ` Andrew Jones
@ 2026-02-09 17:19   ` Samuel Holland
  2026-02-09 20:34   ` Raymond Mao
       [not found]   ` <CAMkFH19feRsme6Mfr1vQ7hSnr2yhFMivNpGkwfTT2uSV3ojnjg@mail.gmail.com>
  3 siblings, 0 replies; 26+ messages in thread
From: Samuel Holland @ 2026-02-09 17:19 UTC (permalink / raw)
  To: Anup Patel, Atish Patra
  Cc: Andrew Jones, Raymond Mao, Dave Patel, Anup Patel, opensbi

Hi Anup,

On 2026-02-07 4:26 AM, Anup Patel wrote:
> To handle external interrupts in M-mode, the sbi_irqchip framework
> must allow registering interrupt handlers from device drivers.
> 
> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
> ---
>  include/sbi/sbi_irqchip.h |  56 ++++++++++-
>  lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
>  lib/utils/irqchip/aplic.c |   1 +
>  lib/utils/irqchip/imsic.c |   9 ++
>  lib/utils/irqchip/plic.c  |   1 +
>  5 files changed, 267 insertions(+), 2 deletions(-)
> 
> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> index d2c47ae8..77b54110 100644
> --- a/include/sbi/sbi_irqchip.h
> +++ b/include/sbi/sbi_irqchip.h
> @@ -18,12 +18,21 @@ struct sbi_scratch;
>  
>  /** irqchip hardware device */
>  struct sbi_irqchip_device {
> -	/** Node in the list of irqchip devices */
> +	/** Node in the list of irqchip devices (private) */
>  	struct sbi_dlist node;
>  
> +	/** Internal data of all hardware interrupts of this irqchip (private) */
> +	struct sbi_irqchip_hwirq_data *hwirqs;
> +
> +	/** List of interrupt handlers */
> +	struct sbi_dlist handler_list;
> +
>  	/** Unique ID of this irqchip */
>  	u32 id;
>  
> +	/** Number of hardware IRQs of this irqchip */
> +	u32 num_hwirq;
> +
>  	/** Set of harts targetted by this irqchip */
>  	struct sbi_hartmask target_harts;
>  
> @@ -32,6 +41,21 @@ struct sbi_irqchip_device {
>  
>  	/** Process hardware interrupts from this irqchip */
>  	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> +
> +	/** Setup a hardware interrupt of this irqchip */
> +	int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Cleanup a hardware interrupt of this irqchip */
> +	void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** End of hardware interrupt of this irqchip */
> +	void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Mask a hardware interrupt of this irqchip */
> +	void (*hwirq_mask)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Unmask a hardware interrupt of this irqchip */
> +	void (*hwirq_unmask)(struct sbi_irqchip_device *chip, u32 hwirq);
>  };
>  
>  /**
> @@ -44,6 +68,36 @@ struct sbi_irqchip_device {
>   */
>  int sbi_irqchip_process(void);
>  
> +/**
> + * Process a hwirq of an irqchip device
> + *
> + * This function is called by irqchip drivers to handle hardware
> + * interrupts of the irqchip.
> + */
> +int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Unmask a hardware interrupt */
> +int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Mask a hardware interrupt */
> +int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Default raw hardware interrupt handler */
> +int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Set raw hardware interrupt handler */
> +int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
> +				int (*raw_hndl)(struct sbi_irqchip_device *, u32));
> +
> +/** Register a hardware interrupt handler */
> +int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
> +				 u32 first_hwirq, u32 num_hwirq,
> +				 int (*callback)(u32 hwirq, void *opaque), void *opaque);
> +
> +/** Unregister a hardware interrupt handler */
> +int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
> +				   u32 first_hwirq, u32 num_hwirq);
> +
>  /** Find an irqchip device based on unique ID */
>  struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id);
>  
> diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> index fb3357f3..736dde6c 100644
> --- a/lib/sbi/sbi_irqchip.c
> +++ b/lib/sbi/sbi_irqchip.c
> @@ -7,10 +7,35 @@
>   *   Anup Patel <apatel@ventanamicro.com>
>   */
>  
> +#include <sbi/sbi_heap.h>
>  #include <sbi/sbi_irqchip.h>
>  #include <sbi/sbi_list.h>
>  #include <sbi/sbi_platform.h>
>  
> +/** Internal irqchip hardware interrupt data */
> +struct sbi_irqchip_hwirq_data {
> +	/** raw hardware interrupt handler */
> +	int (*raw_handler)(struct sbi_irqchip_device *chip, u32 hwirq);
> +};
> +
> +/** Internal irqchip interrupt handler */
> +struct sbi_irqchip_handler {
> +	/** Node in the list of irqchip handlers (private) */
> +	struct sbi_dlist node;
> +
> +	/** First hardware IRQ handled by this handler */
> +	u32 first_hwirq;
> +
> +	/** Number of consecutive hardware IRQs handled by this handler */
> +	u32 num_hwirq;
> +
> +	/** Callback function of this handler */
> +	int (*callback)(u32 hwirq, void *priv);
> +
> +	/** Callback private data */
> +	void *priv;
> +};
> +
>  static SBI_LIST_HEAD(irqchip_list);
>  
>  int sbi_irqchip_process(void)
> @@ -31,6 +56,172 @@ int sbi_irqchip_process(void)
>  	return rc;
>  }
>  
> +int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	struct sbi_irqchip_hwirq_data *data;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	data = &chip->hwirqs[hwirq];
> +	if (!data->raw_handler)
> +		return SBI_ENOENT;
> +
> +	return data->raw_handler(chip, hwirq);
> +}
> +
> +int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	if (chip->hwirq_unmask)
> +		chip->hwirq_unmask(chip, hwirq);
> +	return 0;
> +}
> +
> +int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	if (chip->hwirq_mask)
> +		chip->hwirq_mask(chip, hwirq);
> +	return 0;
> +}
> +
> +static struct sbi_irqchip_handler *sbi_irqchip_find_handler(struct sbi_irqchip_device *chip,
> +							    u32 hwirq)
> +{
> +	struct sbi_irqchip_handler *h;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return NULL;
> +
> +	sbi_list_for_each_entry(h, &chip->handler_list, node) {
> +		if (h->first_hwirq <= hwirq && hwirq < (h->first_hwirq + h->num_hwirq))
> +			return h;
> +	}
> +
> +	return NULL;
> +}
> +
> +int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	struct sbi_irqchip_handler *h;
> +	int rc;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	h = sbi_irqchip_find_handler(chip, hwirq);
> +	rc = h->callback(hwirq, h->priv);
> +
> +	if (chip->hwirq_eoi)
> +		chip->hwirq_eoi(chip, hwirq);
> +
> +	return rc;
> +}
> +
> +int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
> +				int (*raw_hndl)(struct sbi_irqchip_device *, u32))
> +{
> +	struct sbi_irqchip_hwirq_data *data;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	data = &chip->hwirqs[hwirq];
> +	data->raw_handler = raw_hndl;
> +	return 0;
> +}
> +
> +int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
> +				 u32 first_hwirq, u32 num_hwirq,
> +				 int (*callback)(u32 hwirq, void *opaque), void *priv)
> +{
> +	struct sbi_irqchip_handler *h;
> +	u32 i, j;
> +	int rc;
> +
> +	if (!chip || !num_hwirq || !callback)
> +		return SBI_EINVAL;
> +	if (chip->num_hwirq <= first_hwirq ||
> +	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
> +		return SBI_EBAD_RANGE;
> +
> +	h = sbi_irqchip_find_handler(chip, first_hwirq);
> +	if (h)
> +		return SBI_EALREADY;
> +	h = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
> +	if (h)
> +		return SBI_EALREADY;
> +
> +	h = sbi_zalloc(sizeof(*h));
> +	if (!h)
> +		return SBI_ENOMEM;
> +	h->first_hwirq = first_hwirq;
> +	h->num_hwirq = num_hwirq;
> +	h->callback = callback;
> +	h->priv = priv;
> +	sbi_list_add_tail(&h->node, &chip->handler_list);
> +
> +	if (chip->hwirq_setup) {
> +		for (i = 0; i < h->num_hwirq; i++) {
> +			rc = chip->hwirq_setup(chip, h->first_hwirq + i);

I would recommend storing the pointer to the sbi_irqchip_handler in each hwirq's
sbi_irqchip_hwirq_data here, so there is no list lookup in the hot path. If you
do that, there doesn't seem to be a need for the second raw_handler level of
function pointer indirection.

Regards,
Samuel

> +			if (rc) {
> +				if (chip->hwirq_cleanup) {
> +					for (j = 0; j < i; j++)
> +						chip->hwirq_cleanup(chip, h->first_hwirq + j);
> +				}
> +				sbi_list_del(&h->node);
> +				sbi_free(h);
> +				return rc;
> +			}
> +		}
> +	}
> +
> +	if (chip->hwirq_unmask) {
> +		for (i = 0; i < h->num_hwirq; i++)
> +			chip->hwirq_unmask(chip, h->first_hwirq + i);
> +	}
> +
> +	return 0;
> +}
> +
> +int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
> +				   u32 first_hwirq, u32 num_hwirq)
> +{
> +	struct sbi_irqchip_handler *fh, *lh;
> +	u32 i;
> +
> +	if (!chip || !num_hwirq)
> +		return SBI_EINVAL;
> +	if (chip->num_hwirq <= first_hwirq ||
> +	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
> +		return SBI_EBAD_RANGE;
> +
> +	fh = sbi_irqchip_find_handler(chip, first_hwirq);
> +	if (!fh || fh->first_hwirq != first_hwirq || fh->num_hwirq != num_hwirq)
> +		return SBI_ENODEV;
> +	lh = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
> +	if (!lh || lh != fh)
> +		return SBI_ENODEV;
> +
> +	if (chip->hwirq_mask) {
> +		for (i = 0; i < fh->num_hwirq; i++)
> +			chip->hwirq_mask(chip, fh->first_hwirq + i);
> +	}
> +
> +	if (chip->hwirq_cleanup) {
> +		for (i = 0; i < fh->num_hwirq; i++)
> +			chip->hwirq_cleanup(chip, fh->first_hwirq + i);
> +	}
> +
> +	sbi_list_del(&fh->node);
> +	return 0;
> +}
> +
>  struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id)
>  {
>  	struct sbi_irqchip_device *chip;
> @@ -47,8 +238,9 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>  {
>  	struct sbi_irqchip_device *c;
>  	struct sbi_hartmask hm;
> +	u32 i;
>  
> -	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> +	if (!chip || !chip->num_hwirq || !sbi_hartmask_weight(&chip->target_harts))
>  		return SBI_EINVAL;
>  
>  	if (sbi_irqchip_find_device(chip->id))
> @@ -64,6 +256,14 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>  		}
>  	}
>  
> +	chip->hwirqs = sbi_zalloc(sizeof(*chip->hwirqs) * chip->num_hwirq);
> +	if (!chip->hwirqs)
> +		return SBI_ENOMEM;
> +	for (i = 0; i < chip->num_hwirq; i++)
> +		sbi_irqchip_set_raw_handler(chip, i, sbi_irqchip_raw_handler_default);
> +
> +	SBI_INIT_LIST_HEAD(&chip->handler_list);
> +
>  	sbi_list_add_tail(&chip->node, &irqchip_list);
>  	return 0;
>  }
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> index d47a810b..ec69c82b 100644
> --- a/lib/utils/irqchip/aplic.c
> +++ b/lib/utils/irqchip/aplic.c
> @@ -307,6 +307,7 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
>  
>  	/* Register irqchip device */
>  	aplic->irqchip.id = aplic->unique_id;
> +	aplic->irqchip.num_hwirq = aplic->num_source + 1;
>  	rc = sbi_irqchip_add_device(&aplic->irqchip);
>  	if (rc)
>  		return rc;
> diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
> index 0f296c89..7559a069 100644
> --- a/lib/utils/irqchip/imsic.c
> +++ b/lib/utils/irqchip/imsic.c
> @@ -346,9 +346,17 @@ int imsic_data_check(struct imsic_data *imsic)
>  	return 0;
>  }
>  
> +static int imsic_hwirq_setup(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!hwirq || hwirq == IMSIC_IPI_ID)
> +		return SBI_ENOTSUPP;
> +	return 0;
> +}
> +
>  static struct sbi_irqchip_device imsic_device = {
>  	.warm_init	= imsic_warm_irqchip_init,
>  	.process_hwirqs	= imsic_process_hwirqs,
> +	.hwirq_setup	= imsic_hwirq_setup,
>  };
>  
>  int imsic_cold_irqchip_init(struct imsic_data *imsic)
> @@ -392,6 +400,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
>  
>  	/* Register irqchip device */
>  	imsic_device.id = imsic->unique_id;
> +	imsic_device.num_hwirq = imsic->num_ids + 1;
>  	sbi_hartmask_set_all(&imsic_device.target_harts);
>  	rc = sbi_irqchip_add_device(&imsic_device);
>  	if (rc)
> diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
> index 973f7c2a..2d721724 100644
> --- a/lib/utils/irqchip/plic.c
> +++ b/lib/utils/irqchip/plic.c
> @@ -281,6 +281,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
>  
>  	/* Register irqchip device */
>  	plic->irqchip.id = plic->unique_id;
> +	plic->irqchip.num_hwirq = plic->num_src + 1;
>  	plic->irqchip.warm_init = plic_warm_irqchip_init;
>  	return sbi_irqchip_add_device(&plic->irqchip);
>  }


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-07 10:25 ` [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts Anup Patel
  2026-02-09 16:50   ` Andrew Jones
  2026-02-09 17:03   ` Samuel Holland
@ 2026-02-09 20:25   ` Raymond Mao
  2026-02-10 16:09     ` Anup Patel
  2 siblings, 1 reply; 26+ messages in thread
From: Raymond Mao @ 2026-02-09 20:25 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Andrew Jones, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

Hi Anup,

On 2026-02-07 5:25 a.m., anup.patel at oss.qualcomm.com (Anup Patel) wrote:
> It is possible to have platform where an irqchip device targets
> a subset of harts and there are multiple irqchip devices to cover
> all harts.
>
> To support this scenario:
> 1) Add target_harts hartmask to struct sbi_irqchip_device which
>     represents the set of harts targetted by the irqchip device
> 2) Call warm_init() and irq_handle() callbacks of an irqchip device
>     on a hart only if irqchip device targets that particular hart
>
> Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> ---
>   include/sbi/sbi_irqchip.h |  8 +++++--
>   lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
>   lib/utils/irqchip/aplic.c | 12 +++++++++-
>   lib/utils/irqchip/imsic.c |  7 ++++--
>   lib/utils/irqchip/plic.c  |  5 ++--
>   5 files changed, 59 insertions(+), 21 deletions(-)
>
> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> index cda1e50f..c3ded271 100644
> --- a/include/sbi/sbi_irqchip.h
> +++ b/include/sbi/sbi_irqchip.h
> @@ -10,6 +10,7 @@
>   #ifndef __SBI_IRQCHIP_H__
>   #define __SBI_IRQCHIP_H__
>   
> +#include <sbi/sbi_hartmask.h>
>   #include <sbi/sbi_list.h>
>   #include <sbi/sbi_types.h>
>   
> @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
>   	/** Node in the list of irqchip devices */
>   	struct sbi_dlist node;
>   
> +	/** Set of harts targetted by this irqchip */
> +	struct sbi_hartmask target_harts;
> +
>   	/** Initialize per-hart state for the current hart */
>   	int (*warm_init)(struct sbi_irqchip_device *chip);
>   
>   	/** Process hardware interrupts from this irqchip */
> -	int (*process_hwirqs)(void);
> +	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
>   };
>   
>   /**
> @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
>   int sbi_irqchip_process(void);
>   
>   /** Register an irqchip device to receive callbacks */
> -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
>   
>   /** Initialize interrupt controllers */
>   int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> index 3b970527..77ec05af 100644
> --- a/lib/sbi/sbi_irqchip.c
> +++ b/lib/sbi/sbi_irqchip.c
> @@ -13,24 +13,44 @@
>   
>   static SBI_LIST_HEAD(irqchip_list);
>   
> -static int default_irqfn(void)
> +int sbi_irqchip_process(void)
>   {
> -	return SBI_ENODEV;
> -}
> +	struct sbi_irqchip_device *chip;
> +	int rc = SBI_ENODEV;
>   
> -static int (*ext_irqfn)(void) = default_irqfn;
> +	sbi_list_for_each_entry(chip, &irqchip_list, node) {
> +		if (!chip->process_hwirqs)
> +			continue;
> +		if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> +			continue;
> +		rc = chip->process_hwirqs(chip);
> +		if (rc)
> +			break;
> +	}
>   
> -int sbi_irqchip_process(void)
> -{
> -	return ext_irqfn();
> +	return rc;
>   }
>   
> -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>   {
> -	sbi_list_add_tail(&chip->node, &irqchip_list);
> +	struct sbi_irqchip_device *c;
> +	struct sbi_hartmask hm;
> +
> +	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> +		return SBI_EINVAL;
> +
> +	if (chip->process_hwirqs) {
> +		sbi_list_for_each_entry(c, &irqchip_list, node) {
> +			if (!c->process_hwirqs)
> +				continue;
> +			sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> +			if (sbi_hartmask_weight(&hm))
> +				return SBI_EINVAL;

I tested this by registering a 'process_hwirqs' hook, but 
'sbi_hartmask_weight' returns errors.

Regards,
Raymond

> +		}
> +	}
>   
> -	if (chip->process_hwirqs)
> -		ext_irqfn = chip->process_hwirqs;
> +	sbi_list_add_tail(&chip->node, &irqchip_list);
> +	return 0;
>   }
>   
>   int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
> @@ -48,12 +68,14 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
>   	sbi_list_for_each_entry(chip, &irqchip_list, node) {
>   		if (!chip->warm_init)
>   			continue;
> +		if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> +			continue;
>   		rc = chip->warm_init(chip);
>   		if (rc)
>   			return rc;
>   	}
>   
> -	if (ext_irqfn != default_irqfn)
> +	if (!sbi_list_empty(&irqchip_list))
>   		csr_set(CSR_MIE, MIP_MEIP);
>   
>   	return 0;
> @@ -61,6 +83,6 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
>   
>   void sbi_irqchip_exit(struct sbi_scratch *scratch)
>   {
> -	if (ext_irqfn != default_irqfn)
> +	if (!sbi_list_empty(&irqchip_list))
>   		csr_clear(CSR_MIE, MIP_MEIP);
>   }
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> index 8d0db168..ea5cb7c4 100644
> --- a/lib/utils/irqchip/aplic.c
> +++ b/lib/utils/irqchip/aplic.c
> @@ -297,8 +297,18 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
>   			return rc;
>   	}
>   
> +	if (aplic->num_idc) {
> +		for (i = 0; i < aplic->num_idc; i++)
> +			sbi_hartmask_set_hartindex(aplic->idc_map[i],
> +						   &aplic->irqchip.target_harts);
> +	} else {
> +		sbi_hartmask_set_all(&aplic->irqchip.target_harts);
> +	}
> +
>   	/* Register irqchip device */
> -	sbi_irqchip_add_device(&aplic->irqchip);
> +	rc = sbi_irqchip_add_device(&aplic->irqchip);
> +	if (rc)
> +		return rc;
>   
>   	/* Attach to the aplic list */
>   	sbi_list_add_tail(&aplic->node, &aplic_list);
> diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
> index 0e9917da..5ec9dff4 100644
> --- a/lib/utils/irqchip/imsic.c
> +++ b/lib/utils/irqchip/imsic.c
> @@ -147,7 +147,7 @@ int imsic_get_target_file(u32 hartindex)
>   	return imsic_get_hart_file(scratch);
>   }
>   
> -static int imsic_process_hwirqs(void)
> +static int imsic_process_hwirqs(struct sbi_irqchip_device *chip)
>   {
>   	ulong mirq;
>   
> @@ -391,7 +391,10 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
>   	}
>   
>   	/* Register irqchip device */
> -	sbi_irqchip_add_device(&imsic_device);
> +	sbi_hartmask_set_all(&imsic_device.target_harts);
> +	rc = sbi_irqchip_add_device(&imsic_device);
> +	if (rc)
> +		return rc;
>   
>   	/* Register IPI device */
>   	sbi_ipi_add_device(&imsic_ipi_device);
> diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
> index 7989a962..25cc2787 100644
> --- a/lib/utils/irqchip/plic.c
> +++ b/lib/utils/irqchip/plic.c
> @@ -276,11 +276,10 @@ int plic_cold_irqchip_init(struct plic_data *plic)
>   			continue;
>   
>   		plic_set_hart_data_ptr(sbi_hartindex_to_scratch(i), plic);
> +		sbi_hartmask_set_hartindex(i, &plic->irqchip.target_harts);
>   	}
>   
>   	/* Register irqchip device */
>   	plic->irqchip.warm_init = plic_warm_irqchip_init;
> -	sbi_irqchip_add_device(&plic->irqchip);
> -
> -	return 0;
> +	return sbi_irqchip_add_device(&plic->irqchip);
>   }

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
  2026-02-07 10:26 ` [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers Anup Patel
  2026-02-09 16:52   ` Andrew Jones
  2026-02-09 17:19   ` Samuel Holland
@ 2026-02-09 20:34   ` Raymond Mao
       [not found]   ` <CAMkFH19feRsme6Mfr1vQ7hSnr2yhFMivNpGkwfTT2uSV3ojnjg@mail.gmail.com>
  3 siblings, 0 replies; 26+ messages in thread
From: Raymond Mao @ 2026-02-09 20:34 UTC (permalink / raw)
  To: Anup Patel
  Cc: Atish Patra, Andrew Jones, Dave Patel, Samuel Holland, Anup Patel,
	opensbi, Anup Patel

Hi Anup,

On 2026-02-07 5:26 a.m., anup.patel at oss.qualcomm.com (Anup Patel) wrote:
> To handle external interrupts in M-mode, the sbi_irqchip framework
> must allow registering interrupt handlers from device drivers.
>
> Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> ---
>   include/sbi/sbi_irqchip.h |  56 ++++++++++-
>   lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
>   lib/utils/irqchip/aplic.c |   1 +
>   lib/utils/irqchip/imsic.c |   9 ++
>   lib/utils/irqchip/plic.c  |   1 +
>   5 files changed, 267 insertions(+), 2 deletions(-)
>
> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> index d2c47ae8..77b54110 100644
> --- a/include/sbi/sbi_irqchip.h
> +++ b/include/sbi/sbi_irqchip.h
> @@ -18,12 +18,21 @@ struct sbi_scratch;
>   
>   /** irqchip hardware device */
>   struct sbi_irqchip_device {
> -	/** Node in the list of irqchip devices */
> +	/** Node in the list of irqchip devices (private) */
>   	struct sbi_dlist node;
>   
> +	/** Internal data of all hardware interrupts of this irqchip (private) */
> +	struct sbi_irqchip_hwirq_data *hwirqs;
> +
> +	/** List of interrupt handlers */
> +	struct sbi_dlist handler_list;
> +
>   	/** Unique ID of this irqchip */
>   	u32 id;
>   
> +	/** Number of hardware IRQs of this irqchip */
> +	u32 num_hwirq;
> +
>   	/** Set of harts targetted by this irqchip */
>   	struct sbi_hartmask target_harts;
>   
> @@ -32,6 +41,21 @@ struct sbi_irqchip_device {
>   
>   	/** Process hardware interrupts from this irqchip */
>   	int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> +
> +	/** Setup a hardware interrupt of this irqchip */
> +	int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Cleanup a hardware interrupt of this irqchip */
> +	void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** End of hardware interrupt of this irqchip */
> +	void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);


If hwirq_eoi() is an equivalent of claim(), then hwirq should be a 
pointer of memory, since we need to read and return the IDC_TOPI_ID from 
CLAIMI.

Regards,
Raymond


> +
> +	/** Mask a hardware interrupt of this irqchip */
> +	void (*hwirq_mask)(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +	/** Unmask a hardware interrupt of this irqchip */
> +	void (*hwirq_unmask)(struct sbi_irqchip_device *chip, u32 hwirq);
>   };
>   
>   /**
> @@ -44,6 +68,36 @@ struct sbi_irqchip_device {
>    */
>   int sbi_irqchip_process(void);
>   
> +/**
> + * Process a hwirq of an irqchip device
> + *
> + * This function is called by irqchip drivers to handle hardware
> + * interrupts of the irqchip.
> + */
> +int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Unmask a hardware interrupt */
> +int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Mask a hardware interrupt */
> +int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Default raw hardware interrupt handler */
> +int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq);
> +
> +/** Set raw hardware interrupt handler */
> +int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
> +				int (*raw_hndl)(struct sbi_irqchip_device *, u32));
> +
> +/** Register a hardware interrupt handler */
> +int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
> +				 u32 first_hwirq, u32 num_hwirq,
> +				 int (*callback)(u32 hwirq, void *opaque), void *opaque);
> +
> +/** Unregister a hardware interrupt handler */
> +int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
> +				   u32 first_hwirq, u32 num_hwirq);
> +
>   /** Find an irqchip device based on unique ID */
>   struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id);
>   
> diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> index fb3357f3..736dde6c 100644
> --- a/lib/sbi/sbi_irqchip.c
> +++ b/lib/sbi/sbi_irqchip.c
> @@ -7,10 +7,35 @@
>    *   Anup Patel <apatel at ventanamicro.com>
>    */
>   
> +#include <sbi/sbi_heap.h>
>   #include <sbi/sbi_irqchip.h>
>   #include <sbi/sbi_list.h>
>   #include <sbi/sbi_platform.h>
>   
> +/** Internal irqchip hardware interrupt data */
> +struct sbi_irqchip_hwirq_data {
> +	/** raw hardware interrupt handler */
> +	int (*raw_handler)(struct sbi_irqchip_device *chip, u32 hwirq);
> +};
> +
> +/** Internal irqchip interrupt handler */
> +struct sbi_irqchip_handler {
> +	/** Node in the list of irqchip handlers (private) */
> +	struct sbi_dlist node;
> +
> +	/** First hardware IRQ handled by this handler */
> +	u32 first_hwirq;
> +
> +	/** Number of consecutive hardware IRQs handled by this handler */
> +	u32 num_hwirq;
> +
> +	/** Callback function of this handler */
> +	int (*callback)(u32 hwirq, void *priv);
> +
> +	/** Callback private data */
> +	void *priv;
> +};
> +
>   static SBI_LIST_HEAD(irqchip_list);
>   
>   int sbi_irqchip_process(void)
> @@ -31,6 +56,172 @@ int sbi_irqchip_process(void)
>   	return rc;
>   }
>   
> +int sbi_irqchip_process_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	struct sbi_irqchip_hwirq_data *data;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	data = &chip->hwirqs[hwirq];
> +	if (!data->raw_handler)
> +		return SBI_ENOENT;
> +
> +	return data->raw_handler(chip, hwirq);
> +}
> +
> +int sbi_irqchip_unmask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	if (chip->hwirq_unmask)
> +		chip->hwirq_unmask(chip, hwirq);
> +	return 0;
> +}
> +
> +int sbi_irqchip_mask_hwirq(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	if (chip->hwirq_mask)
> +		chip->hwirq_mask(chip, hwirq);
> +	return 0;
> +}
> +
> +static struct sbi_irqchip_handler *sbi_irqchip_find_handler(struct sbi_irqchip_device *chip,
> +							    u32 hwirq)
> +{
> +	struct sbi_irqchip_handler *h;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return NULL;
> +
> +	sbi_list_for_each_entry(h, &chip->handler_list, node) {
> +		if (h->first_hwirq <= hwirq && hwirq < (h->first_hwirq + h->num_hwirq))
> +			return h;
> +	}
> +
> +	return NULL;
> +}
> +
> +int sbi_irqchip_raw_handler_default(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	struct sbi_irqchip_handler *h;
> +	int rc;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	h = sbi_irqchip_find_handler(chip, hwirq);
> +	rc = h->callback(hwirq, h->priv);
> +
> +	if (chip->hwirq_eoi)
> +		chip->hwirq_eoi(chip, hwirq);
> +
> +	return rc;
> +}
> +
> +int sbi_irqchip_set_raw_handler(struct sbi_irqchip_device *chip, u32 hwirq,
> +				int (*raw_hndl)(struct sbi_irqchip_device *, u32))
> +{
> +	struct sbi_irqchip_hwirq_data *data;
> +
> +	if (!chip || chip->num_hwirq <= hwirq)
> +		return SBI_EINVAL;
> +
> +	data = &chip->hwirqs[hwirq];
> +	data->raw_handler = raw_hndl;
> +	return 0;
> +}
> +
> +int sbi_irqchip_register_handler(struct sbi_irqchip_device *chip,
> +				 u32 first_hwirq, u32 num_hwirq,
> +				 int (*callback)(u32 hwirq, void *opaque), void *priv)
> +{
> +	struct sbi_irqchip_handler *h;
> +	u32 i, j;
> +	int rc;
> +
> +	if (!chip || !num_hwirq || !callback)
> +		return SBI_EINVAL;
> +	if (chip->num_hwirq <= first_hwirq ||
> +	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
> +		return SBI_EBAD_RANGE;
> +
> +	h = sbi_irqchip_find_handler(chip, first_hwirq);
> +	if (h)
> +		return SBI_EALREADY;
> +	h = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
> +	if (h)
> +		return SBI_EALREADY;
> +
> +	h = sbi_zalloc(sizeof(*h));
> +	if (!h)
> +		return SBI_ENOMEM;
> +	h->first_hwirq = first_hwirq;
> +	h->num_hwirq = num_hwirq;
> +	h->callback = callback;
> +	h->priv = priv;
> +	sbi_list_add_tail(&h->node, &chip->handler_list);
> +
> +	if (chip->hwirq_setup) {
> +		for (i = 0; i < h->num_hwirq; i++) {
> +			rc = chip->hwirq_setup(chip, h->first_hwirq + i);
> +			if (rc) {
> +				if (chip->hwirq_cleanup) {
> +					for (j = 0; j < i; j++)
> +						chip->hwirq_cleanup(chip, h->first_hwirq + j);
> +				}
> +				sbi_list_del(&h->node);
> +				sbi_free(h);
> +				return rc;
> +			}
> +		}
> +	}
> +
> +	if (chip->hwirq_unmask) {
> +		for (i = 0; i < h->num_hwirq; i++)
> +			chip->hwirq_unmask(chip, h->first_hwirq + i);
> +	}
> +
> +	return 0;
> +}
> +
> +int sbi_irqchip_unregister_handler(struct sbi_irqchip_device *chip,
> +				   u32 first_hwirq, u32 num_hwirq)
> +{
> +	struct sbi_irqchip_handler *fh, *lh;
> +	u32 i;
> +
> +	if (!chip || !num_hwirq)
> +		return SBI_EINVAL;
> +	if (chip->num_hwirq <= first_hwirq ||
> +	    chip->num_hwirq <= (first_hwirq + num_hwirq - 1))
> +		return SBI_EBAD_RANGE;
> +
> +	fh = sbi_irqchip_find_handler(chip, first_hwirq);
> +	if (!fh || fh->first_hwirq != first_hwirq || fh->num_hwirq != num_hwirq)
> +		return SBI_ENODEV;
> +	lh = sbi_irqchip_find_handler(chip, first_hwirq + num_hwirq - 1);
> +	if (!lh || lh != fh)
> +		return SBI_ENODEV;
> +
> +	if (chip->hwirq_mask) {
> +		for (i = 0; i < fh->num_hwirq; i++)
> +			chip->hwirq_mask(chip, fh->first_hwirq + i);
> +	}
> +
> +	if (chip->hwirq_cleanup) {
> +		for (i = 0; i < fh->num_hwirq; i++)
> +			chip->hwirq_cleanup(chip, fh->first_hwirq + i);
> +	}
> +
> +	sbi_list_del(&fh->node);
> +	return 0;
> +}
> +
>   struct sbi_irqchip_device *sbi_irqchip_find_device(u32 id)
>   {
>   	struct sbi_irqchip_device *chip;
> @@ -47,8 +238,9 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>   {
>   	struct sbi_irqchip_device *c;
>   	struct sbi_hartmask hm;
> +	u32 i;
>   
> -	if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> +	if (!chip || !chip->num_hwirq || !sbi_hartmask_weight(&chip->target_harts))
>   		return SBI_EINVAL;
>   
>   	if (sbi_irqchip_find_device(chip->id))
> @@ -64,6 +256,14 @@ int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
>   		}
>   	}
>   
> +	chip->hwirqs = sbi_zalloc(sizeof(*chip->hwirqs) * chip->num_hwirq);
> +	if (!chip->hwirqs)
> +		return SBI_ENOMEM;
> +	for (i = 0; i < chip->num_hwirq; i++)
> +		sbi_irqchip_set_raw_handler(chip, i, sbi_irqchip_raw_handler_default);
> +
> +	SBI_INIT_LIST_HEAD(&chip->handler_list);
> +
>   	sbi_list_add_tail(&chip->node, &irqchip_list);
>   	return 0;
>   }
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> index d47a810b..ec69c82b 100644
> --- a/lib/utils/irqchip/aplic.c
> +++ b/lib/utils/irqchip/aplic.c
> @@ -307,6 +307,7 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
>   
>   	/* Register irqchip device */
>   	aplic->irqchip.id = aplic->unique_id;
> +	aplic->irqchip.num_hwirq = aplic->num_source + 1;
>   	rc = sbi_irqchip_add_device(&aplic->irqchip);
>   	if (rc)
>   		return rc;
> diff --git a/lib/utils/irqchip/imsic.c b/lib/utils/irqchip/imsic.c
> index 0f296c89..7559a069 100644
> --- a/lib/utils/irqchip/imsic.c
> +++ b/lib/utils/irqchip/imsic.c
> @@ -346,9 +346,17 @@ int imsic_data_check(struct imsic_data *imsic)
>   	return 0;
>   }
>   
> +static int imsic_hwirq_setup(struct sbi_irqchip_device *chip, u32 hwirq)
> +{
> +	if (!hwirq || hwirq == IMSIC_IPI_ID)
> +		return SBI_ENOTSUPP;
> +	return 0;
> +}
> +
>   static struct sbi_irqchip_device imsic_device = {
>   	.warm_init	= imsic_warm_irqchip_init,
>   	.process_hwirqs	= imsic_process_hwirqs,
> +	.hwirq_setup	= imsic_hwirq_setup,
>   };
>   
>   int imsic_cold_irqchip_init(struct imsic_data *imsic)
> @@ -392,6 +400,7 @@ int imsic_cold_irqchip_init(struct imsic_data *imsic)
>   
>   	/* Register irqchip device */
>   	imsic_device.id = imsic->unique_id;
> +	imsic_device.num_hwirq = imsic->num_ids + 1;
>   	sbi_hartmask_set_all(&imsic_device.target_harts);
>   	rc = sbi_irqchip_add_device(&imsic_device);
>   	if (rc)
> diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
> index 973f7c2a..2d721724 100644
> --- a/lib/utils/irqchip/plic.c
> +++ b/lib/utils/irqchip/plic.c
> @@ -281,6 +281,7 @@ int plic_cold_irqchip_init(struct plic_data *plic)
>   
>   	/* Register irqchip device */
>   	plic->irqchip.id = plic->unique_id;
> +	plic->irqchip.num_hwirq = plic->num_src + 1;
>   	plic->irqchip.warm_init = plic_warm_irqchip_init;
>   	return sbi_irqchip_add_device(&plic->irqchip);
>   }

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-09 20:25   ` Raymond Mao
@ 2026-02-10 16:09     ` Anup Patel
  2026-02-11 15:02       ` Raymond Mao
  0 siblings, 1 reply; 26+ messages in thread
From: Anup Patel @ 2026-02-10 16:09 UTC (permalink / raw)
  To: Raymond Mao
  Cc: Anup Patel, Atish Patra, Andrew Jones, Dave Patel, Samuel Holland,
	opensbi

On Tue, Feb 10, 2026 at 1:55 AM Raymond Mao <raymondmaoca@gmail.com> wrote:
>
> Hi Anup,
>
> On 2026-02-07 5:25 a.m., anup.patel at oss.qualcomm.com (Anup Patel) wrote:
> > It is possible to have platform where an irqchip device targets
> > a subset of harts and there are multiple irqchip devices to cover
> > all harts.
> >
> > To support this scenario:
> > 1) Add target_harts hartmask to struct sbi_irqchip_device which
> >     represents the set of harts targetted by the irqchip device
> > 2) Call warm_init() and irq_handle() callbacks of an irqchip device
> >     on a hart only if irqchip device targets that particular hart
> >
> > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > ---
> >   include/sbi/sbi_irqchip.h |  8 +++++--
> >   lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
> >   lib/utils/irqchip/aplic.c | 12 +++++++++-
> >   lib/utils/irqchip/imsic.c |  7 ++++--
> >   lib/utils/irqchip/plic.c  |  5 ++--
> >   5 files changed, 59 insertions(+), 21 deletions(-)
> >
> > diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> > index cda1e50f..c3ded271 100644
> > --- a/include/sbi/sbi_irqchip.h
> > +++ b/include/sbi/sbi_irqchip.h
> > @@ -10,6 +10,7 @@
> >   #ifndef __SBI_IRQCHIP_H__
> >   #define __SBI_IRQCHIP_H__
> >
> > +#include <sbi/sbi_hartmask.h>
> >   #include <sbi/sbi_list.h>
> >   #include <sbi/sbi_types.h>
> >
> > @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
> >       /** Node in the list of irqchip devices */
> >       struct sbi_dlist node;
> >
> > +     /** Set of harts targetted by this irqchip */
> > +     struct sbi_hartmask target_harts;
> > +
> >       /** Initialize per-hart state for the current hart */
> >       int (*warm_init)(struct sbi_irqchip_device *chip);
> >
> >       /** Process hardware interrupts from this irqchip */
> > -     int (*process_hwirqs)(void);
> > +     int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> >   };
> >
> >   /**
> > @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
> >   int sbi_irqchip_process(void);
> >
> >   /** Register an irqchip device to receive callbacks */
> > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> >
> >   /** Initialize interrupt controllers */
> >   int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> > diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> > index 3b970527..77ec05af 100644
> > --- a/lib/sbi/sbi_irqchip.c
> > +++ b/lib/sbi/sbi_irqchip.c
> > @@ -13,24 +13,44 @@
> >
> >   static SBI_LIST_HEAD(irqchip_list);
> >
> > -static int default_irqfn(void)
> > +int sbi_irqchip_process(void)
> >   {
> > -     return SBI_ENODEV;
> > -}
> > +     struct sbi_irqchip_device *chip;
> > +     int rc = SBI_ENODEV;
> >
> > -static int (*ext_irqfn)(void) = default_irqfn;
> > +     sbi_list_for_each_entry(chip, &irqchip_list, node) {
> > +             if (!chip->process_hwirqs)
> > +                     continue;
> > +             if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> > +                     continue;
> > +             rc = chip->process_hwirqs(chip);
> > +             if (rc)
> > +                     break;
> > +     }
> >
> > -int sbi_irqchip_process(void)
> > -{
> > -     return ext_irqfn();
> > +     return rc;
> >   }
> >
> > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> >   {
> > -     sbi_list_add_tail(&chip->node, &irqchip_list);
> > +     struct sbi_irqchip_device *c;
> > +     struct sbi_hartmask hm;
> > +
> > +     if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> > +             return SBI_EINVAL;
> > +
> > +     if (chip->process_hwirqs) {
> > +             sbi_list_for_each_entry(c, &irqchip_list, node) {
> > +                     if (!c->process_hwirqs)
> > +                             continue;
> > +                     sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> > +                     if (sbi_hartmask_weight(&hm))
> > +                             return SBI_EINVAL;
>
> I tested this by registering a 'process_hwirqs' hook, but
> 'sbi_hartmask_weight' returns errors.

This loop ensures that irqchips which directly connect
to external interrupt line of harts (aka irqchips which
implement process_hwirqs) don't have overlapping
target_harts.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
       [not found]   ` <CAMkFH19feRsme6Mfr1vQ7hSnr2yhFMivNpGkwfTT2uSV3ojnjg@mail.gmail.com>
@ 2026-02-10 16:39     ` Anup Patel
  2026-02-10 16:57       ` Raymond Mao
  0 siblings, 1 reply; 26+ messages in thread
From: Anup Patel @ 2026-02-10 16:39 UTC (permalink / raw)
  To: Ray Mao
  Cc: Anup Patel, Atish Patra, Andrew Jones, Dave Patel, Samuel Holland,
	opensbi

On Tue, Feb 10, 2026 at 12:29 AM Ray Mao <raymond.mao@riscstar.com> wrote:
>
> Hi Anup,
>
> On Sat, Feb 7, 2026 at 5:26 AM Anup Patel <anup.patel@oss.qualcomm.com> wrote:
>>
>> To handle external interrupts in M-mode, the sbi_irqchip framework
>> must allow registering interrupt handlers from device drivers.
>>
>> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
>> ---
>>  include/sbi/sbi_irqchip.h |  56 ++++++++++-
>>  lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
>>  lib/utils/irqchip/aplic.c |   1 +
>>  lib/utils/irqchip/imsic.c |   9 ++
>>  lib/utils/irqchip/plic.c  |   1 +
>>  5 files changed, 267 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
>> index d2c47ae8..77b54110 100644
>> --- a/include/sbi/sbi_irqchip.h
>> +++ b/include/sbi/sbi_irqchip.h
>> @@ -18,12 +18,21 @@ struct sbi_scratch;
>>
>>  /** irqchip hardware device */
>>  struct sbi_irqchip_device {
>> -       /** Node in the list of irqchip devices */
>> +       /** Node in the list of irqchip devices (private) */
>>         struct sbi_dlist node;
>>
>> +       /** Internal data of all hardware interrupts of this irqchip (private) */
>> +       struct sbi_irqchip_hwirq_data *hwirqs;
>> +
>> +       /** List of interrupt handlers */
>> +       struct sbi_dlist handler_list;
>> +
>>         /** Unique ID of this irqchip */
>>         u32 id;
>>
>> +       /** Number of hardware IRQs of this irqchip */
>> +       u32 num_hwirq;
>> +
>>         /** Set of harts targetted by this irqchip */
>>         struct sbi_hartmask target_harts;
>>
>> @@ -32,6 +41,21 @@ struct sbi_irqchip_device {
>>
>>         /** Process hardware interrupts from this irqchip */
>>         int (*process_hwirqs)(struct sbi_irqchip_device *chip);
>> +
>> +       /** Setup a hardware interrupt of this irqchip */
>> +       int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
>> +
>> +       /** Cleanup a hardware interrupt of this irqchip */
>> +       void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
>> +
>> +       /** End of hardware interrupt of this irqchip */
>> +       void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
>
>
> If hwirq_eoi() is an equivalent of claim(), then hwirq should be a pointer of memory, since we need to read and return the IDC_TOPI_ID from CLAIMI.
>

I think the external interrupt handling flow is not clear
to you but let me try to explain.

Whenever a hart receives external interrupt:

1) The sbi_trap_handler() is called by low-level handler
which in-turn calls sbi_irqchip_process()
2) The sbi_irqchip_process() will in-turn call
process_hwirqs() of appropriate driver
3) The process_hwirqs() in-case of APLIC
direct-mode will use IDC_TOPI_ID to determine
hwirq number and call sbi_irqchip_process_hwirq()
to handle it.

If we have nested irqchip such as IMSIC+APLIC
then process_hwirqs() will be implemented by IMSIC
whereas APLIC will use sbi_irqchip_request_handler()
to register callback for IMSIC hwirqs. This means
sbi_irqchip_process() will call process_hwirqs() of
IMSIC and IMSIC will call APLIC interrupt handler
via sbi_irqchip_process_hwirq() whereas the APLIC
interrupt handler will again call sbi_irqchip_process_hwirq().

In other words, we can support any irqchip topology.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
  2026-02-10 16:39     ` Anup Patel
@ 2026-02-10 16:57       ` Raymond Mao
  2026-02-11 17:30         ` Anup Patel
  0 siblings, 1 reply; 26+ messages in thread
From: Raymond Mao @ 2026-02-10 16:57 UTC (permalink / raw)
  To: Anup Patel
  Cc: Ray Mao, Anup Patel, Atish Patra, Andrew Jones, Dave Patel,
	Samuel Holland, opensbi

Hi Anup,

On Tue, Feb 10, 2026 at 11:40 AM Anup Patel <anup@brainfault.org> wrote:
>
> On Tue, Feb 10, 2026 at 12:29 AM Ray Mao <raymond.mao@riscstar.com> wrote:
> >
> > Hi Anup,
> >
> > On Sat, Feb 7, 2026 at 5:26 AM Anup Patel <anup.patel@oss.qualcomm.com> wrote:
> >>
> >> To handle external interrupts in M-mode, the sbi_irqchip framework
> >> must allow registering interrupt handlers from device drivers.
> >>
> >> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
> >> ---
> >>  include/sbi/sbi_irqchip.h |  56 ++++++++++-
> >>  lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
> >>  lib/utils/irqchip/aplic.c |   1 +
> >>  lib/utils/irqchip/imsic.c |   9 ++
> >>  lib/utils/irqchip/plic.c  |   1 +
> >>  5 files changed, 267 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> >> index d2c47ae8..77b54110 100644
> >> --- a/include/sbi/sbi_irqchip.h
> >> +++ b/include/sbi/sbi_irqchip.h
> >> @@ -18,12 +18,21 @@ struct sbi_scratch;
> >>
> >>  /** irqchip hardware device */
> >>  struct sbi_irqchip_device {
> >> -       /** Node in the list of irqchip devices */
> >> +       /** Node in the list of irqchip devices (private) */
> >>         struct sbi_dlist node;
> >>
> >> +       /** Internal data of all hardware interrupts of this irqchip (private) */
> >> +       struct sbi_irqchip_hwirq_data *hwirqs;
> >> +
> >> +       /** List of interrupt handlers */
> >> +       struct sbi_dlist handler_list;
> >> +
> >>         /** Unique ID of this irqchip */
> >>         u32 id;
> >>
> >> +       /** Number of hardware IRQs of this irqchip */
> >> +       u32 num_hwirq;
> >> +
> >>         /** Set of harts targetted by this irqchip */
> >>         struct sbi_hartmask target_harts;
> >>
> >> @@ -32,6 +41,21 @@ struct sbi_irqchip_device {
> >>
> >>         /** Process hardware interrupts from this irqchip */
> >>         int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> >> +
> >> +       /** Setup a hardware interrupt of this irqchip */
> >> +       int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
> >> +
> >> +       /** Cleanup a hardware interrupt of this irqchip */
> >> +       void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
> >> +
> >> +       /** End of hardware interrupt of this irqchip */
> >> +       void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
> >
> >
> > If hwirq_eoi() is an equivalent of claim(), then hwirq should be a pointer of memory, since we need to read and return the IDC_TOPI_ID from CLAIMI.
> >
>
> I think the external interrupt handling flow is not clear
> to you but let me try to explain.
>
> Whenever a hart receives external interrupt:
>
> 1) The sbi_trap_handler() is called by low-level handler
> which in-turn calls sbi_irqchip_process()
> 2) The sbi_irqchip_process() will in-turn call
> process_hwirqs() of appropriate driver
> 3) The process_hwirqs() in-case of APLIC
> direct-mode will use IDC_TOPI_ID to determine
> hwirq number and call sbi_irqchip_process_hwirq()
> to handle it.
>
> If we have nested irqchip such as IMSIC+APLIC
> then process_hwirqs() will be implemented by IMSIC
> whereas APLIC will use sbi_irqchip_request_handler()
> to register callback for IMSIC hwirqs. This means
> sbi_irqchip_process() will call process_hwirqs() of
> IMSIC and IMSIC will call APLIC interrupt handler
> via sbi_irqchip_process_hwirq() whereas the APLIC
> interrupt handler will again call sbi_irqchip_process_hwirq().
>
> In other words, we can support any irqchip topology.
>

I know this flow of interrupt handling, before I planned to read
TOPI_ID in the eoi hook, but yes, I can do this in process_hwirqs()
I almost rebased all my work in APLIC on top of your patch series. I
will push a new version to RISE Gitlab and ping you and Robin.

Raymond

> Regards,
> Anup
>
> --
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-10 16:09     ` Anup Patel
@ 2026-02-11 15:02       ` Raymond Mao
  2026-02-11 15:43         ` Anup Patel
  0 siblings, 1 reply; 26+ messages in thread
From: Raymond Mao @ 2026-02-11 15:02 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Atish Patra, Andrew Jones, Dave Patel, Samuel Holland,
	opensbi

Hi Anup,

On Tue, Feb 10, 2026 at 11:09 AM Anup Patel <anup@brainfault.org> wrote:
>
> On Tue, Feb 10, 2026 at 1:55 AM Raymond Mao <raymondmaoca@gmail.com> wrote:
> >
> > Hi Anup,
> >
> > On 2026-02-07 5:25 a.m., anup.patel at oss.qualcomm.com (Anup Patel) wrote:
> > > It is possible to have platform where an irqchip device targets
> > > a subset of harts and there are multiple irqchip devices to cover
> > > all harts.
> > >
> > > To support this scenario:
> > > 1) Add target_harts hartmask to struct sbi_irqchip_device which
> > >     represents the set of harts targetted by the irqchip device
> > > 2) Call warm_init() and irq_handle() callbacks of an irqchip device
> > >     on a hart only if irqchip device targets that particular hart
> > >
> > > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > > ---
> > >   include/sbi/sbi_irqchip.h |  8 +++++--
> > >   lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
> > >   lib/utils/irqchip/aplic.c | 12 +++++++++-
> > >   lib/utils/irqchip/imsic.c |  7 ++++--
> > >   lib/utils/irqchip/plic.c  |  5 ++--
> > >   5 files changed, 59 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> > > index cda1e50f..c3ded271 100644
> > > --- a/include/sbi/sbi_irqchip.h
> > > +++ b/include/sbi/sbi_irqchip.h
> > > @@ -10,6 +10,7 @@
> > >   #ifndef __SBI_IRQCHIP_H__
> > >   #define __SBI_IRQCHIP_H__
> > >
> > > +#include <sbi/sbi_hartmask.h>
> > >   #include <sbi/sbi_list.h>
> > >   #include <sbi/sbi_types.h>
> > >
> > > @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
> > >       /** Node in the list of irqchip devices */
> > >       struct sbi_dlist node;
> > >
> > > +     /** Set of harts targetted by this irqchip */
> > > +     struct sbi_hartmask target_harts;
> > > +
> > >       /** Initialize per-hart state for the current hart */
> > >       int (*warm_init)(struct sbi_irqchip_device *chip);
> > >
> > >       /** Process hardware interrupts from this irqchip */
> > > -     int (*process_hwirqs)(void);
> > > +     int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> > >   };
> > >
> > >   /**
> > > @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
> > >   int sbi_irqchip_process(void);
> > >
> > >   /** Register an irqchip device to receive callbacks */
> > > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > >
> > >   /** Initialize interrupt controllers */
> > >   int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> > > diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> > > index 3b970527..77ec05af 100644
> > > --- a/lib/sbi/sbi_irqchip.c
> > > +++ b/lib/sbi/sbi_irqchip.c
> > > @@ -13,24 +13,44 @@
> > >
> > >   static SBI_LIST_HEAD(irqchip_list);
> > >
> > > -static int default_irqfn(void)
> > > +int sbi_irqchip_process(void)
> > >   {
> > > -     return SBI_ENODEV;
> > > -}
> > > +     struct sbi_irqchip_device *chip;
> > > +     int rc = SBI_ENODEV;
> > >
> > > -static int (*ext_irqfn)(void) = default_irqfn;
> > > +     sbi_list_for_each_entry(chip, &irqchip_list, node) {
> > > +             if (!chip->process_hwirqs)
> > > +                     continue;
> > > +             if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> > > +                     continue;
> > > +             rc = chip->process_hwirqs(chip);
> > > +             if (rc)
> > > +                     break;
> > > +     }
> > >
> > > -int sbi_irqchip_process(void)
> > > -{
> > > -     return ext_irqfn();
> > > +     return rc;
> > >   }
> > >
> > > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > >   {
> > > -     sbi_list_add_tail(&chip->node, &irqchip_list);
> > > +     struct sbi_irqchip_device *c;
> > > +     struct sbi_hartmask hm;
> > > +
> > > +     if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> > > +             return SBI_EINVAL;
> > > +
> > > +     if (chip->process_hwirqs) {
> > > +             sbi_list_for_each_entry(c, &irqchip_list, node) {
> > > +                     if (!c->process_hwirqs)
> > > +                             continue;
> > > +                     sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> > > +                     if (sbi_hartmask_weight(&hm))
> > > +                             return SBI_EINVAL;
> >
> > I tested this by registering a 'process_hwirqs' hook, but
> > 'sbi_hartmask_weight' returns errors.
>
> This loop ensures that irqchips which directly connect
> to external interrupt line of harts (aka irqchips which
> implement process_hwirqs) don't have overlapping
> target_harts.
>

If my understanding is correct, this means only single process_hwirqs
can be registered for a target hart - if IMSIC registered it then it
rejects when APLIC tries to register its own process_hwirqs.
But according to our use case, each irqchip should be allowed to
register its own operation hooks, including process_hwirqs.
Then the IMSIC's process_hwirqs handles MSI, while the APLIC's
process_hwirqs handles wired ext interrupt, they don't overlap each
other.
I would suggest allowing multiple process_hwirqs hooks for one target hart.

Regards,
Raymond


> Regards,
> Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-11 15:02       ` Raymond Mao
@ 2026-02-11 15:43         ` Anup Patel
  2026-02-11 17:49           ` Raymond Mao
  0 siblings, 1 reply; 26+ messages in thread
From: Anup Patel @ 2026-02-11 15:43 UTC (permalink / raw)
  To: Raymond Mao
  Cc: Anup Patel, Atish Patra, Andrew Jones, Dave Patel, Samuel Holland,
	opensbi

On Wed, Feb 11, 2026 at 8:32 PM Raymond Mao <raymondmaoca@gmail.com> wrote:
>
> Hi Anup,
>
> On Tue, Feb 10, 2026 at 11:09 AM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Tue, Feb 10, 2026 at 1:55 AM Raymond Mao <raymondmaoca@gmail.com> wrote:
> > >
> > > Hi Anup,
> > >
> > > On 2026-02-07 5:25 a.m., anup.patel at oss.qualcomm.com (Anup Patel) wrote:
> > > > It is possible to have platform where an irqchip device targets
> > > > a subset of harts and there are multiple irqchip devices to cover
> > > > all harts.
> > > >
> > > > To support this scenario:
> > > > 1) Add target_harts hartmask to struct sbi_irqchip_device which
> > > >     represents the set of harts targetted by the irqchip device
> > > > 2) Call warm_init() and irq_handle() callbacks of an irqchip device
> > > >     on a hart only if irqchip device targets that particular hart
> > > >
> > > > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > > > ---
> > > >   include/sbi/sbi_irqchip.h |  8 +++++--
> > > >   lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
> > > >   lib/utils/irqchip/aplic.c | 12 +++++++++-
> > > >   lib/utils/irqchip/imsic.c |  7 ++++--
> > > >   lib/utils/irqchip/plic.c  |  5 ++--
> > > >   5 files changed, 59 insertions(+), 21 deletions(-)
> > > >
> > > > diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> > > > index cda1e50f..c3ded271 100644
> > > > --- a/include/sbi/sbi_irqchip.h
> > > > +++ b/include/sbi/sbi_irqchip.h
> > > > @@ -10,6 +10,7 @@
> > > >   #ifndef __SBI_IRQCHIP_H__
> > > >   #define __SBI_IRQCHIP_H__
> > > >
> > > > +#include <sbi/sbi_hartmask.h>
> > > >   #include <sbi/sbi_list.h>
> > > >   #include <sbi/sbi_types.h>
> > > >
> > > > @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
> > > >       /** Node in the list of irqchip devices */
> > > >       struct sbi_dlist node;
> > > >
> > > > +     /** Set of harts targetted by this irqchip */
> > > > +     struct sbi_hartmask target_harts;
> > > > +
> > > >       /** Initialize per-hart state for the current hart */
> > > >       int (*warm_init)(struct sbi_irqchip_device *chip);
> > > >
> > > >       /** Process hardware interrupts from this irqchip */
> > > > -     int (*process_hwirqs)(void);
> > > > +     int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> > > >   };
> > > >
> > > >   /**
> > > > @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
> > > >   int sbi_irqchip_process(void);
> > > >
> > > >   /** Register an irqchip device to receive callbacks */
> > > > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > > > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > > >
> > > >   /** Initialize interrupt controllers */
> > > >   int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> > > > diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> > > > index 3b970527..77ec05af 100644
> > > > --- a/lib/sbi/sbi_irqchip.c
> > > > +++ b/lib/sbi/sbi_irqchip.c
> > > > @@ -13,24 +13,44 @@
> > > >
> > > >   static SBI_LIST_HEAD(irqchip_list);
> > > >
> > > > -static int default_irqfn(void)
> > > > +int sbi_irqchip_process(void)
> > > >   {
> > > > -     return SBI_ENODEV;
> > > > -}
> > > > +     struct sbi_irqchip_device *chip;
> > > > +     int rc = SBI_ENODEV;
> > > >
> > > > -static int (*ext_irqfn)(void) = default_irqfn;
> > > > +     sbi_list_for_each_entry(chip, &irqchip_list, node) {
> > > > +             if (!chip->process_hwirqs)
> > > > +                     continue;
> > > > +             if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> > > > +                     continue;
> > > > +             rc = chip->process_hwirqs(chip);
> > > > +             if (rc)
> > > > +                     break;
> > > > +     }
> > > >
> > > > -int sbi_irqchip_process(void)
> > > > -{
> > > > -     return ext_irqfn();
> > > > +     return rc;
> > > >   }
> > > >
> > > > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > > > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > > >   {
> > > > -     sbi_list_add_tail(&chip->node, &irqchip_list);
> > > > +     struct sbi_irqchip_device *c;
> > > > +     struct sbi_hartmask hm;
> > > > +
> > > > +     if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> > > > +             return SBI_EINVAL;
> > > > +
> > > > +     if (chip->process_hwirqs) {
> > > > +             sbi_list_for_each_entry(c, &irqchip_list, node) {
> > > > +                     if (!c->process_hwirqs)
> > > > +                             continue;
> > > > +                     sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> > > > +                     if (sbi_hartmask_weight(&hm))
> > > > +                             return SBI_EINVAL;
> > >
> > > I tested this by registering a 'process_hwirqs' hook, but
> > > 'sbi_hartmask_weight' returns errors.
> >
> > This loop ensures that irqchips which directly connect
> > to external interrupt line of harts (aka irqchips which
> > implement process_hwirqs) don't have overlapping
> > target_harts.
> >
>
> If my understanding is correct, this means only single process_hwirqs
> can be registered for a target hart - if IMSIC registered it then it
> rejects when APLIC tries to register its own process_hwirqs.

That's right.

APLIC must register its own process_hwirqs() only when it is
in DIRECT mode.

On platforms with IMSIC+APLIC, the APLIC will be in MSI mode
so in this case APLIC must not register process_hwirqs().

> But according to our use case, each irqchip should be allowed to
> register its own operation hooks, including process_hwirqs.
> Then the IMSIC's process_hwirqs handles MSI, while the APLIC's
> process_hwirqs handles wired ext interrupt, they don't overlap each
> other.
> I would suggest allowing multiple process_hwirqs hooks for one target hart.

Your understanding is not correct. Please see the above comment.

In your use-case, you have APLIC in DIRECT mode without any
IMSIC.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers
  2026-02-10 16:57       ` Raymond Mao
@ 2026-02-11 17:30         ` Anup Patel
  0 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-11 17:30 UTC (permalink / raw)
  To: Raymond Mao
  Cc: Ray Mao, Anup Patel, Atish Patra, Andrew Jones, Dave Patel,
	Samuel Holland, opensbi

On Tue, Feb 10, 2026 at 10:28 PM Raymond Mao <raymondmaoca@gmail.com> wrote:
>
> Hi Anup,
>
> On Tue, Feb 10, 2026 at 11:40 AM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Tue, Feb 10, 2026 at 12:29 AM Ray Mao <raymond.mao@riscstar.com> wrote:
> > >
> > > Hi Anup,
> > >
> > > On Sat, Feb 7, 2026 at 5:26 AM Anup Patel <anup.patel@oss.qualcomm.com> wrote:
> > >>
> > >> To handle external interrupts in M-mode, the sbi_irqchip framework
> > >> must allow registering interrupt handlers from device drivers.
> > >>
> > >> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
> > >> ---
> > >>  include/sbi/sbi_irqchip.h |  56 ++++++++++-
> > >>  lib/sbi/sbi_irqchip.c     | 202 +++++++++++++++++++++++++++++++++++++-
> > >>  lib/utils/irqchip/aplic.c |   1 +
> > >>  lib/utils/irqchip/imsic.c |   9 ++
> > >>  lib/utils/irqchip/plic.c  |   1 +
> > >>  5 files changed, 267 insertions(+), 2 deletions(-)
> > >>
> > >> diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> > >> index d2c47ae8..77b54110 100644
> > >> --- a/include/sbi/sbi_irqchip.h
> > >> +++ b/include/sbi/sbi_irqchip.h
> > >> @@ -18,12 +18,21 @@ struct sbi_scratch;
> > >>
> > >>  /** irqchip hardware device */
> > >>  struct sbi_irqchip_device {
> > >> -       /** Node in the list of irqchip devices */
> > >> +       /** Node in the list of irqchip devices (private) */
> > >>         struct sbi_dlist node;
> > >>
> > >> +       /** Internal data of all hardware interrupts of this irqchip (private) */
> > >> +       struct sbi_irqchip_hwirq_data *hwirqs;
> > >> +
> > >> +       /** List of interrupt handlers */
> > >> +       struct sbi_dlist handler_list;
> > >> +
> > >>         /** Unique ID of this irqchip */
> > >>         u32 id;
> > >>
> > >> +       /** Number of hardware IRQs of this irqchip */
> > >> +       u32 num_hwirq;
> > >> +
> > >>         /** Set of harts targetted by this irqchip */
> > >>         struct sbi_hartmask target_harts;
> > >>
> > >> @@ -32,6 +41,21 @@ struct sbi_irqchip_device {
> > >>
> > >>         /** Process hardware interrupts from this irqchip */
> > >>         int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> > >> +
> > >> +       /** Setup a hardware interrupt of this irqchip */
> > >> +       int (*hwirq_setup)(struct sbi_irqchip_device *chip, u32 hwirq);
> > >> +
> > >> +       /** Cleanup a hardware interrupt of this irqchip */
> > >> +       void (*hwirq_cleanup)(struct sbi_irqchip_device *chip, u32 hwirq);
> > >> +
> > >> +       /** End of hardware interrupt of this irqchip */
> > >> +       void (*hwirq_eoi)(struct sbi_irqchip_device *chip, u32 hwirq);
> > >
> > >
> > > If hwirq_eoi() is an equivalent of claim(), then hwirq should be a pointer of memory, since we need to read and return the IDC_TOPI_ID from CLAIMI.
> > >
> >
> > I think the external interrupt handling flow is not clear
> > to you but let me try to explain.
> >
> > Whenever a hart receives external interrupt:
> >
> > 1) The sbi_trap_handler() is called by low-level handler
> > which in-turn calls sbi_irqchip_process()
> > 2) The sbi_irqchip_process() will in-turn call
> > process_hwirqs() of appropriate driver
> > 3) The process_hwirqs() in-case of APLIC
> > direct-mode will use IDC_TOPI_ID to determine
> > hwirq number and call sbi_irqchip_process_hwirq()
> > to handle it.
> >
> > If we have nested irqchip such as IMSIC+APLIC
> > then process_hwirqs() will be implemented by IMSIC
> > whereas APLIC will use sbi_irqchip_request_handler()
> > to register callback for IMSIC hwirqs. This means
> > sbi_irqchip_process() will call process_hwirqs() of
> > IMSIC and IMSIC will call APLIC interrupt handler
> > via sbi_irqchip_process_hwirq() whereas the APLIC
> > interrupt handler will again call sbi_irqchip_process_hwirq().
> >
> > In other words, we can support any irqchip topology.
> >
>
> I know this flow of interrupt handling, before I planned to read
> TOPI_ID in the eoi hook, but yes, I can do this in process_hwirqs()
> I almost rebased all my work in APLIC on top of your patch series. I
> will push a new version to RISE Gitlab and ping you and Robin.

Thanks Raymond, the intention of this series was to give
you a good starting point to build upon. I will send-out v2
pretty soon addressing comments from Drew and Samuel.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-11 15:43         ` Anup Patel
@ 2026-02-11 17:49           ` Raymond Mao
  0 siblings, 0 replies; 26+ messages in thread
From: Raymond Mao @ 2026-02-11 17:49 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Atish Patra, Andrew Jones, Dave Patel, Samuel Holland,
	opensbi

Hi Anup,

On Wed, Feb 11, 2026 at 10:43 AM Anup Patel <anup@brainfault.org> wrote:
>
> On Wed, Feb 11, 2026 at 8:32 PM Raymond Mao <raymondmaoca@gmail.com> wrote:
> >
> > Hi Anup,
> >
> > On Tue, Feb 10, 2026 at 11:09 AM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Tue, Feb 10, 2026 at 1:55 AM Raymond Mao <raymondmaoca@gmail.com> wrote:
> > > >
> > > > Hi Anup,
> > > >
> > > > On 2026-02-07 5:25 a.m., anup.patel at oss.qualcomm.com (Anup Patel) wrote:
> > > > > It is possible to have platform where an irqchip device targets
> > > > > a subset of harts and there are multiple irqchip devices to cover
> > > > > all harts.
> > > > >
> > > > > To support this scenario:
> > > > > 1) Add target_harts hartmask to struct sbi_irqchip_device which
> > > > >     represents the set of harts targetted by the irqchip device
> > > > > 2) Call warm_init() and irq_handle() callbacks of an irqchip device
> > > > >     on a hart only if irqchip device targets that particular hart
> > > > >
> > > > > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > > > > ---
> > > > >   include/sbi/sbi_irqchip.h |  8 +++++--
> > > > >   lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
> > > > >   lib/utils/irqchip/aplic.c | 12 +++++++++-
> > > > >   lib/utils/irqchip/imsic.c |  7 ++++--
> > > > >   lib/utils/irqchip/plic.c  |  5 ++--
> > > > >   5 files changed, 59 insertions(+), 21 deletions(-)
> > > > >
> > > > > diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> > > > > index cda1e50f..c3ded271 100644
> > > > > --- a/include/sbi/sbi_irqchip.h
> > > > > +++ b/include/sbi/sbi_irqchip.h
> > > > > @@ -10,6 +10,7 @@
> > > > >   #ifndef __SBI_IRQCHIP_H__
> > > > >   #define __SBI_IRQCHIP_H__
> > > > >
> > > > > +#include <sbi/sbi_hartmask.h>
> > > > >   #include <sbi/sbi_list.h>
> > > > >   #include <sbi/sbi_types.h>
> > > > >
> > > > > @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
> > > > >       /** Node in the list of irqchip devices */
> > > > >       struct sbi_dlist node;
> > > > >
> > > > > +     /** Set of harts targetted by this irqchip */
> > > > > +     struct sbi_hartmask target_harts;
> > > > > +
> > > > >       /** Initialize per-hart state for the current hart */
> > > > >       int (*warm_init)(struct sbi_irqchip_device *chip);
> > > > >
> > > > >       /** Process hardware interrupts from this irqchip */
> > > > > -     int (*process_hwirqs)(void);
> > > > > +     int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> > > > >   };
> > > > >
> > > > >   /**
> > > > > @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
> > > > >   int sbi_irqchip_process(void);
> > > > >
> > > > >   /** Register an irqchip device to receive callbacks */
> > > > > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > > > > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > > > >
> > > > >   /** Initialize interrupt controllers */
> > > > >   int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> > > > > diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> > > > > index 3b970527..77ec05af 100644
> > > > > --- a/lib/sbi/sbi_irqchip.c
> > > > > +++ b/lib/sbi/sbi_irqchip.c
> > > > > @@ -13,24 +13,44 @@
> > > > >
> > > > >   static SBI_LIST_HEAD(irqchip_list);
> > > > >
> > > > > -static int default_irqfn(void)
> > > > > +int sbi_irqchip_process(void)
> > > > >   {
> > > > > -     return SBI_ENODEV;
> > > > > -}
> > > > > +     struct sbi_irqchip_device *chip;
> > > > > +     int rc = SBI_ENODEV;
> > > > >
> > > > > -static int (*ext_irqfn)(void) = default_irqfn;
> > > > > +     sbi_list_for_each_entry(chip, &irqchip_list, node) {
> > > > > +             if (!chip->process_hwirqs)
> > > > > +                     continue;
> > > > > +             if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> > > > > +                     continue;
> > > > > +             rc = chip->process_hwirqs(chip);
> > > > > +             if (rc)
> > > > > +                     break;
> > > > > +     }
> > > > >
> > > > > -int sbi_irqchip_process(void)
> > > > > -{
> > > > > -     return ext_irqfn();
> > > > > +     return rc;
> > > > >   }
> > > > >
> > > > > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > > > > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > > > >   {
> > > > > -     sbi_list_add_tail(&chip->node, &irqchip_list);
> > > > > +     struct sbi_irqchip_device *c;
> > > > > +     struct sbi_hartmask hm;
> > > > > +
> > > > > +     if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> > > > > +             return SBI_EINVAL;
> > > > > +
> > > > > +     if (chip->process_hwirqs) {
> > > > > +             sbi_list_for_each_entry(c, &irqchip_list, node) {
> > > > > +                     if (!c->process_hwirqs)
> > > > > +                             continue;
> > > > > +                     sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> > > > > +                     if (sbi_hartmask_weight(&hm))
> > > > > +                             return SBI_EINVAL;
> > > >
> > > > I tested this by registering a 'process_hwirqs' hook, but
> > > > 'sbi_hartmask_weight' returns errors.
> > >
> > > This loop ensures that irqchips which directly connect
> > > to external interrupt line of harts (aka irqchips which
> > > implement process_hwirqs) don't have overlapping
> > > target_harts.
> > >
> >
> > If my understanding is correct, this means only single process_hwirqs
> > can be registered for a target hart - if IMSIC registered it then it
> > rejects when APLIC tries to register its own process_hwirqs.
>
> That's right.
>
> APLIC must register its own process_hwirqs() only when it is
> in DIRECT mode.
>
> On platforms with IMSIC+APLIC, the APLIC will be in MSI mode
> so in this case APLIC must not register process_hwirqs().
>
> > But according to our use case, each irqchip should be allowed to
> > register its own operation hooks, including process_hwirqs.
> > Then the IMSIC's process_hwirqs handles MSI, while the APLIC's
> > process_hwirqs handles wired ext interrupt, they don't overlap each
> > other.
> > I would suggest allowing multiple process_hwirqs hooks for one target hart.
>
> Your understanding is not correct. Please see the above comment.
>
> In your use-case, you have APLIC in DIRECT mode without any
> IMSIC.
>

In APLIC, I can add a condition:
```
if (!aplic->has_msicfg_mmode && !aplic->has_msicfg_smode)
aplic->irqchip.process_hwirqs = aplic_process_hwirqs,
```
to make sure process_hwirqs is registered when there are no IMSIC configs.

But in IMSIC side, we need to check the existence of an IMISC node
before registering process_hwirqs.
For example, when running QEMU with `-M virt,aia=aplic`, there is no
IMSIC node and it should skip registering process_hwirqs, but I think
this part is missing at the moment.

Regards,
Raymond


> Regards,
> Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data
  2026-02-09 16:50   ` Andrew Jones
@ 2026-02-13  3:57     ` Anup Patel
  0 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-13  3:57 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Atish Patra, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi

On Mon, Feb 9, 2026 at 10:20 PM Andrew Jones
<andrew.jones@oss.qualcomm.com> wrote:
>
> On Sat, Feb 07, 2026 at 03:55:58PM +0530, Anup Patel wrote:
> > A platform can have multiple APLICs in direct-mode targetting
> > different subset of harts. Add APLIC ID to hartindex map in
> > struct aplic_data to capture the set of harts targed by a
>
> /targed/targeted/

Okay, I will update.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-09 16:50   ` Andrew Jones
@ 2026-02-13  3:59     ` Anup Patel
  0 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-13  3:59 UTC (permalink / raw)
  To: Andrew Jones
  Cc: Atish Patra, Raymond Mao, Dave Patel, Samuel Holland, Anup Patel,
	opensbi

On Mon, Feb 9, 2026 at 10:20 PM Andrew Jones
<andrew.jones@oss.qualcomm.com> wrote:
>
> On Sat, Feb 07, 2026 at 03:55:59PM +0530, Anup Patel wrote:
> > It is possible to have platform where an irqchip device targets
> > a subset of harts and there are multiple irqchip devices to cover
> > all harts.
> >
> > To support this scenario:
> > 1) Add target_harts hartmask to struct sbi_irqchip_device which
> >    represents the set of harts targetted by the irqchip device
> > 2) Call warm_init() and irq_handle() callbacks of an irqchip device
>
> /irq_handle/process_hwirqs/
>

Okay, I will update.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts
  2026-02-09 17:03   ` Samuel Holland
@ 2026-02-13  4:01     ` Anup Patel
  0 siblings, 0 replies; 26+ messages in thread
From: Anup Patel @ 2026-02-13  4:01 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Atish Patra, Andrew Jones, Raymond Mao, Dave Patel, Anup Patel,
	opensbi

On Mon, Feb 9, 2026 at 10:33 PM Samuel Holland
<samuel.holland@sifive.com> wrote:
>
> Hi Anup,
>
> On 2026-02-07 4:25 AM, Anup Patel wrote:
> > It is possible to have platform where an irqchip device targets
> > a subset of harts and there are multiple irqchip devices to cover
> > all harts.
> >
> > To support this scenario:
> > 1) Add target_harts hartmask to struct sbi_irqchip_device which
> >    represents the set of harts targetted by the irqchip device
> > 2) Call warm_init() and irq_handle() callbacks of an irqchip device
> >    on a hart only if irqchip device targets that particular hart
> >
> > Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
> > ---
> >  include/sbi/sbi_irqchip.h |  8 +++++--
> >  lib/sbi/sbi_irqchip.c     | 48 ++++++++++++++++++++++++++++-----------
> >  lib/utils/irqchip/aplic.c | 12 +++++++++-
> >  lib/utils/irqchip/imsic.c |  7 ++++--
> >  lib/utils/irqchip/plic.c  |  5 ++--
> >  5 files changed, 59 insertions(+), 21 deletions(-)
> >
> > diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h
> > index cda1e50f..c3ded271 100644
> > --- a/include/sbi/sbi_irqchip.h
> > +++ b/include/sbi/sbi_irqchip.h
> > @@ -10,6 +10,7 @@
> >  #ifndef __SBI_IRQCHIP_H__
> >  #define __SBI_IRQCHIP_H__
> >
> > +#include <sbi/sbi_hartmask.h>
> >  #include <sbi/sbi_list.h>
> >  #include <sbi/sbi_types.h>
> >
> > @@ -20,11 +21,14 @@ struct sbi_irqchip_device {
> >       /** Node in the list of irqchip devices */
> >       struct sbi_dlist node;
> >
> > +     /** Set of harts targetted by this irqchip */
> > +     struct sbi_hartmask target_harts;
> > +
> >       /** Initialize per-hart state for the current hart */
> >       int (*warm_init)(struct sbi_irqchip_device *chip);
> >
> >       /** Process hardware interrupts from this irqchip */
> > -     int (*process_hwirqs)(void);
> > +     int (*process_hwirqs)(struct sbi_irqchip_device *chip);
> >  };
> >
> >  /**
> > @@ -38,7 +42,7 @@ struct sbi_irqchip_device {
> >  int sbi_irqchip_process(void);
> >
> >  /** Register an irqchip device to receive callbacks */
> > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip);
> >
> >  /** Initialize interrupt controllers */
> >  int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot);
> > diff --git a/lib/sbi/sbi_irqchip.c b/lib/sbi/sbi_irqchip.c
> > index 3b970527..77ec05af 100644
> > --- a/lib/sbi/sbi_irqchip.c
> > +++ b/lib/sbi/sbi_irqchip.c
> > @@ -13,24 +13,44 @@
> >
> >  static SBI_LIST_HEAD(irqchip_list);
> >
> > -static int default_irqfn(void)
> > +int sbi_irqchip_process(void)
> >  {
> > -     return SBI_ENODEV;
> > -}
> > +     struct sbi_irqchip_device *chip;
> > +     int rc = SBI_ENODEV;
> >
> > -static int (*ext_irqfn)(void) = default_irqfn;
> > +     sbi_list_for_each_entry(chip, &irqchip_list, node) {
> > +             if (!chip->process_hwirqs)
> > +                     continue;
> > +             if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> > +                     continue;
> > +             rc = chip->process_hwirqs(chip);
> > +             if (rc)
> > +                     break;
>
> This is a hot path (used for IPIs already), so I would recommend using a
> per-hart pointer to the top-level chip that gets set in
> sbi_irqchip_add_device(), so there is no lookup needed here.

Good suggestion. I will update in the next revision.

>
> > +     }
> >
> > -int sbi_irqchip_process(void)
> > -{
> > -     return ext_irqfn();
> > +     return rc;
> >  }
> >
> > -void sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> > +int sbi_irqchip_add_device(struct sbi_irqchip_device *chip)
> >  {
> > -     sbi_list_add_tail(&chip->node, &irqchip_list);
> > +     struct sbi_irqchip_device *c;
> > +     struct sbi_hartmask hm;
> > +
> > +     if (!chip || !sbi_hartmask_weight(&chip->target_harts))
> > +             return SBI_EINVAL;
> > +
> > +     if (chip->process_hwirqs) {
> > +             sbi_list_for_each_entry(c, &irqchip_list, node) {
> > +                     if (!c->process_hwirqs)
> > +                             continue;
> > +                     sbi_hartmask_and(&hm, &c->target_harts, &chip->target_harts);
> > +                     if (sbi_hartmask_weight(&hm))
> > +                             return SBI_EINVAL;
> > +             }
> > +     }
> >
> > -     if (chip->process_hwirqs)
> > -             ext_irqfn = chip->process_hwirqs;
> > +     sbi_list_add_tail(&chip->node, &irqchip_list);
> > +     return 0;
> >  }
> >
> >  int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
> > @@ -48,12 +68,14 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot)
> >       sbi_list_for_each_entry(chip, &irqchip_list, node) {
> >               if (!chip->warm_init)
> >                       continue;
> > +             if (!sbi_hartmask_test_hartindex(current_hartindex(), &chip->target_harts))
> > +                     continue;
> >               rc = chip->warm_init(chip);
> >               if (rc)
> >                       return rc;
> >       }
> >
> > -     if (ext_irqfn != default_irqfn)
> > +     if (!sbi_list_empty(&irqchip_list))
> >               csr_set(CSR_MIE, MIP_MEIP);
>
> This should only enable interrupts if there is an irqchip targeting the current
> hart.

Yes, good catch. I will update in the next revision.

Regards,
Anup

-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2026-02-13  4:01 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-07 10:25 [PATCH 0/8] Extend irqchip framework for M-mode interrupts Anup Patel
2026-02-07 10:25 ` [PATCH 1/8] lib: sbi_irqchip: Use chip as variable name for irqchip device Anup Patel
2026-02-07 10:25 ` [PATCH 2/8] lib: sbi_irqchip: Rename irq_handle() callback to process_hwirqs() Anup Patel
2026-02-07 10:25 ` [PATCH 3/8] lib: utils/irqchip: Fix context_map init in irqchip_plic_update_context_map() Anup Patel
2026-02-07 10:25 ` [PATCH 4/8] lib: utils/irqchip: Add IDC to hartindex map in struct aplic_data Anup Patel
2026-02-09 16:50   ` Andrew Jones
2026-02-13  3:57     ` Anup Patel
2026-02-07 10:25 ` [PATCH 5/8] lib: sbi_irqchip: Support irqchip device targetting subset of harts Anup Patel
2026-02-09 16:50   ` Andrew Jones
2026-02-13  3:59     ` Anup Patel
2026-02-09 17:03   ` Samuel Holland
2026-02-13  4:01     ` Anup Patel
2026-02-09 20:25   ` Raymond Mao
2026-02-10 16:09     ` Anup Patel
2026-02-11 15:02       ` Raymond Mao
2026-02-11 15:43         ` Anup Patel
2026-02-11 17:49           ` Raymond Mao
2026-02-07 10:26 ` [PATCH 6/8] lib: utils/irqchip: Add unique_id to plic, aplic, and imsic data Anup Patel
2026-02-07 10:26 ` [PATCH 7/8] lib: sbi_irqchip: Associate 32-bit unique ID for each irqchip device Anup Patel
2026-02-07 10:26 ` [PATCH 8/8] lib: sbi_irqchip: Allow registering interrupt handlers Anup Patel
2026-02-09 16:52   ` Andrew Jones
2026-02-09 17:19   ` Samuel Holland
2026-02-09 20:34   ` Raymond Mao
     [not found]   ` <CAMkFH19feRsme6Mfr1vQ7hSnr2yhFMivNpGkwfTT2uSV3ojnjg@mail.gmail.com>
2026-02-10 16:39     ` Anup Patel
2026-02-10 16:57       ` Raymond Mao
2026-02-11 17:30         ` Anup Patel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox