]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - drivers/cpufreq/cpufreq.c
cpufreq: make __cpufreq_notify_transition() static
[linux-imx.git] / drivers / cpufreq / cpufreq.c
index 4b8c7f297d74db41778aa31b5e0fbcf4c389bda5..d976e222f10fb3f50143963a435638257bb314f4 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 2001 Russell King
  *            (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ *            (C) 2013 Viresh Kumar <viresh.kumar@linaro.org>
  *
  *  Oct 2005 - Ashok Raj <ashok.raj@intel.com>
  *     Added handling for CPU hotplug
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <asm/cputime.h>
 #include <linux/kernel.h>
+#include <linux/kernel_stat.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/notifier.h>
@@ -25,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/tick.h>
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
  */
 static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_RWLOCK(cpufreq_driver_lock);
+static DEFINE_MUTEX(cpufreq_governor_lock);
+
 #ifdef CONFIG_HOTPLUG_CPU
 /* This one keeps track of the previously set governor of a removed CPU */
 static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
 #endif
-static DEFINE_RWLOCK(cpufreq_driver_lock);
 
 /*
  * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -132,6 +137,51 @@ bool have_governor_per_policy(void)
 {
        return cpufreq_driver->have_governor_per_policy;
 }
+EXPORT_SYMBOL_GPL(have_governor_per_policy);
+
+struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
+{
+       if (have_governor_per_policy())
+               return &policy->kobj;
+       else
+               return cpufreq_global_kobject;
+}
+EXPORT_SYMBOL_GPL(get_governor_parent_kobj);
+
+static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
+{
+       u64 idle_time;
+       u64 cur_wall_time;
+       u64 busy_time;
+
+       cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+       busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+       idle_time = cur_wall_time - busy_time;
+       if (wall)
+               *wall = cputime_to_usecs(cur_wall_time);
+
+       return cputime_to_usecs(idle_time);
+}
+
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
+{
+       u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
+
+       if (idle_time == -1ULL)
+               return get_cpu_idle_time_jiffy(cpu, wall);
+       else if (!io_busy)
+               idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+       return idle_time;
+}
+EXPORT_SYMBOL_GPL(get_cpu_idle_time);
 
 static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
 {
@@ -150,7 +200,6 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
        if (!try_module_get(cpufreq_driver->owner))
                goto err_out_unlock;
 
-
        /* get the CPU */
        data = per_cpu(cpufreq_cpu_data, cpu);
 
@@ -220,7 +269,7 @@ static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
  */
 #ifndef CONFIG_SMP
 static unsigned long l_p_j_ref;
-static unsigned int  l_p_j_ref_freq;
+static unsigned int l_p_j_ref_freq;
 
 static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
 {
@@ -233,7 +282,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
                pr_debug("saving %lu as reference value for loops_per_jiffy; "
                        "freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
        }
-       if ((val == CPUFREQ_POSTCHANGE  && ci->old != ci->new) ||
+       if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
            (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
                loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
                                                                ci->new);
@@ -248,8 +297,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
 }
 #endif
 
-
-void __cpufreq_notify_transition(struct cpufreq_policy *policy,
+static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                struct cpufreq_freqs *freqs, unsigned int state)
 {
        BUG_ON(irqs_disabled());
@@ -294,6 +342,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                break;
        }
 }
+
 /**
  * cpufreq_notify_transition - call notifier chain and adjust_jiffies
  * on frequency transition.
@@ -311,7 +360,6 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
 EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
 
 
-
 /*********************************************************************
  *                          SYSFS INTERFACE                          *
  *********************************************************************/
@@ -376,7 +424,6 @@ out:
        return err;
 }
 
-
 /**
  * cpufreq_per_cpu_attr_read() / show_##file_name() -
  * print out cpufreq information
@@ -441,7 +488,6 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
        return sprintf(buf, "%u\n", cur_freq);
 }
 
-
 /**
  * show_scaling_governor - show the current policy for the specified CPU
  */
@@ -457,7 +503,6 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
        return -EINVAL;
 }
 
-
 /**
  * store_scaling_governor - store policy for the specified CPU
  */
@@ -480,8 +525,10 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
                                                &new_policy.governor))
                return -EINVAL;
 
-       /* Do not use cpufreq_set_policy here or the user_policy.max
-          will be wrongly overridden */
+       /*
+        * Do not use cpufreq_set_policy here or the user_policy.max
+        * will be wrongly overridden
+        */
        ret = __cpufreq_set_policy(policy, &new_policy);
 
        policy->user_policy.policy = policy->policy;
@@ -630,9 +677,6 @@ static struct attribute *default_attrs[] = {
        NULL
 };
 
-struct kobject *cpufreq_global_kobject;
-EXPORT_SYMBOL(cpufreq_global_kobject);
-
 #define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
 #define to_attr(a) container_of(a, struct freq_attr, attr)
 
