Branch data Line data Source code
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 : :
14 : : struct cs_policy_dbs_info {
15 : : struct policy_dbs_info policy_dbs;
16 : : unsigned int down_skip;
17 : : unsigned int requested_freq;
18 : : };
19 : :
20 : : static 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 : :
25 : : struct 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 : :
37 : : static inline unsigned int get_freq_step(struct cs_dbs_tuners *cs_tuners,
38 : : struct cpufreq_policy *policy)
39 : : {
40 : 0 : unsigned int freq_step = (cs_tuners->freq_step * policy->max) / 100;
41 : :
42 : : /* max freq cannot be less than 100. But who knows... */
43 [ # # ]: 0 : 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 : : */
58 : 0 : static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
59 : : {
60 : 0 : struct policy_dbs_info *policy_dbs = policy->governor_data;
61 : : struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
62 : 0 : unsigned int requested_freq = dbs_info->requested_freq;
63 : 0 : struct dbs_data *dbs_data = policy_dbs->dbs_data;
64 : 0 : struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
65 : 0 : 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 [ # # ]: 0 : 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 [ # # # # ]: 0 : if (requested_freq > policy->max || requested_freq < policy->min) {
81 : 0 : requested_freq = policy->cur;
82 : 0 : 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 [ # # ]: 0 : if (policy_dbs->idle_periods < UINT_MAX) {
92 : 0 : unsigned int freq_steps = policy_dbs->idle_periods * freq_step;
93 : :
94 [ # # ]: 0 : if (requested_freq > policy->min + freq_steps)
95 : 0 : requested_freq -= freq_steps;
96 : : else
97 : : requested_freq = policy->min;
98 : :
99 : 0 : policy_dbs->idle_periods = UINT_MAX;
100 : : }
101 : :
102 : : /* Check for frequency increase */
103 [ # # ]: 0 : if (load > dbs_data->up_threshold) {
104 : 0 : dbs_info->down_skip = 0;
105 : :
106 : : /* if we are already at full speed then break out early */
107 [ # # ]: 0 : if (requested_freq == policy->max)
108 : : goto out;
109 : :
110 : 0 : requested_freq += freq_step;
111 [ # # ]: 0 : if (requested_freq > policy->max)
112 : : requested_freq = policy->max;
113 : :
114 : 0 : __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H);
115 : 0 : dbs_info->requested_freq = requested_freq;
116 : 0 : goto out;
117 : : }
118 : :
119 : : /* if sampling_down_factor is active break out early */
120 [ # # ]: 0 : if (++dbs_info->down_skip < dbs_data->sampling_down_factor)
121 : : goto out;
122 : 0 : dbs_info->down_skip = 0;
123 : :
124 : : /* Check for frequency decrease */
125 [ # # ]: 0 : if (load < cs_tuners->down_threshold) {
126 : : /*
127 : : * if we cannot reduce the frequency anymore, break out early
128 : : */
129 [ # # ]: 0 : if (requested_freq == policy->min)
130 : : goto out;
131 : :
132 [ # # ]: 0 : if (requested_freq > freq_step)
133 : 0 : requested_freq -= freq_step;
134 : : else
135 : : requested_freq = policy->min;
136 : :
137 : 0 : __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L);
138 : 0 : dbs_info->requested_freq = requested_freq;
139 : : }
140 : :
141 : : out:
142 : 0 : return dbs_data->sampling_rate;
143 : : }
144 : :
145 : : /************************** sysfs interface ************************/
146 : :
147 : 0 : static 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 : 0 : ret = sscanf(buf, "%u", &input);
154 : :
155 [ # # # # : 0 : if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
# # ]
156 : : return -EINVAL;
157 : :
158 : 0 : dbs_data->sampling_down_factor = input;
159 : 0 : return count;
160 : : }
161 : :
162 : 0 : static 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 : 0 : struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
167 : : unsigned int input;
168 : : int ret;
169 : 0 : ret = sscanf(buf, "%u", &input);
170 : :
171 [ # # # # : 0 : if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
# # ]
172 : : return -EINVAL;
173 : :
174 : 0 : dbs_data->up_threshold = input;
175 : 0 : return count;
176 : : }
177 : :
178 : 0 : static 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 : 0 : struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
183 : : unsigned int input;
184 : : int ret;
185 : 0 : ret = sscanf(buf, "%u", &input);
186 : :
187 : : /* cannot be lower than 1 otherwise freq will not fall */
188 [ # # # # : 0 : if (ret != 1 || input < 1 || input > 100 ||
# # # # ]
189 : 0 : input >= dbs_data->up_threshold)
190 : : return -EINVAL;
191 : :
192 : 0 : cs_tuners->down_threshold = input;
193 : 0 : return count;
194 : : }
195 : :
196 : 0 : static 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 : 0 : ret = sscanf(buf, "%u", &input);
204 [ # # ]: 0 : if (ret != 1)
205 : : return -EINVAL;
206 : :
207 [ # # ]: 0 : if (input > 1)
208 : 0 : input = 1;
209 : :
210 [ # # ]: 0 : if (input == dbs_data->ignore_nice_load) /* nothing to do */
211 : 0 : return count;
212 : :
213 : 0 : dbs_data->ignore_nice_load = input;
214 : :
215 : : /* we need to re-evaluate prev_cpu_idle */
216 : 0 : gov_update_cpu_data(dbs_data);
217 : :
218 : 0 : return count;
219 : : }
220 : :
221 : 0 : static 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 : 0 : struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
226 : : unsigned int input;
227 : : int ret;
228 : 0 : ret = sscanf(buf, "%u", &input);
229 : :
230 [ # # ]: 0 : if (ret != 1)
231 : : return -EINVAL;
232 : :
233 [ # # ]: 0 : if (input > 100)
234 : 0 : 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 : 0 : cs_tuners->freq_step = input;
241 : 0 : return count;
242 : : }
243 : :
244 : 0 : gov_show_one_common(sampling_rate);
245 : 0 : gov_show_one_common(sampling_down_factor);
246 : 0 : gov_show_one_common(up_threshold);
247 : 0 : gov_show_one_common(ignore_nice_load);
248 : 0 : gov_show_one(cs, down_threshold);
249 : 0 : gov_show_one(cs, freq_step);
250 : :
251 : : gov_attr_rw(sampling_rate);
252 : : gov_attr_rw(sampling_down_factor);
253 : : gov_attr_rw(up_threshold);
254 : : gov_attr_rw(ignore_nice_load);
255 : : gov_attr_rw(down_threshold);
256 : : gov_attr_rw(freq_step);
257 : :
258 : : static 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 : :
270 : 0 : static struct policy_dbs_info *cs_alloc(void)
271 : : {
272 : : struct cs_policy_dbs_info *dbs_info;
273 : :
274 : 0 : dbs_info = kzalloc(sizeof(*dbs_info), GFP_KERNEL);
275 [ # # ]: 0 : return dbs_info ? &dbs_info->policy_dbs : NULL;
276 : : }
277 : :
278 : 0 : static void cs_free(struct policy_dbs_info *policy_dbs)
279 : : {
280 : 0 : kfree(to_dbs_info(policy_dbs));
281 : 0 : }
282 : :
283 : 0 : static int cs_init(struct dbs_data *dbs_data)
284 : : {
285 : : struct cs_dbs_tuners *tuners;
286 : :
287 : 0 : tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
288 [ # # ]: 0 : if (!tuners)
289 : : return -ENOMEM;
290 : :
291 : 0 : tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
292 : 0 : tuners->freq_step = DEF_FREQUENCY_STEP;
293 : 0 : dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
294 : 0 : dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
295 : 0 : dbs_data->ignore_nice_load = 0;
296 : 0 : dbs_data->tuners = tuners;
297 : :
298 : 0 : return 0;
299 : : }
300 : :
301 : 0 : static void cs_exit(struct dbs_data *dbs_data)
302 : : {
303 : 0 : kfree(dbs_data->tuners);
304 : 0 : }
305 : :
306 : 0 : static void cs_start(struct cpufreq_policy *policy)
307 : : {
308 : 0 : struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
309 : :
310 : 0 : dbs_info->down_skip = 0;
311 : 0 : dbs_info->requested_freq = policy->cur;
312 : 0 : }
313 : :
314 : : static 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 : :
327 : 207 : static int __init cpufreq_gov_dbs_init(void)
328 : : {
329 : 207 : return cpufreq_register_governor(CPU_FREQ_GOV_CONSERVATIVE);
330 : : }
331 : :
332 : 0 : static void __exit cpufreq_gov_dbs_exit(void)
333 : : {
334 : 0 : cpufreq_unregister_governor(CPU_FREQ_GOV_CONSERVATIVE);
335 : 0 : }
336 : :
337 : : MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>");
338 : : MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for "
339 : : "Low Latency Frequency Transition capable processors "
340 : : "optimised for use in a battery environment");
341 : : MODULE_LICENSE("GPL");
342 : :
343 : : #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
344 : : struct cpufreq_governor *cpufreq_default_governor(void)
345 : : {
346 : : return CPU_FREQ_GOV_CONSERVATIVE;
347 : : }
348 : :
349 : : fs_initcall(cpufreq_gov_dbs_init);
350 : : #else
351 : : module_init(cpufreq_gov_dbs_init);
352 : : #endif
353 : : module_exit(cpufreq_gov_dbs_exit);
|