[PATCH v2 1/2] lib: utils: Add fdt_add_cpu_idle_states() helper function

Anup Patel anup at brainfault.org
Tue Jan 24 04:32:05 PST 2023


On Mon, Jan 23, 2023 at 12:02 PM Samuel Holland <samuel at sholland.org> wrote:
>
> Since the availability and latency properties of CPU idle states depend
> on the specific SBI HSM implementation, it is appropriate that the idle
> states are added to the devicetree at runtime by that implementation.
>
> This helper function adds a platform-provided array of idle states to
> the devicetree, following the SBI idle state binding.
>
> Reviewed-by: Anup Patel <anup at brainfault.org>
> Signed-off-by: Samuel Holland <samuel at sholland.org>

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> ---
>
> Changes in v2:
>  - Do nothing if the idle-states node already exists
>
>  include/sbi_utils/fdt/fdt_fixup.h | 23 +++++++++
>  lib/utils/fdt/fdt_fixup.c         | 85 +++++++++++++++++++++++++++++++
>  2 files changed, 108 insertions(+)
>
> diff --git a/include/sbi_utils/fdt/fdt_fixup.h b/include/sbi_utils/fdt/fdt_fixup.h
> index fb076ba..cab3f0f 100644
> --- a/include/sbi_utils/fdt/fdt_fixup.h
> +++ b/include/sbi_utils/fdt/fdt_fixup.h
> @@ -9,6 +9,29 @@
>  #ifndef __FDT_FIXUP_H__
>  #define __FDT_FIXUP_H__
>
> +struct sbi_cpu_idle_state {
> +       const char *name;
> +       uint32_t suspend_param;
> +       bool local_timer_stop;
> +       uint32_t entry_latency_us;
> +       uint32_t exit_latency_us;
> +       uint32_t min_residency_us;
> +       uint32_t wakeup_latency_us;
> +};
> +
> +/**
> + * Add CPU idle states to cpu nodes in the DT
> + *
> + * Add information about CPU idle states to the devicetree. This function
> + * assumes that CPU idle states are not already present in the devicetree, and
> + * that all CPU states are equally applicable to all CPUs.
> + *
> + * @param fdt: device tree blob
> + * @param states: array of idle state descriptions, ending with empty element
> + * @return zero on success and -ve on failure
> + */
> +int fdt_add_cpu_idle_states(void *dtb, const struct sbi_cpu_idle_state *state);
> +
>  /**
>   * Fix up the CPU node in the device tree
>   *
> diff --git a/lib/utils/fdt/fdt_fixup.c b/lib/utils/fdt/fdt_fixup.c
> index 42692cc..e57a4e1 100644
> --- a/lib/utils/fdt/fdt_fixup.c
> +++ b/lib/utils/fdt/fdt_fixup.c
> @@ -18,6 +18,91 @@
>  #include <sbi_utils/fdt/fdt_pmu.h>
>  #include <sbi_utils/fdt/fdt_helper.h>
>
> +int fdt_add_cpu_idle_states(void *fdt, const struct sbi_cpu_idle_state *state)
> +{
> +       int cpu_node, cpus_node, err, idle_states_node;
> +       uint32_t count, phandle;
> +
> +       err = fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + 1024);
> +       if (err < 0)
> +               return err;
> +
> +       err = fdt_find_max_phandle(fdt, &phandle);
> +       phandle++;
> +       if (err < 0)
> +               return err;
> +
> +       cpus_node = fdt_path_offset(fdt, "/cpus");
> +       if (cpus_node < 0)
> +               return cpus_node;
> +
> +       /* Do nothing if the idle-states node already exists. */
> +       idle_states_node = fdt_subnode_offset(fdt, cpus_node, "idle-states");
> +       if (idle_states_node >= 0)
> +               return 0;
> +
> +       /* Create the idle-states node and its child nodes. */
> +       idle_states_node = fdt_add_subnode(fdt, cpus_node, "idle-states");
> +       if (idle_states_node < 0)
> +               return idle_states_node;
> +
> +       for (count = 0; state->name; count++, phandle++, state++) {
> +               int idle_state_node;
> +
> +               idle_state_node = fdt_add_subnode(fdt, idle_states_node,
> +                                                 state->name);
> +               if (idle_state_node < 0)
> +                       return idle_state_node;
> +
> +               fdt_setprop_string(fdt, idle_state_node, "compatible",
> +                                  "riscv,idle-state");
> +               fdt_setprop_u32(fdt, idle_state_node,
> +                               "riscv,sbi-suspend-param",
> +                               state->suspend_param);
> +               if (state->local_timer_stop)
> +                       fdt_setprop_empty(fdt, idle_state_node,
> +                                         "local-timer-stop");
> +               fdt_setprop_u32(fdt, idle_state_node, "entry-latency-us",
> +                               state->entry_latency_us);
> +               fdt_setprop_u32(fdt, idle_state_node, "exit-latency-us",
> +                               state->exit_latency_us);
> +               fdt_setprop_u32(fdt, idle_state_node, "min-residency-us",
> +                               state->min_residency_us);
> +               if (state->wakeup_latency_us)
> +                       fdt_setprop_u32(fdt, idle_state_node,
> +                                       "wakeup-latency-us",
> +                                       state->wakeup_latency_us);
> +               fdt_setprop_u32(fdt, idle_state_node, "phandle", phandle);
> +       }
> +
> +       if (count == 0)
> +               return 0;
> +
> +       /* Link each cpu node to the idle state nodes. */
> +       fdt_for_each_subnode(cpu_node, fdt, cpus_node) {
> +               const char *device_type;
> +               fdt32_t *value;
> +
> +               /* Only process child nodes with device_type = "cpu". */
> +               device_type = fdt_getprop(fdt, cpu_node, "device_type", NULL);
> +               if (!device_type || strcmp(device_type, "cpu"))
> +                       continue;
> +
> +               /* Allocate space for the list of phandles. */
> +               err = fdt_setprop_placeholder(fdt, cpu_node, "cpu-idle-states",
> +                                             count * sizeof(phandle),
> +                                             (void **)&value);
> +               if (err < 0)
> +                       return err;
> +
> +               /* Fill in the phandles of the idle state nodes. */
> +               for (uint32_t i = 0; i < count; ++i)
> +                       value[i] = cpu_to_fdt32(phandle - count + i);
> +       }
> +
> +       return 0;
> +}
> +
>  void fdt_cpu_fixup(void *fdt)
>  {
>         struct sbi_domain *dom = sbi_domain_thishart_ptr();
> --
> 2.37.4
>



More information about the opensbi mailing list