[PATCH v6 08/11] lib: utils/irqchip: Add APLIC restore function
Anup Patel
anup at brainfault.org
Mon Sep 8 04:24:45 PDT 2025
On Fri, Sep 5, 2025 at 7:54 AM Nick Hu <nick.hu at sifive.com> wrote:
>
> Since the APLIC may enter a reset state upon system wake-up from a
> platform low power state, adding a restore function to reinitialize
> the APLIC.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
LGTM.
Reviewed-by: Anup Patel <anup at brainfault.org>
Regards,
Anup
> ---
> include/sbi_utils/irqchip/aplic.h | 3 +
> lib/utils/irqchip/aplic.c | 160 ++++++++++++++++++++++----------------
> 2 files changed, 96 insertions(+), 67 deletions(-)
>
> diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h
> index e31f48a45019e1874e3223e3fb232f553890d06d..cbfcd3fd17bc09a644bf47e7d2716123c25a305e 100644
> --- a/include/sbi_utils/irqchip/aplic.h
> +++ b/include/sbi_utils/irqchip/aplic.h
> @@ -33,6 +33,7 @@ struct aplic_delegate_data {
> struct aplic_data {
> /* Private members */
> struct sbi_irqchip_device irqchip;
> + struct sbi_dlist node;
> /* Public members */
> unsigned long addr;
> unsigned long size;
> @@ -48,4 +49,6 @@ struct aplic_data {
>
> int aplic_cold_irqchip_init(struct aplic_data *aplic);
>
> +void aplic_reinit_all(void);
> +
> #endif
> diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
> index 72906d5d13995fd4e40dc0dc74a609148d65c742..e40d8829d5196dedafeafcd8f1e31d4a88cb5dbb 100644
> --- a/lib/utils/irqchip/aplic.c
> +++ b/lib/utils/irqchip/aplic.c
> @@ -115,6 +115,88 @@
> #define APLIC_DISABLE_ITHRESHOLD 1
> #define APLIC_ENABLE_ITHRESHOLD 0
>
> +static SBI_LIST_HEAD(aplic_list);
> +static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
> + void *msicfgaddr, void *msicfgaddrH);
> +
> +static void aplic_init(struct aplic_data *aplic)
> +{
> + u32 i, j, tmp;
> + struct aplic_delegate_data *deleg;
> +
> + /* Set domain configuration to 0 */
> + writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
> +
> + /* Disable all interrupts */
> + for (i = 0; i <= aplic->num_source; i += 32)
> + writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
> + (i / 32) * sizeof(u32)));
> +
> + /* Set interrupt type and priority for all interrupts */
> + for (i = 1; i <= aplic->num_source; i++) {
> + /* Set IRQ source configuration to 0 */
> + writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
> + (i - 1) * sizeof(u32)));
> + /* Set IRQ target hart index and priority to 1 */
> + writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
> + APLIC_TARGET_BASE +
> + (i - 1) * sizeof(u32)));
> + }
> +
> + /* Configure IRQ delegation */
> + for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
> + deleg = &aplic->delegate[i];
> + if (!deleg->first_irq || !deleg->last_irq)
> + continue;
> + if (aplic->num_source < deleg->first_irq ||
> + aplic->num_source < deleg->last_irq)
> + continue;
> + if (deleg->child_index > APLIC_SOURCECFG_CHILDIDX_MASK)
> + continue;
> + if (deleg->first_irq > deleg->last_irq) {
> + tmp = deleg->first_irq;
> + deleg->first_irq = deleg->last_irq;
> + deleg->last_irq = tmp;
> + }
> + for (j = deleg->first_irq; j <= deleg->last_irq; j++)
> + writel(APLIC_SOURCECFG_D | deleg->child_index,
> + (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
> + (j - 1) * sizeof(u32)));
> + }
> +
> + /* Default initialization of IDC structures */
> + for (i = 0; i < aplic->num_idc; i++) {
> + writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
> + i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
> + writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
> + i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
> + writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
> + APLIC_IDC_BASE +
> + (i * APLIC_IDC_SIZE) +
> + APLIC_IDC_ITHRESHOLD));
> + }
> +
> + /* MSI configuration */
> + if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
> + aplic_writel_msicfg(&aplic->msicfg_mmode,
> + (void *)(aplic->addr + APLIC_MMSICFGADDR),
> + (void *)(aplic->addr + APLIC_MMSICFGADDRH));
> + }
> + if (aplic->targets_mmode && aplic->has_msicfg_smode) {
> + aplic_writel_msicfg(&aplic->msicfg_smode,
> + (void *)(aplic->addr + APLIC_SMSICFGADDR),
> + (void *)(aplic->addr + APLIC_SMSICFGADDRH));
> + }
> +}
> +
> +void aplic_reinit_all(void)
> +{
> + struct aplic_data *aplic;
> +
> + sbi_list_for_each_entry(aplic, &aplic_list, node)
> + aplic_init(aplic);
> +}
> +
> static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
> void *msicfgaddr, void *msicfgaddrH)
> {
> @@ -168,9 +250,8 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
> int aplic_cold_irqchip_init(struct aplic_data *aplic)
> {
> int rc;
> - u32 i, j, tmp;
> struct aplic_delegate_data *deleg;
> - u32 first_deleg_irq, last_deleg_irq;
> + u32 first_deleg_irq, last_deleg_irq, i;
>
> /* Sanity checks */
> if (!aplic ||
> @@ -188,81 +269,23 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
> return rc;
> }
>
> - /* Set domain configuration to 0 */
> - writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
> -
> - /* Disable all interrupts */
> - for (i = 0; i <= aplic->num_source; i += 32)
> - writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
> - (i / 32) * sizeof(u32)));
> -
> - /* Set interrupt type and priority for all interrupts */
> - for (i = 1; i <= aplic->num_source; i++) {
> - /* Set IRQ source configuration to 0 */
> - writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
> - (i - 1) * sizeof(u32)));
> - /* Set IRQ target hart index and priority to 1 */
> - writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
> - APLIC_TARGET_BASE +
> - (i - 1) * sizeof(u32)));
> - }
> + /* Init the APLIC registers */
> + aplic_init(aplic);
>
> - /* Configure IRQ delegation */
> + /*
> + * Add APLIC region to the root domain if:
> + * 1) It targets M-mode of any HART directly or via MSIs
> + * 2) All interrupts are delegated to some child APLIC
> + */
> first_deleg_irq = -1U;
> last_deleg_irq = 0;
> for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
> deleg = &aplic->delegate[i];
> - if (!deleg->first_irq || !deleg->last_irq)
> - continue;
> - if (aplic->num_source < deleg->first_irq ||
> - aplic->num_source < deleg->last_irq)
> - continue;
> - if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
> - continue;
> - if (deleg->first_irq > deleg->last_irq) {
> - tmp = deleg->first_irq;
> - deleg->first_irq = deleg->last_irq;
> - deleg->last_irq = tmp;
> - }
> if (deleg->first_irq < first_deleg_irq)
> first_deleg_irq = deleg->first_irq;
> if (last_deleg_irq < deleg->last_irq)
> last_deleg_irq = deleg->last_irq;
> - for (j = deleg->first_irq; j <= deleg->last_irq; j++)
> - writel(APLIC_SOURCECFG_D | deleg->child_index,
> - (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
> - (j - 1) * sizeof(u32)));
> - }
> -
> - /* Default initialization of IDC structures */
> - for (i = 0; i < aplic->num_idc; i++) {
> - writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
> - i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
> - writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
> - i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
> - writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
> - APLIC_IDC_BASE +
> - (i * APLIC_IDC_SIZE) +
> - APLIC_IDC_ITHRESHOLD));
> - }
> -
> - /* MSI configuration */
> - if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
> - aplic_writel_msicfg(&aplic->msicfg_mmode,
> - (void *)(aplic->addr + APLIC_MMSICFGADDR),
> - (void *)(aplic->addr + APLIC_MMSICFGADDRH));
> - }
> - if (aplic->targets_mmode && aplic->has_msicfg_smode) {
> - aplic_writel_msicfg(&aplic->msicfg_smode,
> - (void *)(aplic->addr + APLIC_SMSICFGADDR),
> - (void *)(aplic->addr + APLIC_SMSICFGADDRH));
> }
> -
> - /*
> - * Add APLIC region to the root domain if:
> - * 1) It targets M-mode of any HART directly or via MSIs
> - * 2) All interrupts are delegated to some child APLIC
> - */
> if (aplic->targets_mmode ||
> ((first_deleg_irq < last_deleg_irq) &&
> (last_deleg_irq == aplic->num_source) &&
> @@ -278,5 +301,8 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
> /* Register irqchip device */
> sbi_irqchip_add_device(&aplic->irqchip);
>
> + /* Attach to the aplic list */
> + sbi_list_add_tail(&aplic->node, &aplic_list);
> +
> return 0;
> }
>
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
More information about the opensbi
mailing list