OSDN Git Service

cpufreq: Improve kerneldoc comments for cpufreq_cpu_get/put()
[uclinux-h8/linux.git] / drivers / cpufreq / cpufreq.c
index e35a886..e109227 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/cpu.h>
 #include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -205,17 +206,15 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
 EXPORT_SYMBOL_GPL(cpufreq_generic_get);
 
 /**
- * cpufreq_cpu_get: returns policy for a cpu and marks it busy.
+ * cpufreq_cpu_get - Return policy for a CPU and mark it as busy.
+ * @cpu: CPU to find the policy for.
  *
- * @cpu: cpu to find policy for.
+ * Call cpufreq_cpu_get_raw() to obtain a cpufreq policy for @cpu and increment
+ * the kobject reference counter of that policy.  Return a valid policy on
+ * success or NULL on failure.
  *
- * This returns policy for 'cpu', returns NULL if it doesn't exist.
- * It also increments the kobject reference count to mark it busy and so would
- * require a corresponding call to cpufreq_cpu_put() to decrement it back.
- * If corresponding call cpufreq_cpu_put() isn't made, the policy wouldn't be
- * freed as that depends on the kobj count.
- *
- * Return: A valid policy on success, otherwise NULL on failure.
+ * The policy returned by this function has to be released with the help of
+ * cpufreq_cpu_put() to balance its kobject reference counter properly.
  */
 struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 {
@@ -242,12 +241,8 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
 
 /**
- * cpufreq_cpu_put: Decrements the usage count of a policy
- *
- * @policy: policy earlier returned by cpufreq_cpu_get().
- *
- * This decrements the kobject reference count incremented earlier by calling
- * cpufreq_cpu_get().
+ * cpufreq_cpu_put - Decrement kobject usage counter for cpufreq policy.
+ * @policy: cpufreq policy returned by cpufreq_cpu_get().
  */
 void cpufreq_cpu_put(struct cpufreq_policy *policy)
 {
@@ -545,13 +540,13 @@ EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us);
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
 static ssize_t show_boost(struct kobject *kobj,
-                                struct attribute *attr, char *buf)
+                         struct kobj_attribute *attr, char *buf)
 {
        return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
 }
 
-static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
-                                 const char *buf, size_t count)
+static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr,
+                          const char *buf, size_t count)
 {
        int ret, enable;
 
@@ -1200,28 +1195,39 @@ static int cpufreq_online(unsigned int cpu)
                        return -ENOMEM;
        }
 
-       cpumask_copy(policy->cpus, cpumask_of(cpu));
+       if (!new_policy && cpufreq_driver->online) {
+               ret = cpufreq_driver->online(policy);
+               if (ret) {
+                       pr_debug("%s: %d: initialization failed\n", __func__,
+                                __LINE__);
+                       goto out_exit_policy;
+               }
 
-       /* call driver. From then on the cpufreq must be able
-        * to accept all calls to ->verify and ->setpolicy for this CPU
-        */
-       ret = cpufreq_driver->init(policy);
-       if (ret) {
-               pr_debug("initialization failed\n");
-               goto out_free_policy;
-       }
+               /* Recover policy->cpus using related_cpus */
+               cpumask_copy(policy->cpus, policy->related_cpus);
+       } else {
+               cpumask_copy(policy->cpus, cpumask_of(cpu));
 
-       ret = cpufreq_table_validate_and_sort(policy);
-       if (ret)
-               goto out_exit_policy;
+               /*
+                * Call driver. From then on the cpufreq must be able
+                * to accept all calls to ->verify and ->setpolicy for this CPU.
+                */
+               ret = cpufreq_driver->init(policy);
+               if (ret) {
+                       pr_debug("%s: %d: initialization failed\n", __func__,
+                                __LINE__);
+                       goto out_free_policy;
+               }
 
-       down_write(&policy->rwsem);
+               ret = cpufreq_table_validate_and_sort(policy);
+               if (ret)
+                       goto out_exit_policy;
 
-       if (new_policy) {
                /* related_cpus should at least include policy->cpus. */
                cpumask_copy(policy->related_cpus, policy->cpus);
        }
 
+       down_write(&policy->rwsem);
        /*
         * affected cpus must always be the one, which are online. We aren't
         * managing offline cpus here.
@@ -1305,8 +1311,6 @@ static int cpufreq_online(unsigned int cpu)
        if (ret) {
                pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n",
                       __func__, cpu, ret);
-               /* cpufreq_policy_free() will notify based on this */
-               new_policy = false;
                goto out_destroy_policy;
        }
 
@@ -1318,6 +1322,10 @@ static int cpufreq_online(unsigned int cpu)
        if (cpufreq_driver->ready)
                cpufreq_driver->ready(policy);
 
+       if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
+           cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV)
+               policy->cdev = of_cpufreq_cooling_register(policy);
+
        pr_debug("initialization complete\n");
 
        return 0;
@@ -1405,6 +1413,12 @@ static int cpufreq_offline(unsigned int cpu)
                goto unlock;
        }
 
+       if (IS_ENABLED(CONFIG_CPU_THERMAL) &&
+           cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) {
+               cpufreq_cooling_unregister(policy->cdev);
+               policy->cdev = NULL;
+       }
+
        if (cpufreq_driver->stop_cpu)
                cpufreq_driver->stop_cpu(policy);
 
