PM / devfreq: map devfreq drivers to governor using name
authorNishanth Menon <nm@ti.com>
Mon, 29 Oct 2012 20:01:45 +0000 (15:01 -0500)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 20 Nov 2012 09:46:22 +0000 (18:46 +0900)
Allow devfreq drivers to register a preferred governor name
and when the devfreq governor loads itself at a later point
required drivers are managed appropriately, at the time of
unload of a devfreq governor, stop managing those drivers
as well.

Since the governor structures do not need to be exposed
anymore, remove the definitions and make them static

NOTE: devfreq_list_lock is now used to protect governor
start and stop - as this allows us to protect governors and
devfreq with the proper dependencies as needed.

As part of this change, change the registration of exynos
bus driver to request for ondemand using the governor name.

Cc: Rajagopal Venkat <rajagopal.venkat@linaro.org>
Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Kevin Hilman <khilman@ti.com>
Cc: linux-pm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Nishanth Menon <nm@ti.com>
[Merge conflict resolved by MyungJoo Ham]
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
drivers/devfreq/devfreq.c
drivers/devfreq/exynos4_bus.c
drivers/devfreq/governor_performance.c
drivers/devfreq/governor_powersave.c
drivers/devfreq/governor_simpleondemand.c
drivers/devfreq/governor_userspace.c
include/linux/devfreq.h

index 679ac424472f6567f5588b0e90de1d062afcf0ae..0d7be03d561f12fea2f769b51bc4840bbb06116a 100644 (file)
@@ -159,6 +159,9 @@ int update_devfreq(struct devfreq *devfreq)
                return -EINVAL;
        }
 
+       if (!devfreq->governor)
+               return -EINVAL;
+
        /* Reevaluate the proper frequency */
        err = devfreq->governor->get_target_freq(devfreq, &freq);
        if (err)
@@ -379,7 +382,9 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
        list_del(&devfreq->node);
        mutex_unlock(&devfreq_list_lock);
 
-       devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL);
+       if (devfreq->governor)
+               devfreq->governor->event_handler(devfreq,
+                                                DEVFREQ_GOV_STOP, NULL);
 
        if (devfreq->profile->exit)
                devfreq->profile->exit(devfreq->dev.parent);
@@ -412,19 +417,20 @@ static void devfreq_dev_release(struct device *dev)
  * devfreq_add_device() - Add devfreq feature to the device
  * @dev:       the device to add devfreq feature.
  * @profile:   device-specific profile to run devfreq.
- * @governor the policy to choose frequency.
+ * @governor_name:     name of the policy to choose frequency.
  * @data:      private data for the governor. The devfreq framework does not
  *             touch this value.
  */
 struct devfreq *devfreq_add_device(struct device *dev,
                                   struct devfreq_dev_profile *profile,
-                                  const struct devfreq_governor *governor,
+                                  const char *governor_name,
                                   void *data)
 {
        struct devfreq *devfreq;
+       struct devfreq_governor *governor;
        int err = 0;
 
-       if (!dev || !profile || !governor) {
+       if (!dev || !profile || !governor_name) {
                dev_err(dev, "%s: Invalid parameters.\n", __func__);
                return ERR_PTR(-EINVAL);
        }
@@ -452,7 +458,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
        devfreq->dev.class = devfreq_class;
        devfreq->dev.release = devfreq_dev_release;
        devfreq->profile = profile;
-       devfreq->governor = governor;
+       strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN);
        devfreq->previous_freq = profile->initial_freq;
        devfreq->data = data;
        devfreq->nb.notifier_call = devfreq_notifier_call;
@@ -478,10 +484,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
 
        mutex_lock(&devfreq_list_lock);
        list_add(&devfreq->node, &devfreq_list);
-       mutex_unlock(&devfreq_list_lock);
 
-       err = devfreq->governor->event_handler(devfreq,
-                               DEVFREQ_GOV_START, NULL);
+       governor = find_devfreq_governor(devfreq->governor_name);
+       if (!IS_ERR(governor))
+               devfreq->governor = governor;
+       if (devfreq->governor)
+               err = devfreq->governor->event_handler(devfreq,
+                                       DEVFREQ_GOV_START, NULL);
+       mutex_unlock(&devfreq_list_lock);
        if (err) {
                dev_err(dev, "%s: Unable to start governor for the device\n",
                        __func__);
@@ -524,6 +534,9 @@ int devfreq_suspend_device(struct devfreq *devfreq)
        if (!devfreq)
                return -EINVAL;
 
+       if (!devfreq->governor)
+               return 0;
+
        return devfreq->governor->event_handler(devfreq,
                                DEVFREQ_GOV_SUSPEND, NULL);
 }
@@ -538,6 +551,9 @@ int devfreq_resume_device(struct devfreq *devfreq)
        if (!devfreq)
                return -EINVAL;
 
+       if (!devfreq->governor)
+               return 0;
+
        return devfreq->governor->event_handler(devfreq,
                                DEVFREQ_GOV_RESUME, NULL);
 }
