aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/devfreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r--drivers/devfreq/devfreq.c442
1 files changed, 189 insertions, 253 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 }
261out:
262 mutex_unlock(&devfreq->lock);
263}
264
265/**
124 * devfreq_notifier_call() - Notify that the device frequency requirements 266 * devfreq_notifier_call() - Notify that the device frequency requirements
125 * has been changed out of devfreq framework. 267 * has been changed out of devfreq framework.
126 * @nb the notifier_block (supposed to be devfreq->nb) 268 * @nb the notifier_block (supposed to be devfreq->nb)
@@ -143,59 +285,32 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
143} 285}
144 286
145/** 287/**
146 * _remove_devfreq() - Remove devfreq from the device. 288 * _remove_devfreq() - Remove devfreq from the list and release its resources.
147 * @devfreq: the devfreq struct 289 * @devfreq: the devfreq struct