[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