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 #include #include @@ -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 #include #include +#include +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) -{ - return SBI_ENODEV; -} - -static int (*ext_irqfn)(void) = default_irqfn; - int sbi_irqchip_process(void) { - return ext_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) + return SBI_ENODEV; + + 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->process_hwirqs) - ext_irqfn = chip->process_hwirqs; + 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; + + 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); }