diff options
author | Enric Balletbo i Serra <enric.balletbo@collabora.com> | 2018-07-04 04:45:50 -0400 |
---|---|---|
committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2018-10-01 21:16:41 -0400 |
commit | 23c7b54ca1cd1797ef39169ab85e6d46f1c2d061 (patch) | |
tree | c04d424c2507228ea6cffb310f9b50b6b738296e /drivers/devfreq/devfreq.c | |
parent | 17b57b1883c1285f3d0dc2266e8f79286a7bef38 (diff) |
PM / devfreq: Fix devfreq_add_device() when drivers are built as modules.
When the devfreq driver and the governor driver are built as modules,
the call to devfreq_add_device() or governor_store() fails because the
governor driver is not loaded at the time the devfreq driver loads. The
devfreq driver has a build dependency on the governor but also should
have a runtime dependency. We need to make sure that the governor driver
is loaded before the devfreq driver.
This patch fixes this bug by adding a try_then_request_governor()
function. First tries to find the governor, and then, if it is not found,
it requests the module and tries again.
Fixes: 1b5c1be2c88e (PM / devfreq: map devfreq drivers to governor using name)
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r-- | drivers/devfreq/devfreq.c | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 4c49bb1330b5..62ead442a872 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/kmod.h> | ||
14 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
15 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
@@ -221,6 +222,49 @@ static struct devfreq_governor *find_devfreq_governor(const char *name) | |||
221 | return ERR_PTR(-ENODEV); | 222 | return ERR_PTR(-ENODEV); |
222 | } | 223 | } |
223 | 224 | ||
225 | /** | ||
226 | * try_then_request_governor() - Try to find the governor and request the | ||
227 | * module if is not found. | ||
228 | * @name: name of the governor | ||
229 | * | ||
230 | * Search the list of devfreq governors and request the module and try again | ||
231 | * if is not found. This can happen when both drivers (the governor driver | ||
232 | * and the driver that call devfreq_add_device) are built as modules. | ||
233 | * devfreq_list_lock should be held by the caller. Returns the matched | ||
234 | * governor's pointer. | ||
235 | */ | ||
236 | static struct devfreq_governor *try_then_request_governor(const char *name) | ||
237 | { | ||
238 | struct devfreq_governor *governor; | ||
239 | int err = 0; | ||
240 | |||
241 | if (IS_ERR_OR_NULL(name)) { | ||
242 | pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); | ||
243 | return ERR_PTR(-EINVAL); | ||
244 | } | ||
245 | WARN(!mutex_is_locked(&devfreq_list_lock), | ||
246 | "devfreq_list_lock must be locked."); | ||
247 | |||
248 | governor = find_devfreq_governor(name); | ||
249 | if (IS_ERR(governor)) { | ||
250 | mutex_unlock(&devfreq_list_lock); | ||
251 | |||
252 | if (!strncmp(name, DEVFREQ_GOV_SIMPLE_ONDEMAND, | ||
253 | DEVFREQ_NAME_LEN)) | ||
254 | err = request_module("governor_%s", "simpleondemand"); | ||
255 | else | ||
256 | err = request_module("governor_%s", name); | ||
257 | /* Restore previous state before return */ | ||
258 | mutex_lock(&devfreq_list_lock); | ||
259 | if (err) | ||
260 | return NULL; | ||
261 | |||
262 | governor = find_devfreq_governor(name); | ||
263 | } | ||
264 | |||
265 | return governor; | ||
266 | } | ||
267 | |||
224 | static int devfreq_notify_transition(struct devfreq *devfreq, | 268 | static int devfreq_notify_transition(struct devfreq *devfreq, |
225 | struct devfreq_freqs *freqs, unsigned int state) | 269 | struct devfreq_freqs *freqs, unsigned int state) |
226 | { | 270 | { |
@@ -646,9 +690,8 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
646 | mutex_unlock(&devfreq->lock); | 690 | mutex_unlock(&devfreq->lock); |
647 | 691 | ||
648 | mutex_lock(&devfreq_list_lock); | 692 | mutex_lock(&devfreq_list_lock); |
649 | list_add(&devfreq->node, &devfreq_list); | ||
650 | 693 | ||
651 | governor = find_devfreq_governor(devfreq->governor_name); | 694 | governor = try_then_request_governor(devfreq->governor_name); |
652 | if (IS_ERR(governor)) { | 695 | if (IS_ERR(governor)) { |
653 | dev_err(dev, "%s: Unable to find governor for the device\n", | 696 | dev_err(dev, "%s: Unable to find governor for the device\n", |
654 | __func__); | 697 | __func__); |
@@ -664,12 +707,14 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
664 | __func__); | 707 | __func__); |
665 | goto err_init; | 708 | goto err_init; |
666 | } | 709 | } |
710 | |||
711 | list_add(&devfreq->node, &devfreq_list); | ||
712 | |||
667 | mutex_unlock(&devfreq_list_lock); | 713 | mutex_unlock(&devfreq_list_lock); |
668 | 714 | ||
669 | return devfreq; | 715 | return devfreq; |
670 | 716 | ||
671 | err_init: | 717 | err_init: |
672 | list_del(&devfreq->node); | ||
673 | mutex_unlock(&devfreq_list_lock); | 718 | mutex_unlock(&devfreq_list_lock); |
674 | 719 | ||
675 | device_unregister(&devfreq->dev); | 720 | device_unregister(&devfreq->dev); |
@@ -991,7 +1036,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, | |||
991 | return -EINVAL; | 1036 | return -EINVAL; |
992 | 1037 | ||
993 | mutex_lock(&devfreq_list_lock); | 1038 | mutex_lock(&devfreq_list_lock); |
994 | governor = find_devfreq_governor(str_governor); | 1039 | governor = try_then_request_governor(str_governor); |
995 | if (IS_ERR(governor)) { | 1040 | if (IS_ERR(governor)) { |
996 | ret = PTR_ERR(governor); | 1041 | ret = PTR_ERR(governor); |
997 | goto out; | 1042 | goto out; |