|
@@ -3,6 +3,7 @@
|
|
*
|
|
*
|
|
* Copyright (C) 2001 Russell King
|
|
* Copyright (C) 2001 Russell King
|
|
* (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
|
|
* (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
|
|
|
|
+ * (C) 2013 Viresh Kumar <viresh.kumar@linaro.org>
|
|
*
|
|
*
|
|
* Oct 2005 - Ashok Raj <ashok.raj@intel.com>
|
|
* Oct 2005 - Ashok Raj <ashok.raj@intel.com>
|
|
* Added handling for CPU hotplug
|
|
* Added handling for CPU hotplug
|
|
@@ -12,12 +13,13 @@
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* 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
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
* published by the Free Software Foundation.
|
|
- *
|
|
|
|
*/
|
|
*/
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
|
|
|
+#include <asm/cputime.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
|
|
+#include <linux/kernel_stat.h>
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/init.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/notifier.h>
|
|
@@ -25,6 +27,7 @@
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
+#include <linux/tick.h>
|
|
#include <linux/device.h>
|
|
#include <linux/device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpu.h>
|
|
@@ -41,11 +44,13 @@
|
|
*/
|
|
*/
|
|
static struct cpufreq_driver *cpufreq_driver;
|
|
static struct cpufreq_driver *cpufreq_driver;
|
|
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
|
|
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
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
/* This one keeps track of the previously set governor of a removed 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);
|
|
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
|
|
#endif
|
|
#endif
|
|
-static DEFINE_RWLOCK(cpufreq_driver_lock);
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
|
|
* 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;
|
|
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)
|
|
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))
|
|
if (!try_module_get(cpufreq_driver->owner))
|
|
goto err_out_unlock;
|
|
goto err_out_unlock;
|
|
|
|
|
|
-
|
|
|
|
/* get the CPU */
|
|
/* get the CPU */
|
|
data = per_cpu(cpufreq_cpu_data, 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
|
|
#ifndef CONFIG_SMP
|
|
static unsigned long l_p_j_ref;
|
|
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)
|
|
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; "
|
|
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);
|
|
"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)) {
|
|
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
|
|
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
|
|
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
|
|
ci->new);
|
|
ci->new);
|
|
@@ -248,8 +297,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
|
}
|
|
}
|
|
#endif
|
|
#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)
|
|
struct cpufreq_freqs *freqs, unsigned int state)
|
|
{
|
|
{
|
|
BUG_ON(irqs_disabled());
|
|
BUG_ON(irqs_disabled());
|
|
@@ -294,6 +342,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
|
|
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
|
|
* on frequency transition.
|
|
* on frequency transition.
|
|
@@ -311,7 +360,6 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
|
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
|
|
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
/*********************************************************************
|
|
/*********************************************************************
|
|
* SYSFS INTERFACE *
|
|
* SYSFS INTERFACE *
|
|
*********************************************************************/
|
|
*********************************************************************/
|
|
@@ -376,7 +424,6 @@ out:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* cpufreq_per_cpu_attr_read() / show_##file_name() -
|
|
* cpufreq_per_cpu_attr_read() / show_##file_name() -
|
|
* print out cpufreq information
|
|
* 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);
|
|
return sprintf(buf, "%u\n", cur_freq);
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* show_scaling_governor - show the current policy for the specified CPU
|
|
* 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;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* store_scaling_governor - store policy for the specified CPU
|
|
* 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))
|
|
&new_policy.governor))
|
|
return -EINVAL;
|
|
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);
|
|
ret = __cpufreq_set_policy(policy, &new_policy);
|
|
|
|
|
|
policy->user_policy.policy = policy->policy;
|
|
policy->user_policy.policy = policy->policy;
|
|
@@ -630,9 +677,6 @@ static struct attribute *default_attrs[] = {
|
|
NULL
|
|
NULL
|
|
};
|
|
};
|
|
|
|
|
|
-struct kobject *cpufreq_global_kobject;
|
|
|
|
-EXPORT_SYMBOL(cpufreq_global_kobject);
|
|
|
|
-
|
|
|
|
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
|
|
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
|
|
#define to_attr(a) container_of(a, struct freq_attr, attr)
|
|
#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,
|
|
.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 */
|
|
/* symlink affected CPUs */
|
|
static int cpufreq_add_dev_symlink(unsigned int cpu,
|
|
static int cpufreq_add_dev_symlink(unsigned int cpu,
|
|
struct cpufreq_policy *policy)
|
|
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.
|
|
* Caller should already have policy_rwsem in write mode for this CPU.
|
|
* This routine frees the rwsem before returning.
|
|
* 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 int cpu = dev->id, ret, cpus;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -1112,7 +1200,6 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
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;
|
|
unsigned int cpu = dev->id;
|
|
@@ -1125,7 +1212,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
static void handle_update(struct work_struct *work)
|
|
static void handle_update(struct work_struct *work)
|
|
{
|
|
{
|
|
struct cpufreq_policy *policy =
|
|
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
|
|
* @cpu: cpu number
|
|
* @old_freq: CPU frequency the kernel thinks the CPU runs at
|
|
* @old_freq: CPU frequency the kernel thinks the CPU runs at
|
|
* @new_freq: CPU frequency the CPU actually 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;
|
|
struct cpufreq_freqs freqs;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
-
|
|
|
|
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
|
|
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
|
|
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
|
|
"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_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
|
|
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
|
|
* @cpu: CPU number
|
|
* @cpu: CPU number
|
|
@@ -1212,7 +1297,6 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(cpufreq_quick_get_max);
|
|
EXPORT_SYMBOL(cpufreq_quick_get_max);
|
|
|
|
|
|
-
|
|
|
|
static unsigned int __cpufreq_get(unsigned int cpu)
|
|
static unsigned int __cpufreq_get(unsigned int cpu)
|
|
{
|
|
{
|
|
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, 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,
|
|
.remove_dev = cpufreq_remove_dev,
|
|
};
|
|
};
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
|
|
* 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);
|
|
EXPORT_SYMBOL(cpufreq_register_notifier);
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* cpufreq_unregister_notifier - unregister a driver with cpufreq
|
|
* cpufreq_unregister_notifier - unregister a driver with cpufreq
|
|
* @nb: notifier block to be unregistered
|
|
* @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.
|
|
* Remove a driver from the CPU frequency notifier list.
|
|
*
|
|
*
|
|
@@ -1448,7 +1530,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
|
|
* GOVERNORS *
|
|
* GOVERNORS *
|
|
*********************************************************************/
|
|
*********************************************************************/
|
|
|
|
|
|
-
|
|
|
|
int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
unsigned int target_freq,
|
|
unsigned int target_freq,
|
|
unsigned int relation)
|
|
unsigned int relation)
|
|
@@ -1484,10 +1565,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
{
|
|
{
|
|
int ret = -EINVAL;
|
|
int ret = -EINVAL;
|
|
|
|
|
|
- policy = cpufreq_cpu_get(policy->cpu);
|
|
|
|
- if (!policy)
|
|
|
|
- goto no_policy;
|
|
|
|
-
|
|
|
|
if (unlikely(lock_policy_rwsem_write(policy->cpu)))
|
|
if (unlikely(lock_policy_rwsem_write(policy->cpu)))
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
|
@@ -1496,30 +1573,19 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
|
|
unlock_policy_rwsem_write(policy->cpu);
|
|
unlock_policy_rwsem_write(policy->cpu);
|
|
|
|
|
|
fail:
|
|
fail:
|
|
- cpufreq_cpu_put(policy);
|
|
|
|
-no_policy:
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
|
|
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
|
|
|
|
|
|
int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
|
|
int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
|
|
{
|
|
{
|
|
- int ret = 0;
|
|
|
|
-
|
|
|
|
if (cpufreq_disabled())
|
|
if (cpufreq_disabled())
|
|
- return ret;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
if (!cpufreq_driver->getavg)
|
|
if (!cpufreq_driver->getavg)
|
|
return 0;
|
|
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);
|
|
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",
|
|
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
|
|
policy->cpu, event);
|
|
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);
|
|
ret = policy->governor->governor(policy, event);
|
|
|
|
|
|
if (!ret) {
|
|
if (!ret) {
|
|
@@ -1569,6 +1650,14 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
|
policy->governor->initialized++;
|
|
policy->governor->initialized++;
|
|
else if (event == CPUFREQ_GOV_POLICY_EXIT)
|
|
else if (event == CPUFREQ_GOV_POLICY_EXIT)
|
|
policy->governor->initialized--;
|
|
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
|
|
/* we keep one module reference alive for
|
|
@@ -1581,7 +1670,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
int cpufreq_register_governor(struct cpufreq_governor *governor)
|
|
int cpufreq_register_governor(struct cpufreq_governor *governor)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
@@ -1606,7 +1694,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(cpufreq_register_governor);
|
|
EXPORT_SYMBOL_GPL(cpufreq_register_governor);
|
|
|
|
|
|
-
|
|
|
|
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
|
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
|
{
|
|
{
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
@@ -1636,7 +1723,6 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
|
EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
|
|
EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
/*********************************************************************
|
|
/*********************************************************************
|
|
* POLICY INTERFACE *
|
|
* POLICY INTERFACE *
|
|
*********************************************************************/
|
|
*********************************************************************/
|
|
@@ -1665,7 +1751,6 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(cpufreq_get_policy);
|
|
EXPORT_SYMBOL(cpufreq_get_policy);
|
|
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* data : current policy.
|
|
* data : current policy.
|
|
* policy : policy to be set.
|
|
* 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,
|
|
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
|
CPUFREQ_INCOMPATIBLE, policy);
|
|
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);
|
|
ret = cpufreq_driver->verify(policy);
|
|
if (ret)
|
|
if (ret)
|
|
goto error_out;
|
|
goto error_out;
|
|
@@ -1802,8 +1889,10 @@ int cpufreq_update_policy(unsigned int cpu)
|
|
policy.policy = data->user_policy.policy;
|
|
policy.policy = data->user_policy.policy;
|
|
policy.governor = data->user_policy.governor;
|
|
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) {
|
|
if (cpufreq_driver->get) {
|
|
policy.cur = cpufreq_driver->get(cpu);
|
|
policy.cur = cpufreq_driver->get(cpu);
|
|
if (!data->cur) {
|
|
if (!data->cur) {
|
|
@@ -1852,7 +1941,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
|
|
}
|
|
}
|
|
|
|
|
|
static struct notifier_block __refdata cpufreq_cpu_notifier = {
|
|
static struct notifier_block __refdata cpufreq_cpu_notifier = {
|
|
- .notifier_call = cpufreq_cpu_callback,
|
|
|
|
|
|
+ .notifier_call = cpufreq_cpu_callback,
|
|
};
|
|
};
|
|
|
|
|
|
/*********************************************************************
|
|
/*********************************************************************
|
|
@@ -1864,7 +1953,7 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
|
|
* @driver_data: A struct cpufreq_driver containing the values#
|
|
* @driver_data: A struct cpufreq_driver containing the values#
|
|
* submitted by the CPU Frequency driver.
|
|
* 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
|
|
* returns zero on success, -EBUSY when another driver got here first
|
|
* (and isn't unregistered in the meantime).
|
|
* (and isn't unregistered in the meantime).
|
|
*
|
|
*
|
|
@@ -1931,11 +2020,10 @@ err_null_driver:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
|
|
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
|
|
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* cpufreq_unregister_driver - unregister the current CPUFreq 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!
|
|
* 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
|
|
* Returns zero if successful, and -EINVAL if the cpufreq_driver is
|
|
* currently not initialised.
|
|
* currently not initialised.
|
|
@@ -1972,7 +2060,7 @@ static int __init cpufreq_core_init(void)
|
|
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
|
|
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);
|
|
BUG_ON(!cpufreq_global_kobject);
|
|
register_syscore_ops(&cpufreq_syscore_ops);
|
|
register_syscore_ops(&cpufreq_syscore_ops);
|
|
|
|
|