root/drivers/cpuidle/dt_idle_states.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_state_node
  2. idle_state_valid
  3. dt_init_idle_driver

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * DT idle states parsing code.
   4  *
   5  * Copyright (C) 2014 ARM Ltd.
   6  * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
   7  */
   8 
   9 #define pr_fmt(fmt) "DT idle-states: " fmt
  10 
  11 #include <linux/cpuidle.h>
  12 #include <linux/cpumask.h>
  13 #include <linux/errno.h>
  14 #include <linux/kernel.h>
  15 #include <linux/module.h>
  16 #include <linux/of.h>
  17 #include <linux/of_device.h>
  18 
  19 #include "dt_idle_states.h"
  20 
  21 static int init_state_node(struct cpuidle_state *idle_state,
  22                            const struct of_device_id *match_id,
  23                            struct device_node *state_node)
  24 {
  25         int err;
  26         const char *desc;
  27 
  28         /*
  29          * CPUidle drivers are expected to initialize the const void *data
  30          * pointer of the passed in struct of_device_id array to the idle
  31          * state enter function.
  32          */
  33         idle_state->enter = match_id->data;
  34         /*
  35          * Since this is not a "coupled" state, it's safe to assume interrupts
  36          * won't be enabled when it exits allowing the tick to be frozen
  37          * safely. So enter() can be also enter_s2idle() callback.
  38          */
  39         idle_state->enter_s2idle = match_id->data;
  40 
  41         err = of_property_read_u32(state_node, "wakeup-latency-us",
  42                                    &idle_state->exit_latency);
  43         if (err) {
  44                 u32 entry_latency, exit_latency;
  45 
  46                 err = of_property_read_u32(state_node, "entry-latency-us",
  47                                            &entry_latency);
  48                 if (err) {
  49                         pr_debug(" * %pOF missing entry-latency-us property\n",
  50                                  state_node);
  51                         return -EINVAL;
  52                 }
  53 
  54                 err = of_property_read_u32(state_node, "exit-latency-us",
  55                                            &exit_latency);
  56                 if (err) {
  57                         pr_debug(" * %pOF missing exit-latency-us property\n",
  58                                  state_node);
  59                         return -EINVAL;
  60                 }
  61                 /*
  62                  * If wakeup-latency-us is missing, default to entry+exit
  63                  * latencies as defined in idle states bindings
  64                  */
  65                 idle_state->exit_latency = entry_latency + exit_latency;
  66         }
  67 
  68         err = of_property_read_u32(state_node, "min-residency-us",
  69                                    &idle_state->target_residency);
  70         if (err) {
  71                 pr_debug(" * %pOF missing min-residency-us property\n",
  72                              state_node);
  73                 return -EINVAL;
  74         }
  75 
  76         err = of_property_read_string(state_node, "idle-state-name", &desc);
  77         if (err)
  78                 desc = state_node->name;
  79 
  80         idle_state->flags = 0;
  81         if (of_property_read_bool(state_node, "local-timer-stop"))
  82                 idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP;
  83         /*
  84          * TODO:
  85          *      replace with kstrdup and pointer assignment when name
  86          *      and desc become string pointers
  87          */
  88         strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1);
  89         strncpy(idle_state->desc, desc, CPUIDLE_DESC_LEN - 1);
  90         return 0;
  91 }
  92 
  93 /*
  94  * Check that the idle state is uniform across all CPUs in the CPUidle driver
  95  * cpumask
  96  */
  97 static bool idle_state_valid(struct device_node *state_node, unsigned int idx,
  98                              const cpumask_t *cpumask)
  99 {
 100         int cpu;
 101         struct device_node *cpu_node, *curr_state_node;
 102         bool valid = true;
 103 
 104         /*
 105          * Compare idle state phandles for index idx on all CPUs in the
 106          * CPUidle driver cpumask. Start from next logical cpu following
 107          * cpumask_first(cpumask) since that's the CPU state_node was
 108          * retrieved from. If a mismatch is found bail out straight
 109          * away since we certainly hit a firmware misconfiguration.
 110          */
 111         for (cpu = cpumask_next(cpumask_first(cpumask), cpumask);
 112              cpu < nr_cpu_ids; cpu = cpumask_next(cpu, cpumask)) {
 113                 cpu_node = of_cpu_device_node_get(cpu);
 114                 curr_state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
 115                                                    idx);
 116                 if (state_node != curr_state_node)
 117                         valid = false;
 118 
 119                 of_node_put(curr_state_node);
 120                 of_node_put(cpu_node);
 121                 if (!valid)
 122                         break;
 123         }
 124 
 125         return valid;
 126 }
 127 
 128 /**
 129  * dt_init_idle_driver() - Parse the DT idle states and initialize the
 130  *                         idle driver states array
 131  * @drv:          Pointer to CPU idle driver to be initialized
 132  * @matches:      Array of of_device_id match structures to search in for
 133  *                compatible idle state nodes. The data pointer for each valid
 134  *                struct of_device_id entry in the matches array must point to
 135  *                a function with the following signature, that corresponds to
 136  *                the CPUidle state enter function signature:
 137  *
 138  *                int (*)(struct cpuidle_device *dev,
 139  *                        struct cpuidle_driver *drv,
 140  *                        int index);
 141  *
 142  * @start_idx:    First idle state index to be initialized
 143  *
 144  * If DT idle states are detected and are valid the state count and states
 145  * array entries in the cpuidle driver are initialized accordingly starting
 146  * from index start_idx.
 147  *
 148  * Return: number of valid DT idle states parsed, <0 on failure
 149  */
 150 int dt_init_idle_driver(struct cpuidle_driver *drv,
 151                         const struct of_device_id *matches,
 152                         unsigned int start_idx)
 153 {
 154         struct cpuidle_state *idle_state;
 155         struct device_node *state_node, *cpu_node;
 156         const struct of_device_id *match_id;
 157         int i, err = 0;
 158         const cpumask_t *cpumask;
 159         unsigned int state_idx = start_idx;
 160 
 161         if (state_idx >= CPUIDLE_STATE_MAX)
 162                 return -EINVAL;
 163         /*
 164          * We get the idle states for the first logical cpu in the
 165          * driver mask (or cpu_possible_mask if the driver cpumask is not set)
 166          * and we check through idle_state_valid() if they are uniform
 167          * across CPUs, otherwise we hit a firmware misconfiguration.
 168          */
 169         cpumask = drv->cpumask ? : cpu_possible_mask;
 170         cpu_node = of_cpu_device_node_get(cpumask_first(cpumask));
 171 
 172         for (i = 0; ; i++) {
 173                 state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
 174                 if (!state_node)
 175                         break;
 176 
 177                 match_id = of_match_node(matches, state_node);
 178                 if (!match_id) {
 179                         err = -ENODEV;
 180                         break;
 181                 }
 182 
 183                 if (!of_device_is_available(state_node)) {
 184                         of_node_put(state_node);
 185                         continue;
 186                 }
 187 
 188                 if (!idle_state_valid(state_node, i, cpumask)) {
 189                         pr_warn("%pOF idle state not valid, bailing out\n",
 190                                 state_node);
 191                         err = -EINVAL;
 192                         break;
 193                 }
 194 
 195                 if (state_idx == CPUIDLE_STATE_MAX) {
 196                         pr_warn("State index reached static CPU idle driver states array size\n");
 197                         break;
 198                 }
 199 
 200                 idle_state = &drv->states[state_idx++];
 201                 err = init_state_node(idle_state, match_id, state_node);
 202                 if (err) {
 203                         pr_err("Parsing idle state node %pOF failed with err %d\n",
 204                                state_node, err);
 205                         err = -EINVAL;
 206                         break;
 207                 }
 208                 of_node_put(state_node);
 209         }
 210 
 211         of_node_put(state_node);
 212         of_node_put(cpu_node);
 213         if (err)
 214                 return err;
 215         /*
 216          * Update the driver state count only if some valid DT idle states
 217          * were detected
 218          */
 219         if (i)
 220                 drv->state_count = state_idx;
 221 
 222         /*
 223          * Return the number of present and valid DT idle states, which can
 224          * also be 0 on platforms with missing DT idle states or legacy DT
 225          * configuration predating the DT idle states bindings.
 226          */
 227         return i;
 228 }
 229 EXPORT_SYMBOL_GPL(dt_init_idle_driver);

/* [<][>][^][v][top][bottom][index][help] */