@@ -550,6 +566,7 @@ EXPORT_SYMBOL(devfreq_resume_device);
 int devfreq_add_governor(struct devfreq_governor *governor)
 {
        struct devfreq_governor *g;
+       struct devfreq *devfreq;
        int err = 0;
 
        if (!governor) {
@@ -568,6 +585,38 @@ int devfreq_add_governor(struct devfreq_governor *governor)
 
        list_add(&governor->node, &devfreq_governor_list);
 
+       list_for_each_entry(devfreq, &devfreq_list, node) {
+               int ret = 0;
+               struct device *dev = devfreq->dev.parent;
+
+               if (!strncmp(devfreq->governor_name, governor->name,
+                            DEVFREQ_NAME_LEN)) {
+                       /* The following should never occur */
+                       if (devfreq->governor) {
+                               dev_warn(dev,
+                                        "%s: Governor %s already present\n",
+                                        __func__, devfreq->governor->name);
+                               ret = devfreq->governor->event_handler(devfreq,
+                                                       DEVFREQ_GOV_STOP, NULL);
+                               if (ret) {
+                                       dev_warn(dev,
+                                                "%s: Governor %s stop = %d\n",
+                                                __func__,
+                                                devfreq->governor->name, ret);
+                               }
+                               /* Fall through */
+                       }
+                       devfreq->governor = governor;
+                       ret = devfreq->governor->event_handler(devfreq,
+                                               DEVFREQ_GOV_START, NULL);
+                       if (ret) {
+                               dev_warn(dev, "%s: Governor %s start=%d\n",
+                                        __func__, devfreq->governor->name,
+                                        ret);
+                       }
+               }
+       }
+
 err_out:
        mutex_unlock(&devfreq_list_lock);
 
@@ -582,6 +631,7 @@ EXPORT_SYMBOL(devfreq_add_governor);
 int devfreq_remove_governor(struct devfreq_governor *governor)
 {
        struct devfreq_governor *g;
+       struct devfreq *devfreq;
        int err = 0;
 
        if (!governor) {
@@ -597,6 +647,29 @@ int devfreq_remove_governor(struct devfreq_governor *governor)
                err = -EINVAL;
                goto err_out;
        }
+       list_for_each_entry(devfreq, &devfreq_list, node) {
+               int ret;
+               struct device *dev = devfreq->dev.parent;
+
+               if (!strncmp(devfreq->governor_name, governor->name,
+                            DEVFREQ_NAME_LEN)) {
+                       /* we should have a devfreq governor! */
+                       if (!devfreq->governor) {
+                               dev_warn(dev, "%s: Governor %s NOT present\n",
+                                        __func__, governor->name);
+                               continue;
+                               /* Fall through */
+                       }
+                       ret = devfreq->governor->event_handler(devfreq,
+                                               DEVFREQ_GOV_STOP, NULL);
+                       if (ret) {
+                               dev_warn(dev, "%s: Governor %s stop=%d\n",
+                                        __func__, devfreq->governor->name,
+                                        ret);
+                       }
+                       devfreq->governor = NULL;
+               }
+       }
 
        list_del(&governor->node);
 err_out:
@@ -609,6 +682,9 @@ EXPORT_SYMBOL(devfreq_remove_governor);
 static ssize_t show_governor(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
+       if (!to_devfreq(dev)->governor)
+               return -EINVAL;
+
        return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
 }
 
@@ -645,6 +721,9 @@ static ssize_t store_polling_interval(struct device *dev,
        unsigned int value;
        int ret;
 
+       if (!df->governor)
+               return -EINVAL;
+
        ret = sscanf(buf, "%u", &value);
        if (ret != 1)
                return -EINVAL;
index 68145316c49c8b048d843dc2bef1910e6cc03e0a..b8ac28497b376e2ea5cdc20e767e27c13ed602ac 100644 (file)
@@ -1040,7 +1040,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
        busfreq_mon_reset(data);
 
        data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
-                                          &devfreq_simple_ondemand, NULL);
+                                          "simple_ondemand", NULL);
        if (IS_ERR(data->devfreq))
                return PTR_ERR(data->devfreq);
 
index db8ff77dbed2c6b46bdecdcb4314b91dbab6b667..865a3695691764c9155132c02a4f65cc1122a103 100644 (file)
@@ -40,7 +40,7 @@ static int devfreq_performance_handler(struct devfreq *devfreq,
        return ret;
 }
 
-const struct devfreq_governor devfreq_performance = {
+static struct devfreq_governor devfreq_performance = {
        .name = "performance",
        .get_target_freq = devfreq_performance_func,
        .event_handler = devfreq_performance_handler,
index 30f0fca8d63554d174343bddf6cba59b0e236530..8612c0f96b793df48a5e6d5d7289773dafa46e8b 100644 (file)
@@ -37,7 +37,7 @@ static int devfreq_powersave_handler(struct devfreq *devfreq,
        return ret;
 }
 
-const struct devfreq_governor devfreq_powersave = {
+static struct devfreq_governor devfreq_powersave = {
        .name = "powersave",
        .get_target_freq = devfreq_powersave_func,
        .event_handler = devfreq_powersave_handler,
index 85f9ed531b1e19ee1ea13c51c0a089d8391fda8f..a870a24bb56b05731e8b9a0c804bbdfc5126b1e9 100644 (file)
@@ -120,7 +120,7 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
        return 0;
 }
 
-const struct devfreq_governor devfreq_simple_ondemand = {
+static struct devfreq_governor devfreq_simple_ondemand = {
        .name = "simple_ondemand",
        .get_target_freq = devfreq_simple_ondemand_func,
        .event_handler = devfreq_simple_ondemand_handler,
index 110f178fec04e130c3cea06b016393cd346214ff..34fb80f50cf6e439cca5765e1f8bf66ca59805a5 100644 (file)
@@ -135,7 +135,7 @@ static int devfreq_userspace_handler(struct devfreq *devfreq,
        return ret;
 }
 
-const struct devfreq_governor devfreq_userspace = {
+static struct devfreq_governor devfreq_userspace = {
        .name = "userspace",
        .get_target_freq = devfreq_userspace_func,
        .event_handler = devfreq_userspace_handler,
index 6484a3f8dda8d6c5710a37b545d968fdc253b67e..235248cb2c938452cbd998c8a171b4ac7c6d0b69 100644 (file)
@@ -125,6 +125,7 @@ struct devfreq_governor {
  *             using devfreq.
  * @profile:   device-specific devfreq profile
  * @governor:  method how to choose frequency based on the usage.
+ * @governor_name:     devfreq governor name for use with this devfreq
  * @nb:                notifier block used to notify devfreq object that it should
  *             reevaluate operable frequencies. Devfreq users may use
  *             devfreq.nb to the corresponding register notifier call chain.
@@ -155,6 +156,7 @@ struct devfreq {
        struct device dev;
        struct devfreq_dev_profile *profile;
        const struct devfreq_governor *governor;
+       char governor_name[DEVFREQ_NAME_LEN];
        struct notifier_block nb;
        struct delayed_work work;
 
@@ -176,7 +178,7 @@ struct devfreq {
 #if defined(CONFIG_PM_DEVFREQ)
 extern struct devfreq *devfreq_add_device(struct device *dev,
                                  struct devfreq_dev_profile *profile,
-                                 const struct devfreq_governor *governor,
+                                 const char *governor_name,
                                  void *data);
 extern int devfreq_remove_device(struct devfreq *devfreq);
 extern int devfreq_suspend_device(struct devfreq *devfreq);
@@ -190,17 +192,7 @@ extern int devfreq_register_opp_notifier(struct device *dev,
 extern int devfreq_unregister_opp_notifier(struct device *dev,
                                           struct devfreq *devfreq);
 
-#ifdef CONFIG_DEVFREQ_GOV_POWERSAVE
-extern const struct devfreq_governor devfreq_powersave;
-#endif
-#ifdef CONFIG_DEVFREQ_GOV_PERFORMANCE
-extern const struct devfreq_governor devfreq_performance;
-#endif
-#ifdef CONFIG_DEVFREQ_GOV_USERSPACE
-extern const struct devfreq_governor devfreq_userspace;
-#endif
 #ifdef CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND
-extern const struct devfreq_governor devfreq_simple_ondemand;
 /**
  * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
  *     and devfreq_add_device
@@ -223,7 +215,7 @@ struct devfreq_simple_ondemand_data {
 #else /* !CONFIG_PM_DEVFREQ */
 static struct devfreq *devfreq_add_device(struct device *dev,
                                          struct devfreq_dev_profile *profile,
-                                         struct devfreq_governor *governor,
+                                         const char *governor_name,
                                          void *data)
 {
        return NULL;
@@ -262,11 +254,6 @@ static int devfreq_unregister_opp_notifier(struct device *dev,
        return -EINVAL;
 }
 
-#define devfreq_powersave      NULL
-#define devfreq_performance    NULL
-#define devfreq_userspace      NULL
-#define devfreq_simple_ondemand        NULL
-
 #endif /* CONFIG_PM_DEVFREQ */
 
 #endif /* __LINUX_DEVFREQ_H__ */