]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * drivers/cpufreq/cpufreq_ondemand.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 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
4471a34f VK |
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
14 | ||
5ff0a268 | 15 | #include <linux/cpu.h> |
4471a34f | 16 | #include <linux/percpu-defs.h> |
4d5dcc42 | 17 | #include <linux/slab.h> |
80800913 | 18 | #include <linux/tick.h> |
4471a34f | 19 | #include "cpufreq_governor.h" |
1da177e4 | 20 | |
06eb09d1 | 21 | /* On-demand governor macros */ |
1da177e4 | 22 | #define DEF_FREQUENCY_UP_THRESHOLD (80) |
3f78a9f7 DN |
23 | #define DEF_SAMPLING_DOWN_FACTOR (1) |
24 | #define MAX_SAMPLING_DOWN_FACTOR (100000) | |
80800913 | 25 | #define MICRO_FREQUENCY_UP_THRESHOLD (95) |
cef9615a | 26 | #define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000) |
c29f1403 | 27 | #define MIN_FREQUENCY_UP_THRESHOLD (11) |
1da177e4 LT |
28 | #define MAX_FREQUENCY_UP_THRESHOLD (100) |
29 | ||
4471a34f | 30 | static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info); |
1da177e4 | 31 | |
fb30809e JS |
32 | static struct od_ops od_ops; |
33 | ||
c2837558 JS |
34 | static unsigned int default_powersave_bias; |
35 | ||
4471a34f | 36 | static void ondemand_powersave_bias_init_cpu(int cpu) |
6b8fcd90 | 37 | { |
4471a34f | 38 | struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); |
6b8fcd90 | 39 | |
4471a34f VK |
40 | dbs_info->freq_table = cpufreq_frequency_get_table(cpu); |
41 | dbs_info->freq_lo = 0; | |
42 | } | |
6b8fcd90 | 43 | |
4471a34f VK |
44 | /* |
45 | * Not all CPUs want IO time to be accounted as busy; this depends on how | |
46 | * efficient idling at a higher frequency/voltage is. | |
47 | * Pavel Machek says this is not so for various generations of AMD and old | |
48 | * Intel systems. | |
06eb09d1 | 49 | * Mike Chan (android.com) claims this is also not true for ARM. |
4471a34f VK |
50 | * Because of this, whitelist specific known (series) of CPUs by default, and |
51 | * leave all others up to the user. | |
52 | */ | |
53 | static int should_io_be_busy(void) | |
54 | { | |
55 | #if defined(CONFIG_X86) | |
56 | /* | |
06eb09d1 | 57 | * For Intel, Core 2 (model 15) and later have an efficient idle. |
4471a34f VK |
58 | */ |
59 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && | |
60 | boot_cpu_data.x86 == 6 && | |
61 | boot_cpu_data.x86_model >= 15) | |
62 | return 1; | |
63 | #endif | |
64 | return 0; | |
6b8fcd90 AV |
65 | } |
66 | ||
05ca0350 AS |
67 | /* |
68 | * Find right freq to be set now with powersave_bias on. | |
69 | * Returns the freq_hi to be used right now and will set freq_hi_jiffies, | |
70 | * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. | |
71 | */ | |
fb30809e | 72 | static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, |
4471a34f | 73 | unsigned int freq_next, unsigned int relation) |
05ca0350 AS |
74 | { |
75 | unsigned int freq_req, freq_reduc, freq_avg; | |
76 | unsigned int freq_hi, freq_lo; | |
77 | unsigned int index = 0; | |
78 | unsigned int jiffies_total, jiffies_hi, jiffies_lo; | |
4471a34f | 79 | struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, |
245b2e70 | 80 | policy->cpu); |
bc505475 RW |
81 | struct policy_dbs_info *policy_dbs = policy->governor_data; |
82 | struct dbs_data *dbs_data = policy_dbs->dbs_data; | |
4d5dcc42 | 83 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
05ca0350 AS |
84 | |
85 | if (!dbs_info->freq_table) { | |
86 | dbs_info->freq_lo = 0; | |
87 | dbs_info->freq_lo_jiffies = 0; | |
88 | return freq_next; | |
89 | } | |
90 | ||
91 | cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, | |
92 | relation, &index); | |
93 | freq_req = dbs_info->freq_table[index].frequency; | |
4d5dcc42 | 94 | freq_reduc = freq_req * od_tuners->powersave_bias / 1000; |
05ca0350 AS |
95 | freq_avg = freq_req - freq_reduc; |
96 | ||
97 | /* Find freq bounds for freq_avg in freq_table */ | |
98 | index = 0; | |
99 | cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, | |
100 | CPUFREQ_RELATION_H, &index); | |
101 | freq_lo = dbs_info->freq_table[index].frequency; | |
102 | index = 0; | |
103 | cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg, | |
104 | CPUFREQ_RELATION_L, &index); | |
105 | freq_hi = dbs_info->freq_table[index].frequency; | |
106 | ||
107 | /* Find out how long we have to be in hi and lo freqs */ | |
108 | if (freq_hi == freq_lo) { | |
109 | dbs_info->freq_lo = 0; | |
110 | dbs_info->freq_lo_jiffies = 0; | |
111 | return freq_lo; | |
112 | } | |
ff4b1789 | 113 | jiffies_total = usecs_to_jiffies(dbs_data->sampling_rate); |
05ca0350 AS |
114 | jiffies_hi = (freq_avg - freq_lo) * jiffies_total; |
115 | jiffies_hi += ((freq_hi - freq_lo) / 2); | |
116 | jiffies_hi /= (freq_hi - freq_lo); | |
117 | jiffies_lo = jiffies_total - jiffies_hi; | |
118 | dbs_info->freq_lo = freq_lo; | |
119 | dbs_info->freq_lo_jiffies = jiffies_lo; | |
120 | dbs_info->freq_hi_jiffies = jiffies_hi; | |
121 | return freq_hi; | |
122 | } | |
123 | ||
124 | static void ondemand_powersave_bias_init(void) | |
125 | { | |
126 | int i; | |
127 | for_each_online_cpu(i) { | |
5a75c828 | 128 | ondemand_powersave_bias_init_cpu(i); |
05ca0350 AS |
129 | } |
130 | } | |
131 | ||
3a3e9e06 | 132 | static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) |
4471a34f | 133 | { |
bc505475 RW |
134 | struct policy_dbs_info *policy_dbs = policy->governor_data; |
135 | struct dbs_data *dbs_data = policy_dbs->dbs_data; | |
4d5dcc42 VK |
136 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
137 | ||
138 | if (od_tuners->powersave_bias) | |
3a3e9e06 | 139 | freq = od_ops.powersave_bias_target(policy, freq, |
fb30809e | 140 | CPUFREQ_RELATION_H); |
3a3e9e06 | 141 | else if (policy->cur == policy->max) |
4471a34f | 142 | return; |
0e625ac1 | 143 | |
3a3e9e06 | 144 | __cpufreq_driver_target(policy, freq, od_tuners->powersave_bias ? |
4471a34f VK |
145 | CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); |
146 | } | |
147 | ||
148 | /* | |
149 | * Every sampling_rate, we check, if current idle time is less than 20% | |
dfa5bb62 SK |
150 | * (default), then we try to increase frequency. Else, we adjust the frequency |
151 | * proportional to load. | |
4471a34f | 152 | */ |
dfa5bb62 | 153 | static void od_check_cpu(int cpu, unsigned int load) |
1da177e4 | 154 | { |
4471a34f | 155 | struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); |
bc505475 RW |
156 | struct policy_dbs_info *policy_dbs = dbs_info->cdbs.policy_dbs; |
157 | struct cpufreq_policy *policy = policy_dbs->policy; | |
158 | struct dbs_data *dbs_data = policy_dbs->dbs_data; | |
4d5dcc42 | 159 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
4471a34f VK |
160 | |
161 | dbs_info->freq_lo = 0; | |
162 | ||
163 | /* Check for frequency increase */ | |
ff4b1789 | 164 | if (load > dbs_data->up_threshold) { |
4471a34f VK |
165 | /* If switching to max speed, apply sampling_down_factor */ |
166 | if (policy->cur < policy->max) | |
ff4b1789 | 167 | dbs_info->rate_mult = dbs_data->sampling_down_factor; |
4471a34f | 168 | dbs_freq_increase(policy, policy->max); |
dfa5bb62 SK |
169 | } else { |
170 | /* Calculate the next frequency proportional to load */ | |
6393d6a1 SK |
171 | unsigned int freq_next, min_f, max_f; |
172 | ||
173 | min_f = policy->cpuinfo.min_freq; | |
174 | max_f = policy->cpuinfo.max_freq; | |
175 | freq_next = min_f + load * (max_f - min_f) / 100; | |
4471a34f VK |
176 | |
177 | /* No longer fully busy, reset rate_mult */ | |
178 | dbs_info->rate_mult = 1; | |
179 | ||
4d5dcc42 | 180 | if (!od_tuners->powersave_bias) { |
4471a34f | 181 | __cpufreq_driver_target(policy, freq_next, |
6393d6a1 | 182 | CPUFREQ_RELATION_C); |
fb30809e | 183 | return; |
4471a34f | 184 | } |
fb30809e JS |
185 | |
186 | freq_next = od_ops.powersave_bias_target(policy, freq_next, | |
187 | CPUFREQ_RELATION_L); | |
6393d6a1 | 188 | __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_C); |
4471a34f | 189 | } |
1da177e4 LT |
190 | } |
191 | ||
9be4fd2c | 192 | static unsigned int od_dbs_timer(struct cpufreq_policy *policy) |
4471a34f | 193 | { |
bc505475 RW |
194 | struct policy_dbs_info *policy_dbs = policy->governor_data; |
195 | struct dbs_data *dbs_data = policy_dbs->dbs_data; | |
d10b5eb5 | 196 | struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); |
a23d6d18 | 197 | int delay, sample_type = dbs_info->sample_type; |
4447266b | 198 | |
4471a34f | 199 | /* Common NORMAL_SAMPLE setup */ |
43e0ee36 | 200 | dbs_info->sample_type = OD_NORMAL_SAMPLE; |
4471a34f | 201 | if (sample_type == OD_SUB_SAMPLE) { |
43e0ee36 VK |
202 | delay = dbs_info->freq_lo_jiffies; |
203 | __cpufreq_driver_target(policy, dbs_info->freq_lo, | |
42994af6 | 204 | CPUFREQ_RELATION_H); |
4471a34f | 205 | } else { |
d10b5eb5 | 206 | dbs_check_cpu(policy); |
43e0ee36 | 207 | if (dbs_info->freq_lo) { |
4471a34f | 208 | /* Setup timer for SUB_SAMPLE */ |
43e0ee36 VK |
209 | dbs_info->sample_type = OD_SUB_SAMPLE; |
210 | delay = dbs_info->freq_hi_jiffies; | |
a23d6d18 VK |
211 | } else { |
212 | delay = delay_for_sampling_rate(dbs_data->sampling_rate | |
213 | * dbs_info->rate_mult); | |
4471a34f VK |
214 | } |
215 | } | |
216 | ||
43e0ee36 | 217 | return delay; |
da53d61e FB |
218 | } |
219 | ||
4471a34f | 220 | /************************** sysfs interface ************************/ |
7bdad34d | 221 | static struct dbs_governor od_dbs_gov; |
1da177e4 | 222 | |
4d5dcc42 VK |
223 | static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf, |
224 | size_t count) | |
19379b11 | 225 | { |
4d5dcc42 | 226 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
19379b11 AV |
227 | unsigned int input; |
228 | int ret; | |
9366d840 | 229 | unsigned int j; |
19379b11 AV |
230 | |
231 | ret = sscanf(buf, "%u", &input); | |
232 | if (ret != 1) | |
233 | return -EINVAL; | |
4d5dcc42 | 234 | od_tuners->io_is_busy = !!input; |
9366d840 SK |
235 | |
236 | /* we need to re-evaluate prev_cpu_idle */ | |
237 | for_each_online_cpu(j) { | |
238 | struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, | |
239 | j); | |
240 | dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, | |
241 | &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy); | |
242 | } | |
19379b11 AV |
243 | return count; |
244 | } | |
245 | ||
4d5dcc42 VK |
246 | static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf, |
247 | size_t count) | |
1da177e4 LT |
248 | { |
249 | unsigned int input; | |
250 | int ret; | |
ffac80e9 | 251 | ret = sscanf(buf, "%u", &input); |
1da177e4 | 252 | |
32ee8c3e | 253 | if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || |
c29f1403 | 254 | input < MIN_FREQUENCY_UP_THRESHOLD) { |
1da177e4 LT |
255 | return -EINVAL; |
256 | } | |
4bd4e428 | 257 | |
ff4b1789 | 258 | dbs_data->up_threshold = input; |
1da177e4 LT |
259 | return count; |
260 | } | |
261 | ||
4d5dcc42 VK |
262 | static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data, |
263 | const char *buf, size_t count) | |
3f78a9f7 DN |
264 | { |
265 | unsigned int input, j; | |
266 | int ret; | |
267 | ret = sscanf(buf, "%u", &input); | |
268 | ||
269 | if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) | |
270 | return -EINVAL; | |
ff4b1789 | 271 | dbs_data->sampling_down_factor = input; |
3f78a9f7 DN |
272 | |
273 | /* Reset down sampling multiplier in case it was active */ | |
274 | for_each_online_cpu(j) { | |
4471a34f VK |
275 | struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, |
276 | j); | |
3f78a9f7 DN |
277 | dbs_info->rate_mult = 1; |
278 | } | |
3f78a9f7 DN |
279 | return count; |
280 | } | |
281 | ||
6c4640c3 VK |
282 | static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data, |
283 | const char *buf, size_t count) | |
3d5ee9e5 | 284 | { |
4d5dcc42 | 285 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
3d5ee9e5 DJ |
286 | unsigned int input; |
287 | int ret; | |
288 | ||
289 | unsigned int j; | |
32ee8c3e | 290 | |
ffac80e9 | 291 | ret = sscanf(buf, "%u", &input); |
2b03f891 | 292 | if (ret != 1) |
3d5ee9e5 DJ |
293 | return -EINVAL; |
294 | ||
2b03f891 | 295 | if (input > 1) |
3d5ee9e5 | 296 | input = 1; |
32ee8c3e | 297 | |
ff4b1789 | 298 | if (input == dbs_data->ignore_nice_load) { /* nothing to do */ |
3d5ee9e5 DJ |
299 | return count; |
300 | } | |
ff4b1789 | 301 | dbs_data->ignore_nice_load = input; |
3d5ee9e5 | 302 | |
ccb2fe20 | 303 | /* we need to re-evaluate prev_cpu_idle */ |
dac1c1a5 | 304 | for_each_online_cpu(j) { |
4471a34f | 305 | struct od_cpu_dbs_info_s *dbs_info; |
245b2e70 | 306 | dbs_info = &per_cpu(od_cpu_dbs_info, j); |
4471a34f | 307 | dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, |
9366d840 | 308 | &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy); |
ff4b1789 | 309 | if (dbs_data->ignore_nice_load) |
4471a34f VK |
310 | dbs_info->cdbs.prev_cpu_nice = |
311 | kcpustat_cpu(j).cpustat[CPUTIME_NICE]; | |
1ca3abdb | 312 | |
3d5ee9e5 | 313 | } |
3d5ee9e5 DJ |
314 | return count; |
315 | } | |
316 | ||
4d5dcc42 VK |
317 | static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf, |
318 | size_t count) | |
05ca0350 | 319 | { |
4d5dcc42 | 320 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
05ca0350 AS |
321 | unsigned int input; |
322 | int ret; | |
323 | ret = sscanf(buf, "%u", &input); | |
324 | ||
325 | if (ret != 1) | |
326 | return -EINVAL; | |
327 | ||
328 | if (input > 1000) | |
329 | input = 1000; | |
330 | ||
4d5dcc42 | 331 | od_tuners->powersave_bias = input; |
05ca0350 | 332 | ondemand_powersave_bias_init(); |
05ca0350 AS |
333 | return count; |
334 | } | |
335 | ||
c4435630 VK |
336 | gov_show_one_common(sampling_rate); |
337 | gov_show_one_common(up_threshold); | |
338 | gov_show_one_common(sampling_down_factor); | |
339 | gov_show_one_common(ignore_nice_load); | |
340 | gov_show_one_common(min_sampling_rate); | |
341 | gov_show_one(od, io_is_busy); | |
342 | gov_show_one(od, powersave_bias); | |
343 | ||
344 | gov_attr_rw(sampling_rate); | |
345 | gov_attr_rw(io_is_busy); | |
346 | gov_attr_rw(up_threshold); | |
347 | gov_attr_rw(sampling_down_factor); | |
348 | gov_attr_rw(ignore_nice_load); | |
349 | gov_attr_rw(powersave_bias); | |
350 | gov_attr_ro(min_sampling_rate); | |
351 | ||
352 | static struct attribute *od_attributes[] = { | |
353 | &min_sampling_rate.attr, | |
354 | &sampling_rate.attr, | |
355 | &up_threshold.attr, | |
356 | &sampling_down_factor.attr, | |
357 | &ignore_nice_load.attr, | |
358 | &powersave_bias.attr, | |
359 | &io_is_busy.attr, | |
1da177e4 LT |
360 | NULL |
361 | }; | |
362 | ||
1da177e4 LT |
363 | /************************** sysfs end ************************/ |
364 | ||
8e0484d2 | 365 | static int od_init(struct dbs_data *dbs_data, bool notify) |
4d5dcc42 VK |
366 | { |
367 | struct od_dbs_tuners *tuners; | |
368 | u64 idle_time; | |
369 | int cpu; | |
370 | ||
d5b73cd8 | 371 | tuners = kzalloc(sizeof(*tuners), GFP_KERNEL); |
4d5dcc42 VK |
372 | if (!tuners) { |
373 | pr_err("%s: kzalloc failed\n", __func__); | |
374 | return -ENOMEM; | |
375 | } | |
376 | ||
377 | cpu = get_cpu(); | |
378 | idle_time = get_cpu_idle_time_us(cpu, NULL); | |
379 | put_cpu(); | |
380 | if (idle_time != -1ULL) { | |
381 | /* Idle micro accounting is supported. Use finer thresholds */ | |
ff4b1789 | 382 | dbs_data->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; |
4d5dcc42 VK |
383 | /* |
384 | * In nohz/micro accounting case we set the minimum frequency | |
385 | * not depending on HZ, but fixed (very low). The deferred | |
386 | * timer might skip some samples if idle/sleeping as needed. | |
387 | */ | |
388 | dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; | |
389 | } else { | |
ff4b1789 | 390 | dbs_data->up_threshold = DEF_FREQUENCY_UP_THRESHOLD; |
4d5dcc42 VK |
391 | |
392 | /* For correct statistics, we need 10 ticks for each measure */ | |
393 | dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * | |
394 | jiffies_to_usecs(10); | |
395 | } | |
396 | ||
ff4b1789 VK |
397 | dbs_data->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR; |
398 | dbs_data->ignore_nice_load = 0; | |
c2837558 | 399 | tuners->powersave_bias = default_powersave_bias; |
4d5dcc42 VK |
400 | tuners->io_is_busy = should_io_be_busy(); |
401 | ||
402 | dbs_data->tuners = tuners; | |
4d5dcc42 VK |
403 | return 0; |
404 | } | |
405 | ||
8e0484d2 | 406 | static void od_exit(struct dbs_data *dbs_data, bool notify) |
4d5dcc42 VK |
407 | { |
408 | kfree(dbs_data->tuners); | |
409 | } | |
410 | ||
4471a34f | 411 | define_get_cpu_dbs_routines(od_cpu_dbs_info); |
6b8fcd90 | 412 | |
4471a34f | 413 | static struct od_ops od_ops = { |
4471a34f | 414 | .powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu, |
fb30809e | 415 | .powersave_bias_target = generic_powersave_bias_target, |
4471a34f VK |
416 | .freq_increase = dbs_freq_increase, |
417 | }; | |
2f8a835c | 418 | |
7bdad34d | 419 | static struct dbs_governor od_dbs_gov = { |
af926185 RW |
420 | .gov = { |
421 | .name = "ondemand", | |
906a6e5a | 422 | .governor = cpufreq_governor_dbs, |
af926185 RW |
423 | .max_transition_latency = TRANSITION_LATENCY_LIMIT, |
424 | .owner = THIS_MODULE, | |
425 | }, | |
4471a34f | 426 | .governor = GOV_ONDEMAND, |
c4435630 | 427 | .kobj_type = { .default_attrs = od_attributes }, |
4471a34f VK |
428 | .get_cpu_cdbs = get_cpu_cdbs, |
429 | .get_cpu_dbs_info_s = get_cpu_dbs_info_s, | |
430 | .gov_dbs_timer = od_dbs_timer, | |
431 | .gov_check_cpu = od_check_cpu, | |
432 | .gov_ops = &od_ops, | |
4d5dcc42 VK |
433 | .init = od_init, |
434 | .exit = od_exit, | |
4471a34f | 435 | }; |
1da177e4 | 436 | |
7bdad34d | 437 | #define CPU_FREQ_GOV_ONDEMAND (&od_dbs_gov.gov) |
af926185 | 438 | |
fb30809e JS |
439 | static void od_set_powersave_bias(unsigned int powersave_bias) |
440 | { | |
441 | struct cpufreq_policy *policy; | |
442 | struct dbs_data *dbs_data; | |
443 | struct od_dbs_tuners *od_tuners; | |
444 | unsigned int cpu; | |
445 | cpumask_t done; | |
446 | ||
c2837558 | 447 | default_powersave_bias = powersave_bias; |
fb30809e JS |
448 | cpumask_clear(&done); |
449 | ||
450 | get_online_cpus(); | |
451 | for_each_online_cpu(cpu) { | |
e40e7b25 | 452 | struct policy_dbs_info *policy_dbs; |
44152cb8 | 453 | |
fb30809e JS |
454 | if (cpumask_test_cpu(cpu, &done)) |
455 | continue; | |
456 | ||
e40e7b25 RW |
457 | policy_dbs = per_cpu(od_cpu_dbs_info, cpu).cdbs.policy_dbs; |
458 | if (!policy_dbs) | |
c2837558 | 459 | continue; |
fb30809e | 460 | |
e40e7b25 | 461 | policy = policy_dbs->policy; |
fb30809e | 462 | cpumask_or(&done, &done, policy->cpus); |
c2837558 | 463 | |
af926185 | 464 | if (policy->governor != CPU_FREQ_GOV_ONDEMAND) |
c2837558 JS |
465 | continue; |
466 | ||
bc505475 | 467 | dbs_data = policy_dbs->dbs_data; |
c2837558 JS |
468 | od_tuners = dbs_data->tuners; |
469 | od_tuners->powersave_bias = default_powersave_bias; | |
fb30809e JS |
470 | } |
471 | put_online_cpus(); | |
472 | } | |
473 | ||
474 | void od_register_powersave_bias_handler(unsigned int (*f) | |
475 | (struct cpufreq_policy *, unsigned int, unsigned int), | |
476 | unsigned int powersave_bias) | |
477 | { | |
478 | od_ops.powersave_bias_target = f; | |
479 | od_set_powersave_bias(powersave_bias); | |
480 | } | |
481 | EXPORT_SYMBOL_GPL(od_register_powersave_bias_handler); | |
482 | ||
483 | void od_unregister_powersave_bias_handler(void) | |
484 | { | |
485 | od_ops.powersave_bias_target = generic_powersave_bias_target; | |
486 | od_set_powersave_bias(0); | |
487 | } | |
488 | EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler); | |
489 | ||
1da177e4 LT |
490 | static int __init cpufreq_gov_dbs_init(void) |
491 | { | |
af926185 | 492 | return cpufreq_register_governor(CPU_FREQ_GOV_ONDEMAND); |
1da177e4 LT |
493 | } |
494 | ||
495 | static void __exit cpufreq_gov_dbs_exit(void) | |
496 | { | |
af926185 | 497 | cpufreq_unregister_governor(CPU_FREQ_GOV_ONDEMAND); |
1da177e4 LT |
498 | } |
499 | ||
ffac80e9 VP |
500 | MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>"); |
501 | MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>"); | |
502 | MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for " | |
2b03f891 | 503 | "Low Latency Frequency Transition capable processors"); |
ffac80e9 | 504 | MODULE_LICENSE("GPL"); |
1da177e4 | 505 | |
6915719b | 506 | #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND |
de1df26b RW |
507 | struct cpufreq_governor *cpufreq_default_governor(void) |
508 | { | |
af926185 | 509 | return CPU_FREQ_GOV_ONDEMAND; |
de1df26b RW |
510 | } |
511 | ||
6915719b JW |
512 | fs_initcall(cpufreq_gov_dbs_init); |
513 | #else | |
1da177e4 | 514 | module_init(cpufreq_gov_dbs_init); |
6915719b | 515 | #endif |
1da177e4 | 516 | module_exit(cpufreq_gov_dbs_exit); |