diff options
Diffstat (limited to 'drivers/devfreq')
| -rw-r--r-- | drivers/devfreq/devfreq.c | 442 | ||||
| -rw-r--r-- | drivers/devfreq/governor.h | 11 | ||||
| -rw-r--r-- | drivers/devfreq/governor_performance.c | 16 | ||||
| -rw-r--r-- | drivers/devfreq/governor_powersave.c | 16 | ||||
| -rw-r--r-- | drivers/devfreq/governor_simpleondemand.c | 24 | ||||
| -rw-r--r-- | drivers/devfreq/governor_userspace.c | 23 |
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 @@ | |||
| 30 | struct class *devfreq_class; | 30 | struct 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 | */ |
| 38 | static bool polling; | ||
| 39 | static struct workqueue_struct *devfreq_wq; | 37 | static struct workqueue_struct *devfreq_wq; |
| 40 | static struct delayed_work devfreq_work; | ||
| 41 | |||
| 42 | /* wait removing if this is to be removed */ | ||
| 43 | static struct devfreq *wait_remove_device; | ||
| 44 | 38 | ||
| 45 | /* The list of all device-devfreq */ | 39 | /* The list of all device-devfreq */ |
| 46 | static LIST_HEAD(devfreq_list); | 40 | static 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 | */ | ||
| 124 | static 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 | */ | ||
| 149 | void 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 | */ | ||
| 165 | void 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 | */ | ||
| 182 | void 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 | */ | ||
| 203 | void 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 | |||
| 215 | out: | ||
| 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 | */ | ||
| 227 | void 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 | } | ||
| 261 | out: | ||
| 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, | |||