@@ -703,6 +747,49 @@ static struct kobj_type ktype_cpufreq = {
        .release        = cpufreq_sysfs_release,
 };
 
+struct kobject *cpufreq_global_kobject;
+EXPORT_SYMBOL(cpufreq_global_kobject);
+
+static int cpufreq_global_kobject_usage;
+
+int cpufreq_get_global_kobject(void)
+{
+       if (!cpufreq_global_kobject_usage++)
+               return kobject_add(cpufreq_global_kobject,
+                               &cpu_subsys.dev_root->kobj, "%s", "cpufreq");
+
+       return 0;
+}
+EXPORT_SYMBOL(cpufreq_get_global_kobject);
+
+void cpufreq_put_global_kobject(void)
+{
+       if (!--cpufreq_global_kobject_usage)
+               kobject_del(cpufreq_global_kobject);
+}
+EXPORT_SYMBOL(cpufreq_put_global_kobject);
+
+int cpufreq_sysfs_create_file(const struct attribute *attr)
+{
+       int ret = cpufreq_get_global_kobject();
+
+       if (!ret) {
+               ret = sysfs_create_file(cpufreq_global_kobject, attr);
+               if (ret)
+                       cpufreq_put_global_kobject();
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(cpufreq_sysfs_create_file);
+
+void cpufreq_sysfs_remove_file(const struct attribute *attr)
+{
+       sysfs_remove_file(cpufreq_global_kobject, attr);
+       cpufreq_put_global_kobject();
+}
+EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
+
 /* symlink affected CPUs */
 static int cpufreq_add_dev_symlink(unsigned int cpu,
                                   struct cpufreq_policy *policy)
@@ -1005,7 +1092,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
  * Caller should already have policy_rwsem in write mode for this CPU.
  * This routine frees the rwsem before returning.
  */
-static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
+static int __cpufreq_remove_dev(struct device *dev,
+               struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id, ret, cpus;
        unsigned long flags;
@@ -1112,7 +1200,6 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
        return 0;
 }
 
-
 static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
@@ -1125,7 +1212,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        return retval;
 }
 
-
 static void handle_update(struct work_struct *work)
 {
        struct cpufreq_policy *policy =
@@ -1136,7 +1222,8 @@ static void handle_update(struct work_struct *work)
 }
 
 /**
- *     cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
+ *     cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
+ *     in deep trouble.
  *     @cpu: cpu number
  *     @old_freq: CPU frequency the kernel thinks the CPU runs at
  *     @new_freq: CPU frequency the CPU actually runs at
@@ -1151,7 +1238,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
        struct cpufreq_freqs freqs;
        unsigned long flags;
 
-
        pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
               "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
 
@@ -1166,7 +1252,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
 }
 
-
 /**
  * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
  * @cpu: CPU number
@@ -1212,7 +1297,6 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_quick_get_max);
 
-
 static unsigned int __cpufreq_get(unsigned int cpu)
 {
        struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
@@ -1271,7 +1355,6 @@ static struct subsys_interface cpufreq_interface = {
        .remove_dev     = cpufreq_remove_dev,
 };
 
-
 /**
  * cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
  *
@@ -1408,11 +1491,10 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
 }
 EXPORT_SYMBOL(cpufreq_register_notifier);
 
-
 /**
  *     cpufreq_unregister_notifier - unregister a driver with cpufreq
  *     @nb: notifier block to be unregistered
- *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ *     @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
  *
  *     Remove a driver from the CPU frequency notifier list.
  *
@@ -1448,7 +1530,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
  *                              GOVERNORS                            *
  *********************************************************************/
 
-
 int __cpufreq_driver_target(struct cpufreq_policy *policy,
                            unsigned int target_freq,
                            unsigned int relation)
@@ -1484,10 +1565,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
 {
        int ret = -EINVAL;
 
-       policy = cpufreq_cpu_get(policy->cpu);
-       if (!policy)
-               goto no_policy;
-
        if (unlikely(lock_policy_rwsem_write(policy->cpu)))
                goto fail;
 
@@ -1496,30 +1573,19 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
        unlock_policy_rwsem_write(policy->cpu);
 
 fail:
-       cpufreq_cpu_put(policy);
-no_policy:
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_target);
 
 int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
 {
-       int ret = 0;
-
        if (cpufreq_disabled())
-               return ret;
+               return 0;
 
        if (!cpufreq_driver->getavg)
                return 0;
 
-       policy = cpufreq_cpu_get(policy->cpu);
-       if (!policy)
-               return -EINVAL;
-
-       ret = cpufreq_driver->getavg(policy, cpu);
-
-       cpufreq_cpu_put(policy);
-       return ret;
+       return cpufreq_driver->getavg(policy, cpu);
 }
 EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
 
@@ -1562,6 +1628,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 
        pr_debug("__cpufreq_governor for CPU %u, event %u\n",
                                                policy->cpu, event);
+
+       mutex_lock(&cpufreq_governor_lock);
+       if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
+           (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
+               mutex_unlock(&cpufreq_governor_lock);
+               return -EBUSY;
+       }
+
+       if (event == CPUFREQ_GOV_STOP)
+               policy->governor_enabled = false;
+       else if (event == CPUFREQ_GOV_START)
+               policy->governor_enabled = true;
+
+       mutex_unlock(&cpufreq_governor_lock);
+
        ret = policy->governor->governor(policy, event);
 
        if (!ret) {
@@ -1569,6 +1650,14 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                        policy->governor->initialized++;
                else if (event == CPUFREQ_GOV_POLICY_EXIT)
                        policy->governor->initialized--;
+       } else {
+               /* Restore original values */
+               mutex_lock(&cpufreq_governor_lock);
+               if (event == CPUFREQ_GOV_STOP)
+                       policy->governor_enabled = true;
+               else if (event == CPUFREQ_GOV_START)
+                       policy->governor_enabled = false;
+               mutex_unlock(&cpufreq_governor_lock);
        }
 
        /* we keep one module reference alive for
@@ -1581,7 +1670,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        return ret;
 }
 
-
 int cpufreq_register_governor(struct cpufreq_governor *governor)
 {
        int err;
@@ -1606,7 +1694,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_governor);
 
-
 void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 {
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1636,7 +1723,6 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
 EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
 
 
-
 /*********************************************************************
  *                          POLICY INTERFACE                         *
  *********************************************************************/
@@ -1665,7 +1751,6 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_get_policy);
 
