linux/drivers/cpufreq/cpufreq_conservative.c
<<
>>
Prefs
   1/*
   2 *  drivers/cpufreq/cpufreq_conservative.c
   3 *
   4 *  Copyright (C)  2001 Russell King
   5 *            (C)  2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
   6 *                      Jun Nakajima <jun.nakajima@intel.com>
   7 *            (C)  2009 Alexander Clouter <alex@digriz.org.uk>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <linux/slab.h>
  15#include "cpufreq_governor.h"
  16
  17/* Conservative governor macros */
  18#define DEF_FREQUENCY_UP_THRESHOLD              (80)
  19#define DEF_FREQUENCY_DOWN_THRESHOLD            (20)
  20#define DEF_FREQUENCY_STEP                      (5)
  21#define DEF_SAMPLING_DOWN_FACTOR                (1)
  22#define MAX_SAMPLING_DOWN_FACTOR                (10)
  23
  24static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);
  25
  26static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
  27                                           struct cpufreq_policy *policy)
  28{
  29        unsigned int freq_target = (cs_tuners->freq_step * policy->max) / 100;
  30
  31        /* max freq cannot be less than 100. But who knows... */
  32        if (unlikely(freq_target == 0))
  33                freq_target = DEF_FREQUENCY_STEP;
  34
  35        return freq_target;
  36}
  37
  38/*
  39 * Every sampling_rate, we check, if current idle time is less than 20%
  40 * (default), then we try to increase frequency. Every sampling_rate *
  41 * sampling_down_factor, we check, if current idle time is more than 80%
  42 * (default), then we try to decrease frequency
  43 *
  44 * Any frequency increase takes it to the maximum frequency. Frequency reduction
  45 * happens at minimum steps of 5% (default) of maximum frequency
  46 */
  47static void cs_check_cpu(int cpu, unsigned int load)
  48{
  49        struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
  50        struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
  51        struct dbs_data *dbs_data = policy->governor_data;
  52        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
  53
  54        /*
  55         * break out if we 'cannot' reduce the speed as the user might
  56         * want freq_step to be zero
  57         */
  58        if (cs_tuners->freq_step == 0)
  59                return;
  60
  61        /* Check for frequency increase */
  62        if (load > cs_tuners->up_threshold) {
  63                dbs_info->down_skip = 0;
  64
  65                /* if we are already at full speed then break out early */
  66                if (dbs_info->requested_freq == policy->max)
  67                        return;
  68
  69                dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
  70
  71                __cpufreq_driver_target(policy, dbs_info->requested_freq,
  72                        CPUFREQ_RELATION_H);
  73                return;
  74        }
  75
  76        /* if sampling_down_factor is active break out early */
  77        if (++dbs_info->down_skip < cs_tuners->sampling_down_factor)
  78                return;
  79        dbs_info->down_skip = 0;
  80
  81        /* Check for frequency decrease */
  82        if (load < cs_tuners->down_threshold) {
  83                /*
  84                 * if we cannot reduce the frequency anymore, break out early
  85                 */
  86                if (policy->cur == policy->min)
  87                        return;
  88
  89                dbs_info->requested_freq -= get_freq_target(cs_tuners, policy);
  90
  91                __cpufreq_driver_target(policy, dbs_info->requested_freq,
  92                                CPUFREQ_RELATION_L);
  93                return;
  94        }
  95}
  96
  97static void cs_dbs_timer(struct work_struct *work)
  98{
  99        struct cs_cpu_dbs_info_s *dbs_info = container_of(work,
 100                        struct cs_cpu_dbs_info_s, cdbs.work.work);
 101        unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
 102        struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info,
 103                        cpu);
 104        struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
 105        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 106        int delay = delay_for_sampling_rate(cs_tuners->sampling_rate);
 107        bool modify_all = true;
 108
 109        mutex_lock(&core_dbs_info->cdbs.timer_mutex);
 110        if (!need_load_eval(&core_dbs_info->cdbs, cs_tuners->sampling_rate))
 111                modify_all = false;
 112        else
 113                dbs_check_cpu(dbs_data, cpu);
 114
 115        gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);
 116        mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
 117}
 118
 119static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
 120                void *data)
 121{
 122        struct cpufreq_freqs *freq = data;
 123        struct cs_cpu_dbs_info_s *dbs_info =
 124                                        &per_cpu(cs_cpu_dbs_info, freq->cpu);
 125        struct cpufreq_policy *policy;
 126
 127        if (!dbs_info->enable)
 128                return 0;
 129
 130        policy = dbs_info->cdbs.cur_policy;
 131
 132        /*
 133         * we only care if our internally tracked freq moves outside the 'valid'
 134         * ranges of frequency available to us otherwise we do not change it
 135        */
 136        if (dbs_info->requested_freq > policy->max
 137                        || dbs_info->requested_freq < policy->min)
 138                dbs_info->requested_freq = freq->new;
 139
 140        return 0;
 141}
 142
 143/************************** sysfs interface ************************/
 144static struct common_dbs_data cs_dbs_cdata;
 145
 146static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
 147                const char *buf, size_t count)
 148{
 149        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 150        unsigned int input;
 151        int ret;
 152        ret = sscanf(buf, "%u", &input);
 153
 154        if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
 155                return -EINVAL;
 156
 157        cs_tuners->sampling_down_factor = input;
 158        return count;
 159}
 160
 161static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
 162                size_t count)
 163{
 164        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 165        unsigned int input;
 166        int ret;
 167        ret = sscanf(buf, "%u", &input);
 168
 169        if (ret != 1)
 170                return -EINVAL;
 171
 172        cs_tuners->sampling_rate = max(input, dbs_data->min_sampling_rate);
 173        return count;
 174}
 175
 176static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
 177                size_t count)
 178{
 179        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 180        unsigned int input;
 181        int ret;
 182        ret = sscanf(buf, "%u", &input);
 183
 184        if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
 185                return -EINVAL;
 186
 187        cs_tuners->up_threshold = input;
 188        return count;
 189}
 190
 191static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
 192                size_t count)
 193{
 194        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 195        unsigned int input;
 196        int ret;
 197        ret = sscanf(buf, "%u", &input);
 198
 199        /* cannot be lower than 11 otherwise freq will not fall */
 200        if (ret != 1 || input < 11 || input > 100 ||
 201                        input >= cs_tuners->up_threshold)
 202                return -EINVAL;
 203
 204        cs_tuners->down_threshold = input;
 205        return count;
 206}
 207
 208static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
 209                const char *buf, size_t count)
 210{
 211        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 212        unsigned int input, j;
 213        int ret;
 214
 215        ret = sscanf(buf, "%u", &input);
 216        if (ret != 1)
 217                return -EINVAL;
 218
 219        if (input > 1)
 220                input = 1;
 221
 222        if (input == cs_tuners->ignore_nice_load) /* nothing to do */
 223                return count;
 224
 225        cs_tuners->ignore_nice_load = input;
 226
 227        /* we need to re-evaluate prev_cpu_idle */
 228        for_each_online_cpu(j) {
 229                struct cs_cpu_dbs_info_s *dbs_info;
 230                dbs_info = &per_cpu(cs_cpu_dbs_info, j);
 231                dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
 232                                        &dbs_info->cdbs.prev_cpu_wall, 0);
 233                if (cs_tuners->ignore_nice_load)
 234                        dbs_info->cdbs.prev_cpu_nice =
 235                                kcpustat_cpu(j).cpustat[CPUTIME_NICE];
 236        }
 237        return count;
 238}
 239
 240static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
 241                size_t count)
 242{
 243        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
 244        unsigned int input;
 245        int ret;
 246        ret = sscanf(buf, "%u", &input);
 247
 248        if (ret != 1)
 249                return -EINVAL;
 250
 251        if (input > 100)
 252                input = 100;
 253
 254        /*
 255         * no need to test here if freq_step is zero as the user might actually
 256         * want this, they would be crazy though :)
 257         */
 258        cs_tuners->freq_step = input;
 259        return count;
 260}
 261
 262show_store_one(cs, sampling_rate);
 263show_store_one(cs, sampling_down_factor);
 264show_store_one(cs, up_threshold);
 265show_store_one(cs, down_threshold);
 266show_store_one(cs, ignore_nice_load);
 267show_store_one(cs, freq_step);
 268declare_show_sampling_rate_min(cs);
 269
 270gov_sys_pol_attr_rw(sampling_rate);
 271gov_sys_pol_attr_rw(sampling_down_factor);
 272gov_sys_pol_attr_rw(up_threshold);
 273gov_sys_pol_attr_rw(down_threshold);
 274gov_sys_pol_attr_rw(ignore_nice_load);
 275gov_sys_pol_attr_rw(freq_step);
 276gov_sys_pol_attr_ro(sampling_rate_min);
 277
 278static struct attribute *dbs_attributes_gov_sys[] = {
 279        &sampling_rate_min_gov_sys.attr,
 280        &sampling_rate_gov_sys.attr,
 281        &sampling_down_factor_gov_sys.attr,
 282        &up_threshold_gov_sys.attr,
 283        &down_threshold_gov_sys.attr,
 284        &ignore_nice_load_gov_sys.attr,
 285        &freq_step_gov_sys.attr,
 286        NULL
 287};
 288
 289static struct attribute_group cs_attr_group_gov_sys = {
 290        .attrs = dbs_attributes_gov_sys,
 291        .name = "conservative",
 292};
 293
 294static struct attribute *dbs_attributes_gov_pol[] = {
 295        &sampling_rate_min_gov_pol.attr,
 296        &sampling_rate_gov_pol.attr,
 297        &sampling_down_factor_gov_pol.attr,
 298        &up_threshold_gov_pol.attr,
 299        &down_threshold_gov_pol.attr,
 300        &ignore_nice_load_gov_pol.attr,
 301        &freq_step_gov_pol.attr,
 302        NULL
 303};
 304
 305static struct attribute_group cs_attr_group_gov_pol = {
 306        .attrs = dbs_attributes_gov_pol,
 307        .name = "conservative",
 308};
 309
 310/************************** sysfs end ************************/
 311
 312static int cs_init(struct dbs_data *dbs_data)
 313{
 314        struct cs_dbs_tuners *tuners;
 315
 316        tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
 317        if (!tuners) {
 318                pr_err("%s: kzalloc failed\n", __func__);
 319                return -ENOMEM;
 320        }
 321
 322        tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
 323        tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
 324        tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
 325        tuners->ignore_nice_load = 0;
 326        tuners->freq_step = DEF_FREQUENCY_STEP;
 327
 328        dbs_data->tuners = tuners;
 329        dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
 330                jiffies_to_usecs(10);
 331        mutex_init(&dbs_data->mutex);
 332        return 0;
 333}
 334
 335static void cs_exit(struct dbs_data *dbs_data)
 336{
 337        kfree(dbs_data->tuners);
 338}
 339
 340define_get_cpu_dbs_routines(cs_cpu_dbs_info);
 341
 342static struct notifier_block cs_cpufreq_notifier_block = {
 343        .notifier_call = dbs_cpufreq_notifier,
 344};
 345
 346static struct cs_ops cs_ops = {
 347        .notifier_block = &cs_cpufreq_notifier_block,
 348};
 349
 350static struct common_dbs_data cs_dbs_cdata = {
 351        .governor = GOV_CONSERVATIVE,
 352        .attr_group_gov_sys = &cs_attr_group_gov_sys,
 353        .attr_group_gov_pol = &cs_attr_group_gov_pol,
 354        .get_cpu_cdbs = get_cpu_cdbs,
 355        .get_cpu_dbs_info_s = get_cpu_dbs_info_s,
 356        .gov_dbs_timer = cs_dbs_timer,
 357        .gov_check_cpu = cs_check_cpu,
 358        .gov_ops = &cs_ops,
 359        .init = cs_init,
 360        .exit = cs_exit,
 361};
 362
 363static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
 364                                   unsigned int event)
 365{
 366        return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
 367}
 368
 369#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
 370static
 371#endif
 372struct cpufreq_governor cpufreq_gov_conservative = {
 373        .name                   = "conservative",
 374        .governor               = cs_cpufreq_governor_dbs,
 375        .max_transition_latency = TRANSITION_LATENCY_LIMIT,
 376        .owner                  = THIS_MODULE,
 377};
 378
 379static int __init cpufreq_gov_dbs_init(void)
 380{
 381        return cpufreq_register_governor(&cpufreq_gov_conservative);
 382}
 383
 384static void __exit cpufreq_gov_dbs_exit(void)
 385{
 386        cpufreq_unregister_governor(&cpufreq_gov_conservative);
 387}
 388
 389MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
 390MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
 391                "Low Latency Frequency Transition capable processors "
 392                "optimised for use in a battery environment");
 393MODULE_LICENSE("GPL");
 394
 395#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
 396fs_initcall(cpufreq_gov_dbs_init);
 397#else
 398module_init(cpufreq_gov_dbs_init);
 399#endif
 400module_exit(cpufreq_gov_dbs_exit);
 401
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.