@@ -1412,11 +1426,12 @@ static int cpufreq_offline(unsigned int cpu)
                cpufreq_exit_governor(policy);
 
        /*
-        * Perform the ->exit() even during light-weight tear-down,
-        * since this is a core component, and is essential for the
-        * subsequent light-weight ->init() to succeed.
+        * Perform the ->offline() during light-weight tear-down, as
+        * that allows fast recovery when the CPU comes back.
         */
-       if (cpufreq_driver->exit) {
+       if (cpufreq_driver->offline) {
+               cpufreq_driver->offline(policy);
+       } else if (cpufreq_driver->exit) {
                cpufreq_driver->exit(policy);
                policy->freq_table = NULL;
        }
@@ -1445,8 +1460,13 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        cpumask_clear_cpu(cpu, policy->real_cpus);
        remove_cpu_dev_symlink(policy, dev);
 
-       if (cpumask_empty(policy->real_cpus))
+       if (cpumask_empty(policy->real_cpus)) {
+               /* We did light-weight exit earlier, do full tear down now */
+               if (cpufreq_driver->offline)
+                       cpufreq_driver->exit(policy);
+
                cpufreq_policy_free(policy);
+       }
 }
 
 /**
@@ -2192,12 +2212,25 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_get_policy);
 
-/*
- * policy : current policy.
- * new_policy: policy to be set.
+/**
+ * cpufreq_set_policy - Modify cpufreq policy parameters.
+ * @policy: Policy object to modify.
+ * @new_policy: New policy data.
+ *
+ * Pass @new_policy to the cpufreq driver's ->verify() callback, run the
+ * installed policy notifiers for it with the CPUFREQ_ADJUST value, pass it to
+ * the driver's ->verify() callback again and run the notifiers for it again
+ * with the CPUFREQ_NOTIFY value.  Next, copy the min and max parameters
+ * of @new_policy to @policy and either invoke the driver's ->setpolicy()
+ * callback (if present) or carry out a governor update for @policy.  That is,
+ * run the current governor's ->limits() callback (if the governor field in
+ * @new_policy points to the same object as the one in @policy) or replace the
+ * governor for @policy with the new one stored in @new_policy.
+ *
+ * The cpuinfo part of @policy is not updated by this function.
  */
 static int cpufreq_set_policy(struct cpufreq_policy *policy,
-                               struct cpufreq_policy *new_policy)
+                             struct cpufreq_policy *new_policy)
 {
        struct cpufreq_governor *old_gov;
        int ret;
@@ -2247,11 +2280,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        if (cpufreq_driver->setpolicy) {
                policy->policy = new_policy->policy;
                pr_debug("setting range\n");
-               return cpufreq_driver->setpolicy(new_policy);
+               return cpufreq_driver->setpolicy(policy);
        }
 
        if (new_policy->governor == policy->governor) {
-               pr_debug("cpufreq: governor limits update\n");
+               pr_debug("governor limits update\n");
                cpufreq_governor_limits(policy);
                return 0;
        }
@@ -2272,7 +2305,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
        if (!ret) {
                ret = cpufreq_start_governor(policy);
                if (!ret) {
-                       pr_debug("cpufreq: governor change\n");
+                       pr_debug("governor change\n");
                        sched_cpufreq_governor_change(policy, old_gov);
                        return 0;
                }
@@ -2293,11 +2326,14 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 }
 
 /**
- *     cpufreq_update_policy - re-evaluate an existing cpufreq policy
- *     @cpu: CPU which shall be re-evaluated
+ * cpufreq_update_policy - Re-evaluate an existing cpufreq policy.
+ * @cpu: CPU to re-evaluate the policy for.
  *
- *     Useful for policy notifiers which have different necessities
- *     at different times.
+ * Update the current frequency for the cpufreq policy of @cpu and use
+ * cpufreq_set_policy() to re-apply the min and max limits saved in the
+ * user_policy sub-structure of that policy, which triggers the evaluation
+ * of policy notifiers and the cpufreq driver's ->verify() callback for the
+ * policy in question, among other things.
  */
 void cpufreq_update_policy(unsigned int cpu)
 {
@@ -2312,23 +2348,18 @@ void cpufreq_update_policy(unsigned int cpu)
        if (policy_is_inactive(policy))
                goto unlock;
 
-       pr_debug("updating policy for CPU %u\n", cpu);
-       memcpy(&new_policy, policy, sizeof(*policy));
-       new_policy.min = policy->user_policy.min;
-       new_policy.max = policy->user_policy.max;
-
        /*
         * BIOS might change freq behind our back
         * -> ask driver for current freq and notify governors about a change
         */
-       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
-               if (cpufreq_suspended)
-                       goto unlock;
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy &&
+           (cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy))))
+               goto unlock;
 
-               new_policy.cur = cpufreq_update_current_freq(policy);
-               if (WARN_ON(!new_policy.cur))
-                       goto unlock;
-       }
+       pr_debug("updating policy for CPU %u\n", cpu);
+       memcpy(&new_policy, policy, sizeof(*policy));
+       new_policy.min = policy->user_policy.min;
+       new_policy.max = policy->user_policy.max;
 
        cpufreq_set_policy(policy, &new_policy);
 
@@ -2479,7 +2510,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                    driver_data->target) ||
             (driver_data->setpolicy && (driver_data->target_index ||
                    driver_data->target)) ||
-            (!!driver_data->get_intermediate != !!driver_data->target_intermediate))
+            (!driver_data->get_intermediate != !driver_data->target_intermediate) ||
+            (!driver_data->online != !driver_data->offline))
                return -EINVAL;
 
        pr_debug("trying to register driver %s\n", driver_data->name);