linux/drivers/cpufreq/cpufreq_conservative.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  drivers/cpufreq/cpufreq_conservative.c
   4 *
   5 *  Copyright (C)  2001 Russell King
   6 *            (C)  2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
   7 *                      Jun Nakajima <jun.nakajima@intel.com>
   8 *            (C)  2009 Alexander Clouter <alex@digriz.org.uk>
   9 */
  10
  11#include <linux/slab.h>
  12#include "cpufreq_governor.h"
  13
  14struct cs_policy_dbs_info {
  15        struct policy_dbs_info policy_dbs;
  16        unsigned int down_skip;
  17        unsigned int requested_freq;
  18};
  19
  20static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs)
  21{
  22        return container_of(policy_dbs, struct cs_policy_dbs_info, policy_dbs);
  23}
  24
  25struct cs_dbs_tuners {
  26        unsigned int down_threshold;
  27        unsigned int freq_step;
  28};
  29
  30/* Conservative governor macros */
  31#define DEF_FREQUENCY_UP_THRESHOLD              (80)
  32#define DEF_FREQUENCY_DOWN_THRESHOLD            (20)
  33#define DEF_FREQUENCY_STEP                      (5)
  34#define DEF_SAMPLING_DOWN_FACTOR                (1)
  35#define MAX_SAMPLING_DOWN_FACTOR                (10)
  36
  37static inline unsigned int get_freq_step(struct cs_dbs_tuners *cs_tuners,
  38                                         struct cpufreq_policy *policy)
  39{
  40        unsigned int freq_step = (cs_tuners->freq_step * policy->max) / 100;
  41
  42        /* max freq cannot be less than 100. But who knows... */
  43        if (unlikely(freq_step == 0))
  44                freq_step = DEF_FREQUENCY_STEP;
  45
  46        return freq_step;
  47}
  48
  49/*
  50 * Every sampling_rate, we check, if current idle time is less than 20%
  51 * (default), then we try to increase frequency. Every sampling_rate *
  52 * sampling_down_factor, we check, if current idle time is more than 80%
  53 * (default), then we try to decrease frequency
  54 *
  55 * Frequency updates happen at minimum steps of 5% (default) of maximum
  56 * frequency
  57 */
  58static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
  59{
  60        struct policy_dbs_info *policy_dbs = policy->governor_data;
  61        struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
  62        unsigned int requested_freq = dbs_info->requested_freq;
  63        struct dbs_data *dbs_data = policy_dbs->dbs_data;
  64        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
  65        unsigned int load = dbs_update(policy);
  66        unsigned int freq_step;
  67
  68        /*
  69         * break out if we 'cannot' reduce the speed as the user might
  70         * want freq_step to be zero
  71         */
  72        if (cs_tuners->freq_step == 0)
  73                goto out;
  74
  75        /*
  76         * If requested_freq is out of range, it is likely that the limits
  77         * changed in the meantime, so fall back to current frequency in that
  78         * case.
  79         */
  80        if (requested_freq > policy->max || requested_freq < policy->min) {
  81                requested_freq = policy->cur;
  82                dbs_info->requested_freq = requested_freq;
  83        }
  84
  85        freq_step = get_freq_step(cs_tuners, policy);
  86
  87        /*
  88         * Decrease requested_freq one freq_step for each idle period that
  89         * we didn't update the frequency.
  90         */
  91        if (policy_dbs->idle_periods < UINT_MAX) {
  92                unsigned int freq_steps = policy_dbs->idle_periods * freq_step;
  93
  94                if (requested_freq > policy->min + freq_steps)
  95                        requested_freq -= freq_steps;
  96                else
  97                        requested_freq = policy->min;
  98
  99                policy_dbs->idle_periods = UINT_MAX;
 100        }
 101
 102        /* Check for frequency increase */
 103        if (load > dbs_data->up_threshold) {
 104                dbs_info->down_skip = 0;
 105
 106                /* if we are already at full speed then break out early */
 107                if (requested_freq == policy->max)
 108                        goto out;
 109
 110                requested_freq += freq_step;
 111                if (requested_freq > policy->max)
 112                        requested_freq = policy->max;
 113
 114                __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H);
 115                dbs_info->requested_freq = requested_freq;
 116                goto out;
 117        }
 118
 119        /* if sampling_down_factor is active break out early */
 120        if (++dbs_info->down_skip < dbs_data->sampling_down_factor)
 121                goto out;
 122        dbs_info->down_skip = 0;
 123
 124        /* Check for frequency decrease */
 125        if (load < cs_tuners->down_threshold) {
 126                /*
 127                 * if we cannot reduce the frequency anymore, break out early
 128                 */
 129                if (requested_freq == policy->min)
 130                        goto out;
 131
 132                if (requested_freq > freq_step)
 133                        requested_freq -= freq_step;
 134                else
 135                        requested_freq = policy->min;
 136
 137                __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L);
 138                dbs_info->requested_freq = requested_freq;
 139        }
 140
 141 out:
 142        return dbs_data->sampling_rate;
 143}
 144
 145/************************** sysfs interface ************************/
 146
 147static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set,
 148                                          const char *buf, size_t count)
 149{
 150        struct dbs_data *dbs_data = to_dbs_data(attr_set);
 151        unsigned int input;
 152        int ret;
 153        ret = sscanf(buf, "%u", &input);
 154
 155        if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
 156                return -EINVAL;
 157
 158        dbs_data->sampling_down_factor = input;
 159        return count;
 160}
 161
 162static ssize_t store_up_threshold(struct gov_attr_set *attr_set,
 163                                  const char *buf, size_t count)
 164{
 165        struct dbs_data *dbs_data = to_dbs_data(attr_set);
 166        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 167        unsigned int input;
 168        int ret;
 169        ret = sscanf(buf, "%u", &input);
 170
 171        if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
 172                return -EINVAL;
 173
 174        dbs_data->up_threshold = input;
 175        return count;
 176}
 177
 178static ssize_t store_down_threshold(struct gov_attr_set *attr_set,
 179                                    const char *buf, size_t count)
 180{
 181        struct dbs_data *dbs_data = to_dbs_data(attr_set);
 182        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 183        unsigned int input;
 184        int ret;
 185        ret = sscanf(buf, "%u", &input);
 186
 187        /* cannot be lower than 1 otherwise freq will not fall */
 188        if (ret != 1 || input < 1 || input > 100 ||
 189                        input >= dbs_data->up_threshold)
 190                return -EINVAL;
 191
 192        cs_tuners->down_threshold = input;
 193        return count;
 194}
 195
 196static ssize_t store_ignore_nice_load(struct gov_attr_set *attr_set,
 197                                      const char *buf, size_t count)
 198{
 199        struct dbs_data *dbs_data = to_dbs_data(attr_set);
 200        unsigned int input;
 201        int ret;
 202
 203        ret = sscanf(buf, "%u", &input);
 204        if (ret != 1)
 205                return -EINVAL;
 206
 207        if (input > 1)
 208                input = 1;
 209
 210        if (input == dbs_data->ignore_nice_load) /* nothing to do */
 211                return count;
 212
 213        dbs_data->ignore_nice_load = input;
 214
 215        /* we need to re-evaluate prev_cpu_idle */
 216        gov_update_cpu_data(dbs_data);
 217
 218        return count;
 219}
 220
 221static ssize_t store_freq_step(struct gov_attr_set *attr_set, const char *buf,
 222                               size_t count)
 223{
 224        struct dbs_data *dbs_data = to_dbs_data(attr_set);
 225        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 226        unsigned int input;
 227        int ret;
 228        ret = sscanf(buf, "%u", &input);
 229
 230        if (ret != 1)
 231                return -EINVAL;
 232
 233        if (input > 100)
 234                input = 100;
 235
 236        /*
 237         * no need to test here if freq_step is zero as the user might actually
 238         * want this, they would be crazy though :)
 239         */
 240        cs_tuners->freq_step = input;
 241        return count;
 242}
 243
 244gov_show_one_common(sampling_rate);
 245gov_show_one_common(sampling_down_factor);
 246gov_show_one_common(up_threshold);
 247gov_show_one_common(ignore_nice_load);
 248gov_show_one(cs, down_threshold);
 249gov_show_one(cs, freq_step);
 250
 251gov_attr_rw(sampling_rate);
 252gov_attr_rw(sampling_down_factor);
 253gov_attr_rw(up_threshold);
 254gov_attr_rw(ignore_nice_load);
 255gov_attr_rw(down_threshold);
 256gov_attr_rw(freq_step);
 257
 258static struct attribute *cs_attributes[] = {
 259        &sampling_rate.attr,
 260        &sampling_down_factor.attr,
 261        &up_threshold.attr,
 262        &down_threshold.attr,
 263        &ignore_nice_load.attr,
 264        &freq_step.attr,
 265        NULL
 266};
 267
 268/************************** sysfs end ************************/
 269
 270static struct policy_dbs_info *cs_alloc(void)
 271{
 272        struct cs_policy_dbs_info *dbs_info;
 273
 274        dbs_info = kzalloc(sizeof(*dbs_info), GFP_KERNEL);
 275        return dbs_info ? &dbs_info->policy_dbs : NULL;
 276}
 277
 278static void cs_free(struct policy_dbs_info *policy_dbs)
 279{
 280        kfree(to_dbs_info(policy_dbs));
 281}
 282
 283static int cs_init(struct dbs_data *dbs_data)
 284{
 285        struct cs_dbs_tuners *tuners;
 286
 287        tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
 288        if (!tuners)
 289                return -ENOMEM;
 290
 291        tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
 292        tuners->freq_step = DEF_FREQUENCY_STEP;
 293        dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
 294        dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
 295        dbs_data->ignore_nice_load = 0;
 296        dbs_data->tuners = tuners;
 297
 298        return 0;
 299}
 300
 301static void cs_exit(struct dbs_data *dbs_data)
 302{
 303        kfree(dbs_data->tuners);
 304}
 305
 306static void cs_start(struct cpufreq_policy *policy)
 307{
 308        struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
 309
 310        dbs_info->down_skip = 0;
 311        dbs_info->requested_freq = policy->cur;
 312}
 313
 314static struct dbs_governor cs_governor = {
 315        .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
 316        .kobj_type = { .default_attrs = cs_attributes },
 317        .gov_dbs_update = cs_dbs_update,
 318        .alloc = cs_alloc,
 319        .free = cs_free,
 320        .init = cs_init,
 321        .exit = cs_exit,
 322        .start = cs_start,
 323};
 324
 325#define CPU_FREQ_GOV_CONSERVATIVE       (cs_governor.gov)
 326
 327MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
 328MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
 329                "Low Latency Frequency Transition capable processors "
 330                "optimised for use in a battery environment");
 331MODULE_LICENSE("GPL");
 332
 333#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
 334struct cpufreq_governor *cpufreq_default_governor(void)
 335{
 336        return &CPU_FREQ_GOV_CONSERVATIVE;
 337}
 338#endif
 339
 340cpufreq_governor_init(CPU_FREQ_GOV_CONSERVATIVE);
 341cpufreq_governor_exit(CPU_FREQ_GOV_CONSERVATIVE);
 342