-
 /*
  * data   : current policy.
  * policy : policy to be set.
@@ -1699,8 +1784,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                        CPUFREQ_INCOMPATIBLE, policy);
 
-       /* verify the cpu speed can be set within this limit,
-          which might be different to the first one */
+       /*
+        * verify the cpu speed can be set within this limit, which might be
+        * different to the first one
+        */
        ret = cpufreq_driver->verify(policy);
        if (ret)
                goto error_out;
@@ -1729,18 +1816,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
                        /* end old governor */
                        if (data->governor) {
                                __cpufreq_governor(data, CPUFREQ_GOV_STOP);
+                               unlock_policy_rwsem_write(policy->cpu);
                                __cpufreq_governor(data,
                                                CPUFREQ_GOV_POLICY_EXIT);
+                               lock_policy_rwsem_write(policy->cpu);
                        }
 
                        /* start new governor */
                        data->governor = policy->governor;
                        if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
-                               if (!__cpufreq_governor(data, CPUFREQ_GOV_START))
+                               if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) {
                                        failed = 0;
-                               else
+                               } else {
+                                       unlock_policy_rwsem_write(policy->cpu);
                                        __cpufreq_governor(data,
                                                        CPUFREQ_GOV_POLICY_EXIT);
+                                       lock_policy_rwsem_write(policy->cpu);
+                               }
                        }
 
                        if (failed) {
@@ -1797,8 +1889,10 @@ int cpufreq_update_policy(unsigned int cpu)
        policy.policy = data->user_policy.policy;
        policy.governor = data->user_policy.governor;
 
-       /* BIOS might change freq behind our back
-         -> ask driver for current freq and notify governors about a change */
+       /*
+        * BIOS might change freq behind our back
+        * -> ask driver for current freq and notify governors about a change
+        */
        if (cpufreq_driver->get) {
                policy.cur = cpufreq_driver->get(cpu);
                if (!data->cur) {
@@ -1847,7 +1941,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
 }
 
 static struct notifier_block __refdata cpufreq_cpu_notifier = {
-    .notifier_call = cpufreq_cpu_callback,
+       .notifier_call = cpufreq_cpu_callback,
 };
 
 /*********************************************************************
@@ -1859,7 +1953,7 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
  * @driver_data: A struct cpufreq_driver containing the values#
  * submitted by the CPU Frequency driver.
  *
- *   Registers a CPU Frequency driver to this core code. This code
+ * Registers a CPU Frequency driver to this core code. This code
  * returns zero on success, -EBUSY when another driver got here first
  * (and isn't unregistered in the meantime).
  *
@@ -1926,11 +2020,10 @@ err_null_driver:
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);
 
-
 /**
  * cpufreq_unregister_driver - unregister the current CPUFreq driver
  *
- *    Unregister the current CPUFreq driver. Only call this if you have
+ * Unregister the current CPUFreq driver. Only call this if you have
  * the right to do so, i.e. if you have succeeded in initialising before!
  * Returns zero if successful, and -EINVAL if the cpufreq_driver is
  * currently not initialised.
@@ -1967,7 +2060,7 @@ static int __init cpufreq_core_init(void)
                init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
        }
 
-       cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
+       cpufreq_global_kobject = kobject_create();
        BUG_ON(!cpufreq_global_kobject);
        register_syscore_ops(&cpufreq_syscore_ops);