aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2011-10-01 18:19:15 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-10-01 18:19:15 -0400
commita3c98b8b2ede1f4230f49f9af7135cd902e71e83 (patch)
tree7016d0409796b8bbe7443b18addd93eaba869d68 /drivers/devfreq
parent03ca370fbf7b76d6d002380dbdc2cdc2319f9c80 (diff)
PM: Introduce devfreq: generic DVFS framework with device-specific OPPs
With OPPs, a device may have multiple operable frequency and voltage sets. However, there can be multiple possible operable sets and a system will need to choose one from them. In order to reduce the power consumption (by reducing frequency and voltage) without affecting the performance too much, a Dynamic Voltage and Frequency Scaling (DVFS) scheme may be used. This patch introduces the DVFS capability to non-CPU devices with OPPs. DVFS is a techique whereby the frequency and supplied voltage of a device is adjusted on-the-fly. DVFS usually sets the frequency as low as possible with given conditions (such as QoS assurance) and adjusts voltage according to the chosen frequency in order to reduce power consumption and heat dissipation. The generic DVFS for devices, devfreq, may appear quite similar with /drivers/cpufreq. However, cpufreq does not allow to have multiple devices registered and is not suitable to have multiple heterogenous devices with different (but simple) governors. Normally, DVFS mechanism controls frequency based on the demand for the device, and then, chooses voltage based on the chosen frequency. devfreq also controls the frequency based on the governor's frequency recommendation and let OPP pick up the pair of frequency and voltage based on the recommended frequency. Then, the chosen OPP is passed to device driver's "target" callback. When PM QoS is going to be used with the devfreq device, the device driver should enable OPPs that are appropriate with the current PM QoS requests. In order to do so, the device driver may call opp_enable and opp_disable at the notifier callback of PM QoS so that PM QoS's update_target() call enables the appropriate OPPs. Note that at least one of OPPs should be enabled at any time; be careful when there is a transition. Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Mike Turquette <mturquette@ti.com> Acked-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/Kconfig39
-rw-r--r--drivers/devfreq/Makefile1
-rw-r--r--drivers/devfreq/devfreq.c532
-rw-r--r--drivers/devfreq/governor.h24
4 files changed, 596 insertions, 0 deletions
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
new file mode 100644
index 000000000000..1fb42de4f420
--- /dev/null
+++ b/drivers/devfreq/Kconfig
@@ -0,0 +1,39 @@
1config ARCH_HAS_DEVFREQ
2 bool
3 depends on ARCH_HAS_OPP
4 help
5 Denotes that the architecture supports DEVFREQ. If the architecture
6 supports multiple OPP entries per device and the frequency of the
7 devices with OPPs may be altered dynamically, the architecture
8 supports DEVFREQ.
9
10menuconfig PM_DEVFREQ
11 bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support"
12 depends on PM_OPP && ARCH_HAS_DEVFREQ
13 help
14 With OPP support, a device may have a list of frequencies and
15 voltages available. DEVFREQ, a generic DVFS framework can be
16 registered for a device with OPP support in order to let the
17 governor provided to DEVFREQ choose an operating frequency
18 based on the OPP's list and the policy given with DEVFREQ.
19
20 Each device may have its own governor and policy. DEVFREQ can
21 reevaluate the device state periodically and/or based on the
22 OPP list changes (each frequency/voltage pair in OPP may be
23 disabled or enabled).
24
25 Like some CPUs with CPUFREQ, a device may have multiple clocks.
26 However, because the clock frequencies of a single device are
27 determined by the single device's state, an instance of DEVFREQ
28 is attached to a single device and returns a "representative"
29 clock frequency from the OPP of the device, which is also attached
30 to a device by 1-to-1. The device registering DEVFREQ takes the
31 responsiblity to "interpret" the frequency listed in OPP and
32 to set its every clock accordingly with the "target" callback
33 given to DEVFREQ.
34
35if PM_DEVFREQ
36
37comment "DEVFREQ Drivers"
38
39endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
new file mode 100644
index 000000000000..168934a12b38
--- /dev/null
+++ b/drivers/devfreq/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_PM_DEVFREQ) += devfreq.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
new file mode 100644
index 000000000000..f3100b19f798
--- /dev/null
+++ b/drivers/devfreq/devfreq.c
@@ -0,0 +1,532 @@
1/*
2 * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
3 * for Non-CPU Devices.
4 *
5 * Copyright (C) 2011 Samsung Electronics
6 * MyungJoo Ham <myungjoo.ham@samsung.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
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/errno.h>
16#include <linux/err.h>
17#include <linux/init.h>
18#include <linux/slab.h>
19#include <linux/opp.h>
20#include <linux/devfreq.h>
21#include <linux/workqueue.h>
22#include <linux/platform_device.h>
23#include <linux/list.h>
24#include <linux/printk.h>
25#include <linux/hrtimer.h>
26#include "governor.h"
27
28struct class *devfreq_class;
29
30/*
31 * devfreq_work periodically monitors every registered device.
32 * The minimum polling interval is one jiffy. The polling interval is
33 * determined by the minimum polling period among all polling devfreq
34 * devices. The resolution of polling interval is one jiffy.
35 */
36static bool polling;
37static struct workqueue_struct *devfreq_wq;
38static struct delayed_work devfreq_work;
39
40/* wait removing if this is to be removed */
41static struct devfreq *wait_remove_device;
42
43/* The list of all device-devfreq */
44static LIST_HEAD(devfreq_list);
45static DEFINE_MUTEX(devfreq_list_lock);
46
47/**
48 * find_device_devfreq() - find devfreq struct using device pointer
49 * @dev: device pointer used to lookup device devfreq.
50 *
51 * Search the list of device devfreqs and return the matched device's
52 * devfreq info. devfreq_list_lock should be held by the caller.
53 */
54static struct devfreq *find_device_devfreq(struct device *dev)
55{
56 struct devfreq *tmp_devfreq;
57
58 if (unlikely(IS_ERR_OR_NULL(dev))) {
59 pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
60 return ERR_PTR(-EINVAL);
61 }
62 WARN(!mutex_is_locked(&devfreq_list_lock),
63 "devfreq_list_lock must be locked.");
64
65 list_for_each_entry(tmp_devfreq, &devfreq_list, node) {
66 if (tmp_devfreq->dev.parent == dev)
67 return tmp_devfreq;
68 }
69
70 return ERR_PTR(-ENODEV);
71}
72
73/**
74 * update_devfreq() - Reevaluate the device and configure frequency.
75 * @devfreq: the devfreq instance.
76 *
77 * Note: Lock devfreq->lock before calling update_devfreq
78 * This function is exported for governors.
79 */
80int update_devfreq(struct devfreq *devfreq)
81{
82 unsigned long freq;
83 int err = 0;
84
85 if (!mutex_is_locked(&devfreq->lock)) {
86 WARN(true, "devfreq->lock must be locked by the caller.\n");
87 return -EINVAL;
88 }
89
90 /* Reevaluate the proper frequency */
91 err = devfreq->governor->get_target_freq(devfreq, &freq);
92 if (err)
93 return err;
94
95 err = devfreq->profile->target(devfreq->dev.parent, &freq);
96 if (err)
97 return err;
98
99 devfreq->previous_freq = freq;
100 return err;
101}
102
103/**
104 * devfreq_notifier_call() - Notify that the device frequency requirements
105 * has been changed out of devfreq framework.
106 * @nb the notifier_block (supposed to be devfreq->nb)
107 * @type not used
108 * @devp not used
109 *
110 * Called by a notifier that uses devfreq->nb.
111 */
112static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
113 void *devp)
114{
115 struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
116 int ret;
117
118 mutex_lock(&devfreq->lock);
119 ret = update_devfreq(devfreq);
120 mutex_unlock(&devfreq->lock);
121
122 return ret;
123}
124
125/**
126 * _remove_devfreq() - Remove devfreq from the device.
127 * @devfreq: the devfreq struct
128 * @skip: skip calling device_unregister().
129 *
130 * Note that the caller should lock devfreq->lock before calling
131 * this. _remove_devfreq() will unlock it and free devfreq
132 * internally. devfreq_list_lock should be locked by the caller
133 * as well (not relased at return)
134 *
135 * Lock usage:
136 * devfreq->lock: locked before call.
137 * unlocked at return (and freed)
138 * devfreq_list_lock: locked before call.
139 * kept locked at return.
140 * if devfreq is centrally polled.
141 *
142 * Freed memory:
143 * devfreq
144 */
145static void _remove_devfreq(struct devfreq *devfreq, bool skip)
146{
147 if (!mutex_is_locked(&devfreq->lock)) {
148 WARN(true, "devfreq->lock must be locked by the caller.\n");
149 return;
150 }
151 if (!devfreq->governor->no_central_polling &&
152 !mutex_is_locked(&devfreq_list_lock)) {
153 WARN(true, "devfreq_list_lock must be locked by the caller.\n");
154 return;
155 }
156
157 if (devfreq->being_removed)
158 return;
159
160 devfreq->being_removed = true;
161
162 if (devfreq->profile->exit)
163 devfreq->profile->exit(devfreq->dev.parent);
164
165 if (devfreq->governor->exit)
166 devfreq->governor->exit(devfreq);
167
168 if (!skip && get_device(&devfreq->dev)) {
169 device_unregister(&devfreq->dev);
170 put_device(&devfreq->dev);
171 }
172
173 if (!devfreq->governor->no_central_polling)
174 list_del(&devfreq->node);
175
176 mutex_unlock(&devfreq->lock);
177 mutex_destroy(&devfreq->lock);
178
179 kfree(devfreq);
180}
181
182/**
183 * devfreq_dev_release() - Callback for struct device to release the device.
184 * @dev: the devfreq device
185 *
186 * This calls _remove_devfreq() if _remove_devfreq() is not called.
187 * Note that devfreq_dev_release() could be called by _remove_devfreq() as
188 * well as by others unregistering the device.
189 */
190static void devfreq_dev_release(struct device *dev)
191{
192 struct devfreq *devfreq = to_devfreq(dev);
193 bool central_polling = !devfreq->governor->no_central_polling;
194
195 /*
196 * If devfreq_dev_release() was called by device_unregister() of
197 * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and
198 * being_removed is already set. This also partially checks the case
199 * where devfreq_dev_release() is called from a thread other than
200 * the one called _remove_devfreq(); however, this case is
201 * dealt completely with another following being_removed check.
202 *
203 * Because being_removed is never being
204 * unset, we do not need to worry about race conditions on
205 * being_removed.
206 */
207 if (devfreq->being_removed)
208 return;
209
210 if (central_polling)
211 mutex_lock(&devfreq_list_lock);
212
213 mutex_lock(&devfreq->lock);
214
215 /*
216 * Check being_removed flag again for the case where
217 * devfreq_dev_release() was called in a thread other than the one
218 * possibly called _remove_devfreq().
219 */
220 if (devfreq->being_removed) {
221 mutex_unlock(&devfreq->lock);
222 goto out;
223 }
224
225 /* devfreq->lock is unlocked and removed in _removed_devfreq() */
226 _remove_devfreq(devfreq, true);
227
228out:
229 if (central_polling)
230 mutex_unlock(&devfreq_list_lock);
231}
232
233/**
234 * devfreq_monitor() - Periodically poll devfreq objects.
235 * @work: the work struct used to run devfreq_monitor periodically.
236 *
237 */
238static void devfreq_monitor(struct work_struct *work)
239{
240 static unsigned long last_polled_at;
241 struct devfreq *devfreq, *tmp;
242 int error;
243 unsigned long jiffies_passed;
244 unsigned long next_jiffies = ULONG_MAX, now = jiffies;
245 struct device *dev;
246
247 /* Initially last_polled_at = 0, polling every device at bootup */
248 jiffies_passed = now - last_polled_at;
249 last_polled_at = now;
250 if (jiffies_passed == 0)
251 jiffies_passed = 1;
252
253 mutex_lock(&devfreq_list_lock);
254 list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) {
255 mutex_lock(&devfreq->lock);
256 dev = devfreq->dev.parent;
257
258 /* Do not remove tmp for a while */
259 wait_remove_device = tmp;
260
261 if (devfreq->governor->no_central_polling ||
262 devfreq->next_polling == 0) {
263 mutex_unlock(&devfreq->lock);
264 continue;
265 }
266 mutex_unlock(&devfreq_list_lock);
267
268 /*
269 * Reduce more next_polling if devfreq_wq took an extra
270 * delay. (i.e., CPU has been idled.)
271 */
272 if (devfreq->next_polling <= jiffies_passed) {
273 error = update_devfreq(devfreq);
274
275 /* Remove a devfreq with an error. */
276 if (error && error != -EAGAIN) {
277
278 dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n",
279 error, devfreq->governor->name);
280
281 /*
282 * Unlock devfreq before locking the list
283 * in order to avoid deadlock with
284 * find_device_devfreq or others
285 */
286 mutex_unlock(&devfreq->lock);
287 mutex_lock(&devfreq_list_lock);
288 /* Check if devfreq is already removed */
289 if (IS_ERR(find_device_devfreq(dev)))
290 continue;
291 mutex_lock(&devfreq->lock);
292 /* This unlocks devfreq->lock and free it */
293 _remove_devfreq(devfreq, false);
294 continue;
295 }
296 devfreq->next_polling = devfreq->polling_jiffies;
297 } else {
298 devfreq->next_polling -= jiffies_passed;
299 }
300
301 if (devfreq->next_polling)
302 next_jiffies = (next_jiffies > devfreq->next_polling) ?
303 devfreq->next_polling : next_jiffies;
304
305 mutex_unlock(&devfreq->lock);
306 mutex_lock(&devfreq_list_lock);
307 }
308 wait_remove_device = NULL;
309 mutex_unlock(&devfreq_list_lock);
310
311 if (next_jiffies > 0 && next_jiffies < ULONG_MAX) {
312 polling = true;
313 queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies);
314 } else {
315 polling = false;
316 }
317}
318
319/**
320 * devfreq_add_device() - Add devfreq feature to the device
321 * @dev: the device to add devfreq feature.
322 * @profile: device-specific profile to run devfreq.
323 * @governor: the policy to choose frequency.
324 * @data: private data for the governor. The devfreq framework does not
325 * touch this value.
326 */
327struct devfreq *devfreq_add_device(struct device *dev,
328 struct devfreq_dev_profile *profile,
329 const struct devfreq_governor *governor,
330 void *data)
331{
332 struct devfreq *devfreq;
333 int err = 0;
334
335 if (!dev || !profile || !governor) {
336 dev_err(dev, "%s: Invalid parameters.\n", __func__);
337 return ERR_PTR(-EINVAL);
338 }
339
340
341 if (!governor->no_central_polling) {
342 mutex_lock(&devfreq_list_lock);
343 devfreq = find_device_devfreq(dev);
344 mutex_unlock(&devfreq_list_lock);
345 if (!IS_ERR(devfreq)) {
346 dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
347 err = -EINVAL;
348 goto out;
349 }
350 }
351
352 devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
353 if (!devfreq) {
354 dev_err(dev, "%s: Unable to create devfreq for the device\n",
355 __func__);
356 err = -ENOMEM;
357 goto out;
358 }
359
360 mutex_init(&devfreq->lock);
361 mutex_lock(&devfreq->lock);
362 devfreq->dev.parent = dev;
363 devfreq->dev.class = devfreq_class;
364 devfreq->dev.release = devfreq_dev_release;
365 devfreq->profile = profile;
366 devfreq->governor = governor;
367 devfreq->previous_freq = profile->initial_freq;
368 devfreq->data = data;
369 devfreq->next_polling = devfreq->polling_jiffies
370 = msecs_to_jiffies(devfreq->profile->polling_ms);
371 devfreq->nb.notifier_call = devfreq_notifier_call;
372
373 dev_set_name(&devfreq->dev, dev_name(dev));
374 err = device_register(&devfreq->dev);
375 if (err) {
376 put_device(&devfreq->dev);
377 goto err_dev;
378 }
379
380 if (governor->init)
381 err = governor->init(devfreq);
382 if (err)
383 goto err_init;
384
385 mutex_unlock(&devfreq->lock);
386
387 if (governor->no_central_polling)
388 goto out;
389
390 mutex_lock(&devfreq_list_lock);
391
392 list_add(&devfreq->node, &devfreq_list);
393
394 if (devfreq_wq && devfreq->next_polling && !polling) {
395 polling = true;
396 queue_delayed_work(devfreq_wq, &devfreq_work,
397 devfreq->next_polling);
398 }
399 mutex_unlock(&devfreq_list_lock);
400 goto out;
401err_init:
402 device_unregister(&devfreq->dev);
403err_dev:
404 mutex_unlock(&devfreq->lock);
405 kfree(devfreq);
406out:
407 if (err)
408 return ERR_PTR(err);
409 else
410 return devfreq;
411}
412
413/**
414 * devfreq_remove_device() - Remove devfreq feature from a device.
415 * @devfreq the devfreq instance to be removed
416 */
417int devfreq_remove_device(struct devfreq *devfreq)
418{
419 if (!devfreq)
420 return -EINVAL;
421
422 if (!devfreq->governor->no_central_polling) {
423 mutex_lock(&devfreq_list_lock);
424 while (wait_remove_device == devfreq) {
425 mutex_unlock(&devfreq_list_lock);
426 schedule();
427 mutex_lock(&devfreq_list_lock);
428 }
429 }
430
431 mutex_lock(&devfreq->lock);
432 _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */
433
434 if (!devfreq->governor->no_central_polling)
435 mutex_unlock(&devfreq_list_lock);
436
437 return 0;
438}
439
440/**
441 * devfreq_start_polling() - Initialize data structure for devfreq framework and
442 * start polling registered devfreq devices.
443 */
444static int __init devfreq_start_polling(void)
445{
446 mutex_lock(&devfreq_list_lock);
447 polling = false;
448 devfreq_wq = create_freezable_workqueue("devfreq_wq");
449 INIT_DELAYED_WORK_DEFERRABLE(&devfreq_work, devfreq_monitor);
450 mutex_unlock(&devfreq_list_lock);
451
452 devfreq_monitor(&devfreq_work.work);
453 return 0;
454}
455late_initcall(devfreq_start_polling);
456
457static int __init devfreq_init(void)
458{
459 devfreq_class = class_create(THIS_MODULE, "devfreq");
460 if (IS_ERR(devfreq_class)) {
461 pr_err("%s: couldn't create class\n", __FILE__);
462 return PTR_ERR(devfreq_class);
463 }
464 return 0;
465}
466subsys_initcall(devfreq_init);
467
468static void __exit devfreq_exit(void)
469{
470 class_destroy(devfreq_class);
471}
472module_exit(devfreq_exit);
473
474/*
475 * The followings are helper functions for devfreq user device drivers with
476 * OPP framework.
477 */
478
479/**
480 * devfreq_recommended_opp() - Helper function to get proper OPP for the
481 * freq value given to target callback.
482 * @dev The devfreq user device. (parent of devfreq)
483 * @freq The frequency given to target function
484 *
485 */
486struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq)
487{
488 struct opp *opp = opp_find_freq_ceil(dev, freq);
489
490 if (opp == ERR_PTR(-ENODEV))
491 opp = opp_find_freq_floor(dev, freq);
492 return opp;
493}
494
495/**
496 * devfreq_register_opp_notifier() - Helper function to get devfreq notified
497 * for any changes in the OPP availability
498 * changes
499 * @dev The devfreq user device. (parent of devfreq)
500 * @devfreq The devfreq object.
501 */
502int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
503{
504 struct srcu_notifier_head *nh = opp_get_notifier(dev);
505
506 if (IS_ERR(nh))
507 return PTR_ERR(nh);
508 return srcu_notifier_chain_register(nh, &devfreq->nb);
509}
510
511/**
512 * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
513 * notified for any changes in the OPP
514 * availability changes anymore.
515 * @dev The devfreq user device. (parent of devfreq)
516 * @devfreq The devfreq object.
517 *
518 * At exit() callback of devfreq_dev_profile, this must be included if
519 * devfreq_recommended_opp is used.
520 */
521int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
522{
523 struct srcu_notifier_head *nh = opp_get_notifier(dev);
524
525 if (IS_ERR(nh))
526 return PTR_ERR(nh);
527 return srcu_notifier_chain_unregister(nh, &devfreq->nb);
528}
529
530MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
531MODULE_DESCRIPTION("devfreq class support");
532MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
new file mode 100644
index 000000000000..ea7f13c58ded
--- /dev/null
+++ b/drivers/devfreq/governor.h
@@ -0,0 +1,24 @@
1/*
2 * governor.h - internal header for devfreq governors.
3 *
4 * Copyright (C) 2011 Samsung Electronics
5 * MyungJoo Ham <myungjoo.ham@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This header is for devfreq governors in drivers/devfreq/
12 */
13
14#ifndef _GOVERNOR_H
15#define _GOVERNOR_H
16
17#include <linux/devfreq.h>
18
19#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
20
21/* Caution: devfreq->lock must be locked before calling update_devfreq */
22extern int update_devfreq(struct devfreq *devfreq);
23
24#endif /* _GOVERNOR_H */