aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorRajagopal Venkat <rajagopal.venkat@linaro.org>2012-10-25 19:50:09 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-14 18:35:04 -0500
commit7e6fdd4bad033fa2d73716377b184fa975b0d985 (patch)
tree171f13c8aadd833965a9cb0b83a84fe3eb74c1da /drivers/devfreq
parent77b67063bb6bce6d475e910d3b886a606d0d91f7 (diff)
PM / devfreq: Core updates to support devices which can idle
Prepare devfreq core framework to support devices which can idle. When device idleness is detected perhaps through runtime-pm, need some mechanism to suspend devfreq load monitoring and resume back when device is online. Present code continues monitoring unless device is removed from devfreq core. This patch introduces following design changes, - use per device work instead of global work to monitor device load. This enables suspend/resume of device devfreq and reduces monitoring code complexity. - decouple delayed work based load monitoring logic from core by introducing helpers functions to be used by governors. This provides flexibility for governors either to use delayed work based monitoring functions or to implement their own mechanism. - devfreq core interacts with governors via events to perform specific actions. These events include start/stop devfreq. This sets ground for adding suspend/resume events. The devfreq apis are not modified and are kept intact. Signed-off-by: Rajagopal Venkat <rajagopal.venkat@linaro.org> Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/devfreq.c442
-rw-r--r--drivers/devfreq/governor.h11
-rw-r--r--drivers/devfreq/governor_performance.c16
-rw-r--r--drivers/devfreq/governor_powersave.c16
-rw-r--r--drivers/devfreq/governor_simpleondemand.c24
-rw-r--r--drivers/devfreq/governor_userspace.c23
6 files changed, 268 insertions, 264 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index b146d76f04cf..1aaf1aeb1f1d 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -30,17 +30,11 @@
30struct class *devfreq_class; 30struct class *devfreq_class;
31 31
32/* 32/*
33 * devfreq_work periodically monitors every registered device. 33 * devfreq core provides delayed work based load monitoring helper
34 * The minimum polling interval is one jiffy. The polling interval is 34 * functions. Governors can use these or can implement their own
35 * determined by the minimum polling period among all polling devfreq 35 * monitoring mechanism.
36 * devices. The resolution of polling interval is one jiffy.
37 */ 36 */
38static bool polling;
39static struct workqueue_struct *devfreq_wq; 37static struct workqueue_struct *devfreq_wq;
40static struct delayed_work devfreq_work;
41
42/* wait removing if this is to be removed */
43static struct devfreq *wait_remove_device;
44 38
45/* The list of all device-devfreq */ 39/* The list of all device-devfreq */
46static LIST_HEAD(devfreq_list); 40static LIST_HEAD(devfreq_list);
@@ -72,6 +66,8 @@ static struct devfreq *find_device_devfreq(struct device *dev)
72 return ERR_PTR(-ENODEV); 66 return ERR_PTR(-ENODEV);
73} 67}
74 68
69/* Load monitoring helper functions for governors use */
70
75/** 71/**
76 * update_devfreq() - Reevaluate the device and configure frequency. 72 * update_devfreq() - Reevaluate the device and configure frequency.
77 * @devfreq: the devfreq instance. 73 * @devfreq: the devfreq instance.
@@ -121,6 +117,152 @@ int update_devfreq(struct devfreq *devfreq)
121} 117}
122 118
123/** 119/**
120 * devfreq_monitor() - Periodically poll devfreq objects.
121 * @work: the work struct used to run devfreq_monitor periodically.
122 *
123 */
124static void devfreq_monitor(struct work_struct *work)
125{
126 int err;
127 struct devfreq *devfreq = container_of(work,
128 struct devfreq, work.work);
129
130 mutex_lock(&devfreq->lock);
131 err = update_devfreq(devfreq);
132 if (err)
133 dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
134
135 queue_delayed_work(devfreq_wq, &devfreq->work,
136 msecs_to_jiffies(devfreq->profile->polling_ms));
137 mutex_unlock(&devfreq->lock);
138}
139
140/**
141 * devfreq_monitor_start() - Start load monitoring of devfreq instance
142 * @devfreq: the devfreq instance.
143 *
144 * Helper function for starting devfreq device load monitoing. By
145 * default delayed work based monitoring is supported. Function
146 * to be called from governor in response to DEVFREQ_GOV_START
147 * event when device is added to devfreq framework.
148 */
149void devfreq_monitor_start(struct devfreq *devfreq)
150{
151 INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
152 if (devfreq->profile->polling_ms)
153 queue_delayed_work(devfreq_wq, &devfreq->work,
154 msecs_to_jiffies(devfreq->profile->polling_ms));
155}
156
157/**
158 * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
159 * @devfreq: the devfreq instance.
160 *
161 * Helper function to stop devfreq device load monitoing. Function
162 * to be called from governor in response to DEVFREQ_GOV_STOP
163 * event when device is removed from devfreq framework.
164 */
165void devfreq_monitor_stop(struct devfreq *devfreq)
166{
167 cancel_delayed_work_sync(&devfreq->work);
168}
169
170/**
171 * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
172 * @devfreq: the devfreq instance.
173 *
174 * Helper function to suspend devfreq device load monitoing. Function
175 * to be called from governor in response to DEVFREQ_GOV_SUSPEND
176 * event or when polling interval is set to zero.
177 *
178 * Note: Though this function is same as devfreq_monitor_stop(),
179 * intentionally kept separate to provide hooks for collecting
180 * transition statistics.
181 */
182void devfreq_monitor_suspend(struct devfreq *devfreq)
183{
184 mutex_lock(&devfreq->lock);
185 if (devfreq->stop_polling) {
186 mutex_unlock(&devfreq->lock);
187 return;
188 }
189
190 devfreq->stop_polling = true;
191 mutex_unlock(&devfreq->lock);
192 cancel_delayed_work_sync(&devfreq->work);
193}
194
195/**
196 * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
197 * @devfreq: the devfreq instance.
198 *
199 * Helper function to resume devfreq device load monitoing. Function
200 * to be called from governor in response to DEVFREQ_GOV_RESUME
201 * event or when polling interval is set to non-zero.
202 */
203void devfreq_monitor_resume(struct devfreq *devfreq)
204{
205 mutex_lock(&devfreq->lock);
206 if (!devfreq->stop_polling)
207 goto out;
208
209 if (!delayed_work_pending(&devfreq->work) &&
210 devfreq->profile->polling_ms)
211 queue_delayed_work(devfreq_wq, &devfreq->work,
212 msecs_to_jiffies(devfreq->profile->polling_ms));
213 devfreq->stop_polling = false;
214
215out:
216 mutex_unlock(&devfreq->lock);
217}
218
219/**
220 * devfreq_interval_update() - Update device devfreq monitoring interval
221 * @devfreq: the devfreq instance.
222 * @delay: new polling interval to be set.
223 *
224 * Helper function to set new load monitoring polling interval. Function
225 * to be called from governor in response to DEVFREQ_GOV_INTERVAL event.
226 */
227void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
228{
229 unsigned int cur_delay = devfreq->profile->polling_ms;
230 unsigned int new_delay = *delay;
231
232 mutex_lock(&devfreq->lock);
233 devfreq->profile->polling_ms = new_delay;
234
235 if (devfreq->stop_polling)
236 goto out;
237
238 /* if new delay is zero, stop polling */
239 if (!new_delay) {
240 mutex_unlock(&devfreq->lock);
241 cancel_delayed_work_sync(&devfreq->work);
242 return;
243 }
244
245 /* if current delay is zero, start polling with new delay */
246 if (!cur_delay) {
247 queue_delayed_work(devfreq_wq, &devfreq->work,
248 msecs_to_jiffies(devfreq->profile->polling_ms));
249 goto out;
250 }
251
252 /* if current delay is greater than new delay, restart polling */
253 if (cur_delay > new_delay) {
254 mutex_unlock(&devfreq->lock);
255 cancel_delayed_work_sync(&devfreq->work);
256 mutex_lock(&devfreq->lock);
257 if (!devfreq->stop_polling)
258 queue_delayed_work(devfreq_wq, &devfreq->work,
259 msecs_to_jiffies(devfreq->profile->polling_ms));
260 }