root/kernel/power/energy_model.c

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

DEFINITIONS

This source file includes following definitions.
  1. em_debug_create_cs
  2. em_debug_cpus_show
  3. em_debug_create_pd
  4. em_debug_init
  5. em_debug_create_pd
  6. em_create_pd
  7. em_cpu_get
  8. em_register_perf_domain

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Energy Model of CPUs
   4  *
   5  * Copyright (c) 2018, Arm ltd.
   6  * Written by: Quentin Perret, Arm ltd.
   7  */
   8 
   9 #define pr_fmt(fmt) "energy_model: " fmt
  10 
  11 #include <linux/cpu.h>
  12 #include <linux/cpumask.h>
  13 #include <linux/debugfs.h>
  14 #include <linux/energy_model.h>
  15 #include <linux/sched/topology.h>
  16 #include <linux/slab.h>
  17 
  18 /* Mapping of each CPU to the performance domain to which it belongs. */
  19 static DEFINE_PER_CPU(struct em_perf_domain *, em_data);
  20 
  21 /*
  22  * Mutex serializing the registrations of performance domains and letting
  23  * callbacks defined by drivers sleep.
  24  */
  25 static DEFINE_MUTEX(em_pd_mutex);
  26 
  27 #ifdef CONFIG_DEBUG_FS
  28 static struct dentry *rootdir;
  29 
  30 static void em_debug_create_cs(struct em_cap_state *cs, struct dentry *pd)
  31 {
  32         struct dentry *d;
  33         char name[24];
  34 
  35         snprintf(name, sizeof(name), "cs:%lu", cs->frequency);
  36 
  37         /* Create per-cs directory */
  38         d = debugfs_create_dir(name, pd);
  39         debugfs_create_ulong("frequency", 0444, d, &cs->frequency);
  40         debugfs_create_ulong("power", 0444, d, &cs->power);
  41         debugfs_create_ulong("cost", 0444, d, &cs->cost);
  42 }
  43 
  44 static int em_debug_cpus_show(struct seq_file *s, void *unused)
  45 {
  46         seq_printf(s, "%*pbl\n", cpumask_pr_args(to_cpumask(s->private)));
  47 
  48         return 0;
  49 }
  50 DEFINE_SHOW_ATTRIBUTE(em_debug_cpus);
  51 
  52 static void em_debug_create_pd(struct em_perf_domain *pd, int cpu)
  53 {
  54         struct dentry *d;
  55         char name[8];
  56         int i;
  57 
  58         snprintf(name, sizeof(name), "pd%d", cpu);
  59 
  60         /* Create the directory of the performance domain */
  61         d = debugfs_create_dir(name, rootdir);
  62 
  63         debugfs_create_file("cpus", 0444, d, pd->cpus, &em_debug_cpus_fops);
  64 
  65         /* Create a sub-directory for each capacity state */
  66         for (i = 0; i < pd->nr_cap_states; i++)
  67                 em_debug_create_cs(&pd->table[i], d);
  68 }
  69 
  70 static int __init em_debug_init(void)
  71 {
  72         /* Create /sys/kernel/debug/energy_model directory */
  73         rootdir = debugfs_create_dir("energy_model", NULL);
  74 
  75         return 0;
  76 }
  77 core_initcall(em_debug_init);
  78 #else /* CONFIG_DEBUG_FS */
  79 static void em_debug_create_pd(struct em_perf_domain *pd, int cpu) {}
  80 #endif
  81 static struct em_perf_domain *em_create_pd(cpumask_t *span, int nr_states,
  82                                                 struct em_data_callback *cb)
  83 {
  84         unsigned long opp_eff, prev_opp_eff = ULONG_MAX;
  85         unsigned long power, freq, prev_freq = 0;
  86         int i, ret, cpu = cpumask_first(span);
  87         struct em_cap_state *table;
  88         struct em_perf_domain *pd;
  89         u64 fmax;
  90 
  91         if (!cb->active_power)
  92                 return NULL;
  93 
  94         pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL);
  95         if (!pd)
  96                 return NULL;
  97 
  98         table = kcalloc(nr_states, sizeof(*table), GFP_KERNEL);
  99         if (!table)
 100                 goto free_pd;
 101 
 102         /* Build the list of capacity states for this performance domain */
 103         for (i = 0, freq = 0; i < nr_states; i++, freq++) {
 104                 /*
 105                  * active_power() is a driver callback which ceils 'freq' to
 106                  * lowest capacity state of 'cpu' above 'freq' and updates
 107                  * 'power' and 'freq' accordingly.
 108                  */
 109                 ret = cb->active_power(&power, &freq, cpu);
 110                 if (ret) {
 111                         pr_err("pd%d: invalid cap. state: %d\n", cpu, ret);
 112                         goto free_cs_table;
 113                 }
 114 
 115                 /*
 116                  * We expect the driver callback to increase the frequency for
 117                  * higher capacity states.
 118                  */
 119                 if (freq <= prev_freq) {
 120                         pr_err("pd%d: non-increasing freq: %lu\n", cpu, freq);
 121                         goto free_cs_table;
 122                 }
 123 
 124                 /*
 125                  * The power returned by active_state() is expected to be
 126                  * positive, in milli-watts and to fit into 16 bits.
 127                  */
 128                 if (!power || power > EM_CPU_MAX_POWER) {
 129                         pr_err("pd%d: invalid power: %lu\n", cpu, power);
 130                         goto free_cs_table;
 131                 }
 132 
 133                 table[i].power = power;
 134                 table[i].frequency = prev_freq = freq;
 135 
 136                 /*
 137                  * The hertz/watts efficiency ratio should decrease as the
 138                  * frequency grows on sane platforms. But this isn't always
 139                  * true in practice so warn the user if a higher OPP is more
 140                  * power efficient than a lower one.
 141                  */
 142                 opp_eff = freq / power;
 143                 if (opp_eff >= prev_opp_eff)
 144                         pr_warn("pd%d: hertz/watts ratio non-monotonically decreasing: em_cap_state %d >= em_cap_state%d\n",
 145                                         cpu, i, i - 1);
 146                 prev_opp_eff = opp_eff;
 147         }
 148 
 149         /* Compute the cost of each capacity_state. */
 150         fmax = (u64) table[nr_states - 1].frequency;
 151         for (i = 0; i < nr_states; i++) {
 152                 table[i].cost = div64_u64(fmax * table[i].power,
 153                                           table[i].frequency);
 154         }
 155 
 156         pd->table = table;
 157         pd->nr_cap_states = nr_states;
 158         cpumask_copy(to_cpumask(pd->cpus), span);
 159 
 160         em_debug_create_pd(pd, cpu);
 161 
 162         return pd;
 163 
 164 free_cs_table:
 165         kfree(table);
 166 free_pd:
 167         kfree(pd);
 168 
 169         return NULL;
 170 }
 171 
 172 /**
 173  * em_cpu_get() - Return the performance domain for a CPU
 174  * @cpu : CPU to find the performance domain for
 175  *
 176  * Return: the performance domain to which 'cpu' belongs, or NULL if it doesn't
 177  * exist.
 178  */
 179 struct em_perf_domain *em_cpu_get(int cpu)
 180 {
 181         return READ_ONCE(per_cpu(em_data, cpu));
 182 }
 183 EXPORT_SYMBOL_GPL(em_cpu_get);
 184 
 185 /**
 186  * em_register_perf_domain() - Register the Energy Model of a performance domain
 187  * @span        : Mask of CPUs in the performance domain
 188  * @nr_states   : Number of capacity states to register
 189  * @cb          : Callback functions providing the data of the Energy Model
 190  *
 191  * Create Energy Model tables for a performance domain using the callbacks
 192  * defined in cb.
 193  *
 194  * If multiple clients register the same performance domain, all but the first
 195  * registration will be ignored.
 196  *
 197  * Return 0 on success
 198  */
 199 int em_register_perf_domain(cpumask_t *span, unsigned int nr_states,
 200                                                 struct em_data_callback *cb)
 201 {
 202         unsigned long cap, prev_cap = 0;
 203         struct em_perf_domain *pd;
 204         int cpu, ret = 0;
 205 
 206         if (!span || !nr_states || !cb)
 207                 return -EINVAL;
 208 
 209         /*
 210          * Use a mutex to serialize the registration of performance domains and
 211          * let the driver-defined callback functions sleep.
 212          */
 213         mutex_lock(&em_pd_mutex);
 214 
 215         for_each_cpu(cpu, span) {
 216                 /* Make sure we don't register again an existing domain. */
 217                 if (READ_ONCE(per_cpu(em_data, cpu))) {
 218                         ret = -EEXIST;
 219                         goto unlock;
 220                 }
 221 
 222                 /*
 223                  * All CPUs of a domain must have the same micro-architecture
 224                  * since they all share the same table.
 225                  */
 226                 cap = arch_scale_cpu_capacity(cpu);
 227                 if (prev_cap && prev_cap != cap) {
 228                         pr_err("CPUs of %*pbl must have the same capacity\n",
 229                                                         cpumask_pr_args(span));
 230                         ret = -EINVAL;
 231                         goto unlock;
 232                 }
 233                 prev_cap = cap;
 234         }
 235 
 236         /* Create the performance domain and add it to the Energy Model. */
 237         pd = em_create_pd(span, nr_states, cb);
 238         if (!pd) {
 239                 ret = -EINVAL;
 240                 goto unlock;
 241         }
 242 
 243         for_each_cpu(cpu, span) {
 244                 /*
 245                  * The per-cpu array can be read concurrently from em_cpu_get().
 246                  * The barrier enforces the ordering needed to make sure readers
 247                  * can only access well formed em_perf_domain structs.
 248                  */
 249                 smp_store_release(per_cpu_ptr(&em_data, cpu), pd);
 250         }
 251 
 252         pr_debug("Created perf domain %*pbl\n", cpumask_pr_args(span));
 253 unlock:
 254         mutex_unlock(&em_pd_mutex);
 255 
 256         return ret;
 257 }
 258 EXPORT_SYMBOL_GPL(em_register_perf_domain);

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