[PATCH 4/9] lib: utils/irqchip: plic: Common PM save/restore

Anup Patel anup at brainfault.org
Wed Nov 27 21:59:12 PST 2024


On Tue, Nov 5, 2024 at 9:40 AM Samuel Holland <samuel.holland at sifive.com> wrote:
>
> Move the PLIC save/restore functions inside the driver, so they can be
> reused on any platform that needs them. The memory needed to store the
> PLIC context is also allocated by the driver. The PM data cannot be
> completely encapsulated, as some platforms (including Allwinner D1) need
> to program the IRQ enable status to a sideband interrupt controller for
> wakeup capability.
>
> Signed-off-by: Samuel Holland <samuel.holland at sifive.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Regards,
Anup

> ---
>
>  include/sbi_utils/irqchip/fdt_irqchip_plic.h |  22 +--
>  include/sbi_utils/irqchip/plic.h             |  19 +--
>  lib/utils/irqchip/fdt_irqchip_plic.c         |  32 +----
>  lib/utils/irqchip/plic.c                     | 134 ++++++++++++-------
>  platform/generic/allwinner/sun20i-d1.c       |  34 +----
>  5 files changed, 112 insertions(+), 129 deletions(-)
>
> diff --git a/include/sbi_utils/irqchip/fdt_irqchip_plic.h b/include/sbi_utils/irqchip/fdt_irqchip_plic.h
> index df645dd0..fe769993 100644
> --- a/include/sbi_utils/irqchip/fdt_irqchip_plic.h
> +++ b/include/sbi_utils/irqchip/fdt_irqchip_plic.h
> @@ -8,26 +8,12 @@
>  #define __IRQCHIP_FDT_IRQCHIP_PLIC_H__
>
>  #include <sbi/sbi_types.h>
> +#include <sbi_utils/irqchip/plic.h>
>
> -/**
> - * Save the PLIC priority state
> - * @param priority pointer to the memory region for the saved priority
> - * @param num size of the memory region including interrupt source 0
> - */
> -void fdt_plic_priority_save(u8 *priority, u32 num);
> -
> -/**
> - * Restore the PLIC priority state
> - * @param priority pointer to the memory region for the saved priority
> - * @param num size of the memory region including interrupt source 0
> - */
> -void fdt_plic_priority_restore(const u8 *priority, u32 num);
> -
> -void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num);
> +struct plic_data *fdt_plic_get(void);
>
> -void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
> -                             u32 num);
> +void fdt_plic_suspend(void);
>
> -void thead_plic_restore(void);
> +void fdt_plic_resume(void);
>
>  #endif
> diff --git a/include/sbi_utils/irqchip/plic.h b/include/sbi_utils/irqchip/plic.h
> index e6b6f823..29fe60c1 100644
> --- a/include/sbi_utils/irqchip/plic.h
> +++ b/include/sbi_utils/irqchip/plic.h
> @@ -17,6 +17,7 @@ struct plic_data {
>         unsigned long size;
>         unsigned long num_src;
>         unsigned long flags;
> +       void *pm_data;
>         s16 context_map[][2];
>  };
>
> @@ -24,6 +25,8 @@ struct plic_data {
>  #define PLIC_FLAG_ARIANE_BUG           BIT(0)
>  /** PLIC must be delegated to S-mode like T-HEAD C906 and C910 */
>  #define PLIC_FLAG_THEAD_DELEGATION     BIT(1)
> +/** Allocate space for power management save/restore operations */
> +#define PLIC_FLAG_ENABLE_PM            BIT(2)
>
>  #define PLIC_M_CONTEXT                 0
>  #define PLIC_S_CONTEXT                 1
> @@ -31,22 +34,14 @@ struct plic_data {
>  #define PLIC_DATA_SIZE(__hart_count)   (sizeof(struct plic_data) + \
>                                          (__hart_count) * 2 * sizeof(s16))
>
> -/* So far, priorities on all consumers of these functions fit in 8 bits. */
> -void plic_priority_save(const struct plic_data *plic, u8 *priority, u32 num);
> +#define PLIC_IE_WORDS(__p)             ((__p)->num_src / 32 + 1)
>
> -void plic_priority_restore(const struct plic_data *plic, const u8 *priority,
> -                          u32 num);
> +void plic_suspend(const struct plic_data *plic);
>
> -void plic_delegate(const struct plic_data *plic);
> -
> -void plic_context_save(const struct plic_data *plic, bool smode,
> -                      u32 *enable, u32 *threshold, u32 num);
> -
> -void plic_context_restore(const struct plic_data *plic, bool smode,
> -                         const u32 *enable, u32 threshold, u32 num);
> +void plic_resume(const struct plic_data *plic);
>
>  int plic_warm_irqchip_init(const struct plic_data *plic);
>
> -int plic_cold_irqchip_init(const struct plic_data *plic);
> +int plic_cold_irqchip_init(struct plic_data *plic);
>
>  #endif
> diff --git a/lib/utils/irqchip/fdt_irqchip_plic.c b/lib/utils/irqchip/fdt_irqchip_plic.c
> index 2ba56748..3826d2ae 100644
> --- a/lib/utils/irqchip/fdt_irqchip_plic.c
> +++ b/lib/utils/irqchip/fdt_irqchip_plic.c
> @@ -26,35 +26,25 @@ static unsigned long plic_ptr_offset;
>  #define plic_set_hart_data_ptr(__scratch, __plic)                      \
>         sbi_scratch_write_type((__scratch), void *, plic_ptr_offset, (__plic))
>
> -void fdt_plic_priority_save(u8 *priority, u32 num)
> +struct plic_data *fdt_plic_get(void)
>  {
>         struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
>
> -       plic_priority_save(plic_get_hart_data_ptr(scratch), priority, num);
> +       return plic_get_hart_data_ptr(scratch);
>  }
>
> -void fdt_plic_priority_restore(const u8 *priority, u32 num)
> +void fdt_plic_suspend(void)
>  {
>         struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
>
> -       plic_priority_restore(plic_get_hart_data_ptr(scratch), priority, num);
> +       plic_suspend(plic_get_hart_data_ptr(scratch));
>  }
>
> -void fdt_plic_context_save(bool smode, u32 *enable, u32 *threshold, u32 num)
> +void fdt_plic_resume(void)
>  {
>         struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
>
> -       plic_context_save(plic_get_hart_data_ptr(scratch), smode,
> -                         enable, threshold, num);
> -}
> -
> -void fdt_plic_context_restore(bool smode, const u32 *enable, u32 threshold,
> -                             u32 num)
> -{
> -       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> -
> -       plic_context_restore(plic_get_hart_data_ptr(scratch), smode,
> -                            enable, threshold, num);
> +       plic_resume(plic_get_hart_data_ptr(scratch));
>  }
>
>  static int irqchip_plic_warm_init(void)
> @@ -151,20 +141,12 @@ fail_free_data:
>         return rc;
>  }
>
> -void thead_plic_restore(void)
> -{
> -       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> -       struct plic_data *plic = plic_get_hart_data_ptr(scratch);
> -
> -       plic_delegate(plic);
> -}
> -
>  static const struct fdt_match irqchip_plic_match[] = {
>         { .compatible = "andestech,nceplic100" },
>         { .compatible = "riscv,plic0" },
>         { .compatible = "sifive,plic-1.0.0" },
>         { .compatible = "thead,c900-plic",
> -         .data = (void *)PLIC_FLAG_THEAD_DELEGATION },
> +         .data = (void *)(PLIC_FLAG_THEAD_DELEGATION | PLIC_FLAG_ENABLE_PM) },
>         { /* sentinel */ }
>  };
>
> diff --git a/lib/utils/irqchip/plic.c b/lib/utils/irqchip/plic.c
> index c8ea8840..ab58e390 100644
> --- a/lib/utils/irqchip/plic.c
> +++ b/lib/utils/irqchip/plic.c
> @@ -14,6 +14,7 @@
>  #include <sbi/sbi_console.h>
>  #include <sbi/sbi_domain.h>
>  #include <sbi/sbi_error.h>
> +#include <sbi/sbi_heap.h>
>  #include <sbi/sbi_string.h>
>  #include <sbi_utils/irqchip/plic.h>
>
> @@ -40,19 +41,6 @@ static void plic_set_priority(const struct plic_data *plic, u32 source, u32 val)
>         writel(val, plic_priority);
>  }
>
> -void plic_priority_save(const struct plic_data *plic, u8 *priority, u32 num)
> -{
> -       for (u32 i = 1; i <= num; i++)
> -               priority[i] = plic_get_priority(plic, i);
> -}
> -
> -void plic_priority_restore(const struct plic_data *plic, const u8 *priority,
> -                          u32 num)
> -{
> -       for (u32 i = 1; i <= num; i++)
> -               plic_set_priority(plic, i, priority[i]);
> -}
> -
>  static u32 plic_get_thresh(const struct plic_data *plic, u32 cntxid)
>  {
>         volatile void *plic_thresh;
> @@ -95,62 +83,91 @@ static void plic_set_ie(const struct plic_data *plic, u32 cntxid,
>         writel(val, plic_ie);
>  }
>
> -void plic_delegate(const struct plic_data *plic)
> +static void plic_delegate(const struct plic_data *plic)
>  {
>         /* If this is a T-HEAD PLIC, delegate access to S-mode */
>         if (plic->flags & PLIC_FLAG_THEAD_DELEGATION)
>                 writel_relaxed(BIT(0), (char *)plic->addr + THEAD_PLIC_CTRL_REG);
>  }
>
> -void plic_context_save(const struct plic_data *plic, bool smode,
> -                      u32 *enable, u32 *threshold, u32 num)
> +static int plic_context_init(const struct plic_data *plic, int context_id,
> +                            bool enable, u32 threshold)
>  {
> -       u32 hartindex = current_hartindex();
> -       s16 context_id = plic->context_map[hartindex][smode];
> -       u32 ie_words = plic->num_src / 32 + 1;
> +       u32 ie_words, ie_value;
>
> -       if (num > ie_words)
> -               num = ie_words;
> +       if (!plic || context_id < 0)
> +               return SBI_EINVAL;
>
> -       for (u32 i = 0; i < num; i++)
> -               enable[i] = plic_get_ie(plic, context_id, i);
> +       ie_words = PLIC_IE_WORDS(plic);
> +       ie_value = enable ? 0xffffffffU : 0U;
> +
> +       for (u32 i = 0; i < ie_words; i++)
> +               plic_set_ie(plic, context_id, i, ie_value);
> +
> +       plic_set_thresh(plic, context_id, threshold);
>
> -       *threshold = plic_get_thresh(plic, context_id);
> +       return 0;
>  }
>
> -void plic_context_restore(const struct plic_data *plic, bool smode,
> -                         const u32 *enable, u32 threshold, u32 num)
> +void plic_suspend(const struct plic_data *plic)
>  {
> -       u32 hartindex = current_hartindex();
> -       s16 context_id = plic->context_map[hartindex][smode];
> -       u32 ie_words = plic->num_src / 32 + 1;
> +       u32 ie_words = PLIC_IE_WORDS(plic);
> +       u32 *data_word = plic->pm_data;
> +       u8 *data_byte;
>
> -       if (num > ie_words)
> -               num = ie_words;
> +       if (!data_word)
> +               return;
>
> -       for (u32 i = 0; i < num; i++)
> -               plic_set_ie(plic, context_id, i, enable[i]);
> +       for (u32 h = 0; h <= sbi_scratch_last_hartindex(); h++) {
> +               u32 context_id = plic->context_map[h][PLIC_S_CONTEXT];
>
> -       plic_set_thresh(plic, context_id, threshold);
> +               if (context_id < 0)
> +                       continue;
> +
> +               /* Save the enable bits */
> +               for (u32 i = 0; i < ie_words; i++)
> +                       *data_word++ = plic_get_ie(plic, context_id, i);
> +
> +               /* Save the context threshold */
> +               *data_word++ = plic_get_thresh(plic, context_id);
> +       }
> +
> +       /* Restore the input priorities */
> +       data_byte = (u8 *)data_word;
> +       for (u32 i = 1; i <= plic->num_src; i++)
> +               *data_byte++ = plic_get_priority(plic, i);
>  }
>
> -static int plic_context_init(const struct plic_data *plic, int context_id,
> -                            bool enable, u32 threshold)
> +void plic_resume(const struct plic_data *plic)
>  {
> -       u32 ie_words, ie_value;
> +       u32 ie_words = PLIC_IE_WORDS(plic);
> +       u32 *data_word = plic->pm_data;
> +       u8 *data_byte;
>
> -       if (!plic || context_id < 0)
> -               return SBI_EINVAL;
> +       if (!data_word)
> +               return;
>
> -       ie_words = plic->num_src / 32 + 1;
> -       ie_value = enable ? 0xffffffffU : 0U;
> +       for (u32 h = 0; h <= sbi_scratch_last_hartindex(); h++) {
> +               u32 context_id = plic->context_map[h][PLIC_S_CONTEXT];
>
> -       for (u32 i = 0; i < ie_words; i++)
> -               plic_set_ie(plic, context_id, i, ie_value);
> +               if (context_id < 0)
> +                       continue;
>
> -       plic_set_thresh(plic, context_id, threshold);
> +               /* Restore the enable bits */
> +               for (u32 i = 0; i < ie_words; i++)
> +                       plic_set_ie(plic, context_id, i, *data_word++);
>
> -       return 0;
> +               /* Restore the context threshold */
> +               plic_set_thresh(plic, context_id, *data_word++);
> +       }
> +
> +       /* Restore the input priorities */
> +       data_byte = (u8 *)data_word;
> +       for (u32 i = 1; i <= plic->num_src; i++)
> +               plic_set_priority(plic, i, *data_byte++);
> +
> +       /* Restore the delegation */
> +       plic_delegate(plic);
>  }
>
>  int plic_warm_irqchip_init(const struct plic_data *plic)
> @@ -182,13 +199,38 @@ int plic_warm_irqchip_init(const struct plic_data *plic)
>         return 0;
>  }
>
> -int plic_cold_irqchip_init(const struct plic_data *plic)
> +int plic_cold_irqchip_init(struct plic_data *plic)
>  {
>         int i;
>
>         if (!plic)
>                 return SBI_EINVAL;
>
> +       if (plic->flags & PLIC_FLAG_ENABLE_PM) {
> +               unsigned long data_size = 0;
> +
> +               for (u32 i = 0; i <= sbi_scratch_last_hartindex(); i++) {
> +                       if (plic->context_map[i][PLIC_S_CONTEXT] < 0)
> +                               continue;
> +
> +                       /* Allocate space for enable bits */
> +                       data_size += (plic->num_src / 32 + 1) * sizeof(u32);
> +
> +                       /* Allocate space for the context threshold */
> +                       data_size += sizeof(u32);
> +               }
> +
> +               /*
> +                * Allocate space for the input priorities. So far,
> +                * priorities on all known implementations fit in 8 bits.
> +                */
> +               data_size += plic->num_src * sizeof(u8);
> +
> +               plic->pm_data = sbi_malloc(data_size);
> +               if (!plic->pm_data)
> +                       return SBI_ENOMEM;
> +       }
> +
>         /* Configure default priorities of all IRQs */
>         for (i = 1; i <= plic->num_src; i++)
>                 plic_set_priority(plic, i, 0);
> diff --git a/platform/generic/allwinner/sun20i-d1.c b/platform/generic/allwinner/sun20i-d1.c
> index 9b1d5559..c4b06d1a 100644
> --- a/platform/generic/allwinner/sun20i-d1.c
> +++ b/platform/generic/allwinner/sun20i-d1.c
> @@ -60,31 +60,6 @@ static void sun20i_d1_csr_restore(void)
>         csr_write(THEAD_C9XX_CSR_MHINT, csr_mhint);
>  }
>
> -/*
> - * PLIC
> - */
> -
> -#define PLIC_SOURCES                   175
> -#define PLIC_IE_WORDS                  (PLIC_SOURCES / 32 + 1)
> -
> -static u8 plic_priority[1 + PLIC_SOURCES];
> -static u32 plic_sie[PLIC_IE_WORDS];
> -static u32 plic_threshold;
> -
> -static void sun20i_d1_plic_save(void)
> -{
> -       fdt_plic_context_save(true, plic_sie, &plic_threshold, PLIC_IE_WORDS);
> -       fdt_plic_priority_save(plic_priority, PLIC_SOURCES);
> -}
> -
> -static void sun20i_d1_plic_restore(void)
> -{
> -       thead_plic_restore();
> -       fdt_plic_priority_restore(plic_priority, PLIC_SOURCES);
> -       fdt_plic_context_restore(true, plic_sie, plic_threshold,
> -                                PLIC_IE_WORDS);
> -}
> -
>  /*
>   * PPU
>   */
> @@ -117,6 +92,9 @@ static void sun20i_d1_ppu_restore(void)
>
>  static void sun20i_d1_riscv_cfg_save(void)
>  {
> +       struct plic_data *plic = fdt_plic_get();
> +       u32 *plic_sie = plic->pm_data;
> +
>         /* Enable MMIO access. Do not assume S-mode leaves the clock enabled. */
>         writel_relaxed(CCU_BGR_ENABLE, SUN20I_D1_CCU_BASE + RISCV_CFG_BGR_REG);
>
> @@ -126,7 +104,7 @@ static void sun20i_d1_riscv_cfg_save(void)
>          * the wakeup mask registers (the offset is for GIC compatibility). So
>          * copying SIE to the wakeup mask needs some bit manipulation.
>          */
> -       for (int i = 0; i < PLIC_IE_WORDS - 1; i++)
> +       for (int i = 0; i < PLIC_IE_WORDS(plic) - 1; i++)
>                 writel_relaxed(plic_sie[i] >> 16 | plic_sie[i + 1] << 16,
>                                SUN20I_D1_RISCV_CFG_BASE + WAKEUP_MASK_REG(i));
>
> @@ -158,7 +136,7 @@ static int sun20i_d1_hart_suspend(u32 suspend_type)
>         if (!(suspend_type & SBI_HSM_SUSP_NON_RET_BIT))
>                 return SBI_ENOTSUPP;
>
> -       sun20i_d1_plic_save();
> +       fdt_plic_suspend();
>         sun20i_d1_ppu_save();
>         sun20i_d1_riscv_cfg_save();
>         sun20i_d1_csr_save();
> @@ -178,7 +156,7 @@ static void sun20i_d1_hart_resume(void)
>         sun20i_d1_csr_restore();
>         sun20i_d1_riscv_cfg_restore();
>         sun20i_d1_ppu_restore();
> -       sun20i_d1_plic_restore();
> +       fdt_plic_resume();
>  }
>
>  static const struct sbi_hsm_device sun20i_d1_ppu = {
> --
> 2.45.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi



More information about the opensbi mailing list