diff options
| author | Anup Patel <anup.patel@oss.qualcomm.com> | 2026-02-13 11:23:39 +0530 |
|---|---|---|
| committer | Anup Patel <anup@brainfault.org> | 2026-03-22 10:53:33 +0530 |
| commit | b55bb4cdcb298c12a316713d6cc7948973c14f9b (patch) | |
| tree | c6ff86c0798e3ed42ba15c0e5f033ca529b3853b | |
| parent | 5a300b32d546d226e55361e47d07b1c9171f07c8 (diff) | |
| download | opensbi-b55bb4cdcb298c12a316713d6cc7948973c14f9b.tar.gz opensbi-b55bb4cdcb298c12a316713d6cc7948973c14f9b.zip | |
lib: sbi_irqchip: Support irqchip device targetting subset of harts
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 process_hwirqs() 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>
Link: https://lore.kernel.org/r/20260213055342.3124872-6-anup.patel@oss.qualcomm.com
Signed-off-by: Anup Patel <anup@brainfault.org>
| -rw-r--r-- | include/sbi/sbi_irqchip.h | 8 | ||||
| -rw-r--r-- | lib/sbi/sbi_irqchip.c | 63 | ||||
| -rw-r--r-- | lib/utils/irqchip/aplic.c | 12 | ||||
| -rw-r--r-- | lib/utils/irqchip/imsic.c | 7 | ||||
| -rw-r--r-- | lib/utils/irqchip/plic.c | 5 |
5 files changed, 73 insertions, 22 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..d3e58288 100644 --- a/lib/sbi/sbi_irqchip.c +++ b/lib/sbi/sbi_irqchip.c @@ -10,36 +10,65 @@ #include <sbi/sbi_irqchip.h> #include <sbi/sbi_list.h> #include <sbi/sbi_platform.h> +#include <sbi/sbi_scratch.h> +struct sbi_irqchip_hart_data { + struct sbi_irqchip_device *chip; +}; + +static unsigned long irqchip_hart_data_off; static SBI_LIST_HEAD(irqchip_list); -static int default_irqfn(void) +int sbi_irqchip_process(void) { - return SBI_ENODEV; -} + struct sbi_irqchip_hart_data *hd; -static int (*ext_irqfn)(void) = default_irqfn; + hd = sbi_scratch_thishart_offset_ptr(irqchip_hart_data_off); + if (!hd || !hd->chip || !hd->chip->process_hwirqs) + return SBI_ENODEV; -int sbi_irqchip_process(void) -{ - return ext_irqfn(); + return hd->chip->process_hwirqs(hd->chip); } -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_hart_data *hd; + struct sbi_scratch *scratch; + u32 h; + + if (!chip || !sbi_hartmask_weight(&chip->target_harts)) + return SBI_EINVAL; + + if (chip->process_hwirqs) { + sbi_hartmask_for_each_hartindex(h, &chip->target_harts) { + scratch = sbi_hartindex_to_scratch(h); + if (!scratch) + continue; - if (chip->process_hwirqs) - ext_irqfn = chip->process_hwirqs; + hd = sbi_scratch_offset_ptr(scratch, irqchip_hart_data_off); + if (hd->chip && hd->chip != chip) + return SBI_EINVAL; + + hd->chip = chip; + } + } + + sbi_list_add_tail(&chip->node, &irqchip_list); + return 0; } 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_hart_data *hd; struct sbi_irqchip_device *chip; + int rc; if (cold_boot) { + irqchip_hart_data_off = + sbi_scratch_alloc_offset(sizeof(struct sbi_irqchip_hart_data)); + if (!irqchip_hart_data_off) + return SBI_ENOMEM; rc = sbi_platform_irqchip_init(plat); if (rc) return rc; @@ -48,12 +77,15 @@ 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) + hd = sbi_scratch_thishart_offset_ptr(irqchip_hart_data_off); + if (hd && hd->chip && hd->chip->process_hwirqs) csr_set(CSR_MIE, MIP_MEIP); return 0; @@ -61,6 +93,9 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot) void sbi_irqchip_exit(struct sbi_scratch *scratch) { - if (ext_irqfn != default_irqfn) + struct sbi_irqchip_hart_data *hd; + + hd = sbi_scratch_thishart_offset_ptr(irqchip_hart_data_off); + if (hd && hd->chip && hd->chip->process_hwirqs) 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); } |
