Path: blob/master/drivers/cpufreq/cpufreq_conservative.c
26278 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* drivers/cpufreq/cpufreq_conservative.c3*4* Copyright (C) 2001 Russell King5* (C) 2003 Venkatesh Pallipadi <[email protected]>.6* Jun Nakajima <[email protected]>7* (C) 2009 Alexander Clouter <[email protected]>8*/910#include <linux/slab.h>11#include "cpufreq_governor.h"1213struct cs_policy_dbs_info {14struct policy_dbs_info policy_dbs;15unsigned int down_skip;16unsigned int requested_freq;17};1819static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs)20{21return container_of(policy_dbs, struct cs_policy_dbs_info, policy_dbs);22}2324struct cs_dbs_tuners {25unsigned int down_threshold;26unsigned int freq_step;27};2829/* Conservative governor macros */30#define DEF_FREQUENCY_UP_THRESHOLD (80)31#define DEF_FREQUENCY_DOWN_THRESHOLD (20)32#define DEF_FREQUENCY_STEP (5)33#define DEF_SAMPLING_DOWN_FACTOR (1)34#define MAX_SAMPLING_DOWN_FACTOR (10)3536static inline unsigned int get_freq_step(struct cs_dbs_tuners *cs_tuners,37struct cpufreq_policy *policy)38{39unsigned int freq_step = (cs_tuners->freq_step * policy->max) / 100;4041/* max freq cannot be less than 100. But who knows... */42if (unlikely(freq_step == 0))43freq_step = DEF_FREQUENCY_STEP;4445return freq_step;46}4748/*49* Every sampling_rate, we check, if current idle time is less than 20%50* (default), then we try to increase frequency. Every sampling_rate *51* sampling_down_factor, we check, if current idle time is more than 80%52* (default), then we try to decrease frequency53*54* Frequency updates happen at minimum steps of 5% (default) of maximum55* frequency56*/57static unsigned int cs_dbs_update(struct cpufreq_policy *policy)58{59struct policy_dbs_info *policy_dbs = policy->governor_data;60struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);61unsigned int requested_freq = dbs_info->requested_freq;62struct dbs_data *dbs_data = policy_dbs->dbs_data;63struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;64unsigned int load = dbs_update(policy);65unsigned int freq_step;6667/*68* break out if we 'cannot' reduce the speed as the user might69* want freq_step to be zero70*/71if (cs_tuners->freq_step == 0)72goto out;7374/*75* If requested_freq is out of range, it is likely that the limits76* changed in the meantime, so fall back to current frequency in that77* case.78*/79if (requested_freq > policy->max || requested_freq < policy->min) {80requested_freq = policy->cur;81dbs_info->requested_freq = requested_freq;82}8384freq_step = get_freq_step(cs_tuners, policy);8586/*87* Decrease requested_freq one freq_step for each idle period that88* we didn't update the frequency.89*/90if (policy_dbs->idle_periods < UINT_MAX) {91unsigned int freq_steps = policy_dbs->idle_periods * freq_step;9293if (requested_freq > policy->min + freq_steps)94requested_freq -= freq_steps;95else96requested_freq = policy->min;9798policy_dbs->idle_periods = UINT_MAX;99}100101/* Check for frequency increase */102if (load > dbs_data->up_threshold) {103dbs_info->down_skip = 0;104105/* if we are already at full speed then break out early */106if (requested_freq == policy->max)107goto out;108109requested_freq += freq_step;110if (requested_freq > policy->max)111requested_freq = policy->max;112113__cpufreq_driver_target(policy, requested_freq,114CPUFREQ_RELATION_HE);115dbs_info->requested_freq = requested_freq;116goto out;117}118119/* if sampling_down_factor is active break out early */120if (++dbs_info->down_skip < dbs_data->sampling_down_factor)121goto out;122dbs_info->down_skip = 0;123124/* Check for frequency decrease */125if (load < cs_tuners->down_threshold) {126/*127* if we cannot reduce the frequency anymore, break out early128*/129if (requested_freq == policy->min)130goto out;131132if (requested_freq > freq_step)133requested_freq -= freq_step;134else135requested_freq = policy->min;136137__cpufreq_driver_target(policy, requested_freq,138CPUFREQ_RELATION_LE);139dbs_info->requested_freq = requested_freq;140}141142out:143return dbs_data->sampling_rate;144}145146/************************** sysfs interface ************************/147148static ssize_t sampling_down_factor_store(struct gov_attr_set *attr_set,149const char *buf, size_t count)150{151struct dbs_data *dbs_data = to_dbs_data(attr_set);152unsigned int input;153int ret;154ret = sscanf(buf, "%u", &input);155156if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)157return -EINVAL;158159dbs_data->sampling_down_factor = input;160return count;161}162163static ssize_t up_threshold_store(struct gov_attr_set *attr_set,164const char *buf, size_t count)165{166struct dbs_data *dbs_data = to_dbs_data(attr_set);167struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;168unsigned int input;169int ret;170ret = sscanf(buf, "%u", &input);171172if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)173return -EINVAL;174175dbs_data->up_threshold = input;176return count;177}178179static ssize_t down_threshold_store(struct gov_attr_set *attr_set,180const char *buf, size_t count)181{182struct dbs_data *dbs_data = to_dbs_data(attr_set);183struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;184unsigned int input;185int ret;186ret = sscanf(buf, "%u", &input);187188/* cannot be lower than 1 otherwise freq will not fall */189if (ret != 1 || input < 1 || input >= dbs_data->up_threshold)190return -EINVAL;191192cs_tuners->down_threshold = input;193return count;194}195196static ssize_t ignore_nice_load_store(struct gov_attr_set *attr_set,197const char *buf, size_t count)198{199struct dbs_data *dbs_data = to_dbs_data(attr_set);200unsigned int input;201int ret;202203ret = sscanf(buf, "%u", &input);204if (ret != 1)205return -EINVAL;206207if (input > 1)208input = 1;209210if (input == dbs_data->ignore_nice_load) /* nothing to do */211return count;212213dbs_data->ignore_nice_load = input;214215/* we need to re-evaluate prev_cpu_idle */216gov_update_cpu_data(dbs_data);217218return count;219}220221static ssize_t freq_step_store(struct gov_attr_set *attr_set, const char *buf,222size_t count)223{224struct dbs_data *dbs_data = to_dbs_data(attr_set);225struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;226unsigned int input;227int ret;228ret = sscanf(buf, "%u", &input);229230if (ret != 1)231return -EINVAL;232233if (input > 100)234input = 100;235236/*237* no need to test here if freq_step is zero as the user might actually238* want this, they would be crazy though :)239*/240cs_tuners->freq_step = input;241return count;242}243244gov_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);250251gov_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);257258static struct attribute *cs_attrs[] = {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,265NULL266};267ATTRIBUTE_GROUPS(cs);268269/************************** sysfs end ************************/270271static struct policy_dbs_info *cs_alloc(void)272{273struct cs_policy_dbs_info *dbs_info;274275dbs_info = kzalloc(sizeof(*dbs_info), GFP_KERNEL);276return dbs_info ? &dbs_info->policy_dbs : NULL;277}278279static void cs_free(struct policy_dbs_info *policy_dbs)280{281kfree(to_dbs_info(policy_dbs));282}283284static int cs_init(struct dbs_data *dbs_data)285{286struct cs_dbs_tuners *tuners;287288tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);289if (!tuners)290return -ENOMEM;291292tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;293tuners->freq_step = DEF_FREQUENCY_STEP;294dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;295dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;296dbs_data->ignore_nice_load = 0;297dbs_data->tuners = tuners;298299return 0;300}301302static void cs_exit(struct dbs_data *dbs_data)303{304kfree(dbs_data->tuners);305}306307static void cs_start(struct cpufreq_policy *policy)308{309struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);310311dbs_info->down_skip = 0;312dbs_info->requested_freq = policy->cur;313}314315static struct dbs_governor cs_governor = {316.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),317.kobj_type = { .default_groups = cs_groups },318.gov_dbs_update = cs_dbs_update,319.alloc = cs_alloc,320.free = cs_free,321.init = cs_init,322.exit = cs_exit,323.start = cs_start,324};325326#define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov)327328MODULE_AUTHOR("Alexander Clouter <[email protected]>");329MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "330"Low Latency Frequency Transition capable processors "331"optimised for use in a battery environment");332MODULE_LICENSE("GPL");333334#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE335struct cpufreq_governor *cpufreq_default_governor(void)336{337return &CPU_FREQ_GOV_CONSERVATIVE;338}339#endif340341cpufreq_governor_init(CPU_FREQ_GOV_CONSERVATIVE);342cpufreq_governor_exit(CPU_FREQ_GOV_CONSERVATIVE);343344345