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