forked from Minki/linux
Merge branch 'pm-cpufreq'
* pm-cpufreq: (30 commits) intel_pstate: Set core to min P state during core offline cpufreq: Add stop CPU callback to cpufreq_driver interface cpufreq: Remove unnecessary braces cpufreq: Fix checkpatch errors and warnings cpufreq: powerpc: add cpufreq transition latency for FSL e500mc SoCs cpufreq: remove unused notifier: CPUFREQ_{SUSPENDCHANGE|RESUMECHANGE} cpufreq: Do not allow ->setpolicy drivers to provide ->target cpufreq: arm_big_little: set 'physical_cluster' for each CPU cpufreq: arm_big_little: make vexpress driver depend on bL core driver cpufreq: SPEAr: Instantiate as platform_driver cpufreq: Remove unnecessary variable/parameter 'frozen' cpufreq: Remove cpufreq_generic_exit() cpufreq: add 'freq_table' in struct cpufreq_policy cpufreq: Reformat printk() statements cpufreq: Tegra: Use cpufreq_generic_suspend() cpufreq: s5pv210: Use cpufreq_generic_suspend() cpufreq: exynos: Use cpufreq_generic_suspend() cpufreq: Implement cpufreq_generic_suspend() cpufreq: suspend governors on system suspend/hibernate cpufreq: move call to __find_governor() to cpufreq_init_policy() ...
This commit is contained in:
commit
5a2d853ffc
@ -92,7 +92,3 @@ values:
|
||||
cpu - number of the affected CPU
|
||||
old - old frequency
|
||||
new - new frequency
|
||||
|
||||
If the cpufreq core detects the frequency has changed while the system
|
||||
was suspended, these notifiers are called with CPUFREQ_RESUMECHANGE as
|
||||
second argument.
|
||||
|
@ -61,7 +61,13 @@ target_index - See below on the differences.
|
||||
|
||||
And optionally
|
||||
|
||||
cpufreq_driver.exit - A pointer to a per-CPU cleanup function.
|
||||
cpufreq_driver.exit - A pointer to a per-CPU cleanup
|
||||
function called during CPU_POST_DEAD
|
||||
phase of cpu hotplug process.
|
||||
|
||||
cpufreq_driver.stop_cpu - A pointer to a per-CPU stop function
|
||||
called during CPU_DOWN_PREPARE phase of
|
||||
cpu hotplug process.
|
||||
|
||||
cpufreq_driver.resume - A pointer to a per-CPU resume function
|
||||
which is called with interrupts disabled
|
||||
|
@ -674,8 +674,7 @@ static int cpufreq_callback(struct notifier_block *nb,
|
||||
}
|
||||
|
||||
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
|
||||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
|
||||
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
|
||||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
|
||||
loops_per_jiffy = cpufreq_scale(global_l_p_j_ref,
|
||||
global_l_p_j_ref_freq,
|
||||
freq->new);
|
||||
|
@ -166,7 +166,7 @@ static int twd_cpufreq_transition(struct notifier_block *nb,
|
||||
* frequency. The timer is local to a cpu, so cross-call to the
|
||||
* changing cpu.
|
||||
*/
|
||||
if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE)
|
||||
if (state == CPUFREQ_POSTCHANGE)
|
||||
smp_call_function_single(freqs->cpu, twd_update_frequency,
|
||||
NULL, 1);
|
||||
|
||||
|
@ -885,9 +885,6 @@ static int viper_cpufreq_notifier(struct notifier_block *nb,
|
||||
viper_set_core_cpu_voltage(freq->new, 0);
|
||||
}
|
||||
break;
|
||||
case CPUFREQ_RESUMECHANGE:
|
||||
viper_set_core_cpu_voltage(freq->new, 0);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
|
@ -28,6 +28,7 @@
|
||||
static void __init spear1310_dt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
|
||||
}
|
||||
|
||||
static const char * const spear1310_dt_board_compat[] = {
|
||||
|
@ -143,6 +143,7 @@ static void __init spear1340_dt_init(void)
|
||||
{
|
||||
of_platform_populate(NULL, of_default_bus_match_table,
|
||||
spear1340_auxdata_lookup, NULL);
|
||||
platform_device_register_simple("spear-cpufreq", -1, NULL, 0);
|
||||
}
|
||||
|
||||
static const char * const spear1340_dt_board_compat[] = {
|
||||
|
@ -303,6 +303,14 @@ source "drivers/cpuidle/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Power management options"
|
||||
|
||||
source "kernel/power/Kconfig"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
source "net/Kconfig"
|
||||
|
||||
source "drivers/Kconfig"
|
||||
|
@ -1121,8 +1121,7 @@ oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
|
||||
int ret = 0;
|
||||
struct cpufreq_freqs *frq = data;
|
||||
if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
|
||||
(val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
|
||||
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
|
||||
(val == CPUFREQ_POSTCHANGE && frq->old > frq->new))
|
||||
set_spu_profiling_frequency(frq->new, spu_cycle_reset);
|
||||
return ret;
|
||||
}
|
||||
|
@ -659,8 +659,7 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
|
||||
ft->clock_tick_ref = cpu_data(cpu).clock_tick;
|
||||
}
|
||||
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
|
||||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
|
||||
(val == CPUFREQ_RESUMECHANGE)) {
|
||||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
|
||||
cpu_data(cpu).clock_tick =
|
||||
cpufreq_scale(ft->clock_tick_ref,
|
||||
ft->ref_freq,
|
||||
|
@ -914,8 +914,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
tsc_khz_ref = tsc_khz;
|
||||
}
|
||||
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
|
||||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
|
||||
(val == CPUFREQ_RESUMECHANGE)) {
|
||||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) {
|
||||
*lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
|
||||
|
||||
tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/async.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <trace/events/power.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
@ -866,6 +867,8 @@ void dpm_resume(pm_message_t state)
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
async_synchronize_full();
|
||||
dpm_show_time(starttime, state, NULL);
|
||||
|
||||
cpufreq_resume();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1434,6 +1437,8 @@ int dpm_suspend(pm_message_t state)
|
||||
|
||||
might_sleep();
|
||||
|
||||
cpufreq_suspend();
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
pm_transition = state;
|
||||
async_error = 0;
|
||||
|
@ -200,7 +200,7 @@ source "drivers/cpufreq/Kconfig.x86"
|
||||
endmenu
|
||||
|
||||
menu "ARM CPU frequency scaling drivers"
|
||||
depends on ARM
|
||||
depends on ARM || ARM64
|
||||
source "drivers/cpufreq/Kconfig.arm"
|
||||
endmenu
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
# ARM CPU Frequency scaling drivers
|
||||
#
|
||||
|
||||
# big LITTLE core layer and glue drivers
|
||||
config ARM_BIG_LITTLE_CPUFREQ
|
||||
tristate "Generic ARM big LITTLE CPUfreq driver"
|
||||
depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
|
||||
@ -16,6 +17,14 @@ config ARM_DT_BL_CPUFREQ
|
||||
This enables probing via DT for Generic CPUfreq driver for ARM
|
||||
big.LITTLE platform. This gets frequency tables from DT.
|
||||
|
||||
config ARM_VEXPRESS_SPC_CPUFREQ
|
||||
tristate "Versatile Express SPC based CPUfreq driver"
|
||||
depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC
|
||||
help
|
||||
This add the CPUfreq driver support for Versatile Express
|
||||
big.LITTLE platforms using SPC for power management.
|
||||
|
||||
|
||||
config ARM_EXYNOS_CPUFREQ
|
||||
bool
|
||||
|
||||
@ -241,11 +250,3 @@ config ARM_TEGRA_CPUFREQ
|
||||
default y
|
||||
help
|
||||
This adds the CPUFreq driver support for TEGRA SOCs.
|
||||
|
||||
config ARM_VEXPRESS_SPC_CPUFREQ
|
||||
tristate "Versatile Express SPC based CPUfreq driver"
|
||||
select ARM_BIG_LITTLE_CPUFREQ
|
||||
depends on ARCH_VEXPRESS_SPC
|
||||
help
|
||||
This add the CPUfreq driver support for Versatile Express
|
||||
big.LITTLE platforms using SPC for power management.
|
||||
|
@ -855,7 +855,6 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
pr_debug("acpi_cpufreq_cpu_exit\n");
|
||||
|
||||
if (data) {
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
per_cpu(acfreq_data, policy->cpu) = NULL;
|
||||
acpi_processor_unregister_performance(data->acpi_data,
|
||||
policy->cpu);
|
||||
|
@ -446,9 +446,12 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
|
||||
}
|
||||
|
||||
if (cur_cluster < MAX_CLUSTERS) {
|
||||
int cpu;
|
||||
|
||||
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
|
||||
|
||||
per_cpu(physical_cluster, policy->cpu) = cur_cluster;
|
||||
for_each_cpu(cpu, policy->cpus)
|
||||
per_cpu(physical_cluster, cpu) = cur_cluster;
|
||||
} else {
|
||||
/* Assumption: during init, we are always running on A15 */
|
||||
per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
|
||||
@ -478,7 +481,6 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
put_cluster_clk_and_freq_table(cpu_dev);
|
||||
dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
|
||||
|
||||
|
@ -195,7 +195,6 @@ static struct cpufreq_driver bfin_driver = {
|
||||
.target_index = bfin_target,
|
||||
.get = bfin_getfreq_khz,
|
||||
.init = __bfin_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "bfin cpufreq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -109,7 +109,6 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
|
||||
.target_index = cpu0_set_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = cpu0_cpufreq_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "generic_cpu0",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/tick.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
@ -42,10 +42,11 @@ static DEFINE_RWLOCK(cpufreq_driver_lock);
|
||||
DEFINE_MUTEX(cpufreq_governor_lock);
|
||||
static LIST_HEAD(cpufreq_policy_list);
|
||||
|
||||
#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
|
||||
|
||||
/* Flag to suspend/resume CPUFreq governors */
|
||||
static bool cpufreq_suspended;
|
||||
|
||||
static inline bool has_target(void)
|
||||
{
|
||||
@ -181,8 +182,8 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
|
||||
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
|
||||
if (!policy || IS_ERR(policy->clk)) {
|
||||
pr_err("%s: No %s associated to cpu: %d\n", __func__,
|
||||
policy ? "clk" : "policy", cpu);
|
||||
pr_err("%s: No %s associated to cpu: %d\n",
|
||||
__func__, policy ? "clk" : "policy", cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -190,6 +191,12 @@ unsigned int cpufreq_generic_get(unsigned int cpu)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_generic_get);
|
||||
|
||||
/* Only for cpufreq core internal use */
|
||||
struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
|
||||
{
|
||||
return per_cpu(cpufreq_cpu_data, cpu);
|
||||
}
|
||||
|
||||
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = NULL;
|
||||
@ -254,15 +261,14 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
|
||||
if (!l_p_j_ref_freq) {
|
||||
l_p_j_ref = loops_per_jiffy;
|
||||
l_p_j_ref_freq = ci->old;
|
||||
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);
|
||||
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) ||
|
||||
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
|
||||
if (val == CPUFREQ_POSTCHANGE && ci->old != ci->new) {
|
||||
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
|
||||
ci->new);
|
||||
pr_debug("scaling loops_per_jiffy to %lu "
|
||||
"for frequency %u kHz\n", loops_per_jiffy, ci->new);
|
||||
pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
|
||||
loops_per_jiffy, ci->new);
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -282,7 +288,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
|
||||
freqs->flags = cpufreq_driver->flags;
|
||||
pr_debug("notification %u of frequency transition to %u kHz\n",
|
||||
state, freqs->new);
|
||||
state, freqs->new);
|
||||
|
||||
switch (state) {
|
||||
|
||||
@ -294,9 +300,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
|
||||
if ((policy) && (policy->cpu == freqs->cpu) &&
|
||||
(policy->cur) && (policy->cur != freqs->old)) {
|
||||
pr_debug("Warning: CPU frequency is"
|
||||
" %u, cpufreq assumed %u kHz.\n",
|
||||
freqs->old, policy->cur);
|
||||
pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n",
|
||||
freqs->old, policy->cur);
|
||||
freqs->old = policy->cur;
|
||||
}
|
||||
}
|
||||
@ -307,8 +312,8 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
|
||||
case CPUFREQ_POSTCHANGE:
|
||||
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
|
||||
pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
|
||||
(unsigned long)freqs->cpu);
|
||||
pr_debug("FREQ: %lu - CPU: %lu\n",
|
||||
(unsigned long)freqs->new, (unsigned long)freqs->cpu);
|
||||
trace_cpu_frequency(freqs->new, freqs->cpu);
|
||||
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
|
||||
CPUFREQ_POSTCHANGE, freqs);
|
||||
@ -352,7 +357,7 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
|
||||
/*********************************************************************
|
||||
* SYSFS INTERFACE *
|
||||
*********************************************************************/
|
||||
ssize_t show_boost(struct kobject *kobj,
|
||||
static ssize_t show_boost(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
|
||||
@ -368,13 +373,13 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
|
||||
return -EINVAL;
|
||||
|
||||
if (cpufreq_boost_trigger_state(enable)) {
|
||||
pr_err("%s: Cannot %s BOOST!\n", __func__,
|
||||
enable ? "enable" : "disable");
|
||||
pr_err("%s: Cannot %s BOOST!\n",
|
||||
__func__, enable ? "enable" : "disable");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("%s: cpufreq BOOST %s\n", __func__,
|
||||
enable ? "enabled" : "disabled");
|
||||
pr_debug("%s: cpufreq BOOST %s\n",
|
||||
__func__, enable ? "enabled" : "disabled");
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -879,18 +884,25 @@ err_out_kobj_put:
|
||||
|
||||
static void cpufreq_init_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_governor *gov = NULL;
|
||||
struct cpufreq_policy new_policy;
|
||||
int ret = 0;
|
||||
|
||||
memcpy(&new_policy, policy, sizeof(*policy));
|
||||
|
||||
/* Update governor of new_policy to the governor used before hotplug */
|
||||
gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
|
||||
if (gov)
|
||||
pr_debug("Restoring governor %s for cpu %d\n",
|
||||
policy->governor->name, policy->cpu);
|
||||
else
|
||||
gov = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
|
||||
new_policy.governor = gov;
|
||||
|
||||
/* Use the default policy if its valid. */
|
||||
if (cpufreq_driver->setpolicy)
|
||||
cpufreq_parse_governor(policy->governor->name,
|
||||
&new_policy.policy, NULL);
|
||||
|
||||
/* assure that the starting sequence is run in cpufreq_set_policy */
|
||||
policy->governor = NULL;
|
||||
cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
|
||||
|
||||
/* set default policy */
|
||||
ret = cpufreq_set_policy(policy, &new_policy);
|
||||
@ -927,8 +939,11 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
|
||||
up_write(&policy->rwsem);
|
||||
|
||||
if (has_target()) {
|
||||
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
|
||||
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
|
||||
ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
|
||||
if (!ret)
|
||||
ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to start governor\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
@ -949,6 +964,8 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
|
||||
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
policy->governor = NULL;
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
@ -1022,21 +1039,19 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
|
||||
up_write(&policy->rwsem);
|
||||
|
||||
cpufreq_frequency_table_update_policy_cpu(policy);
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_UPDATE_POLICY_CPU, policy);
|
||||
}
|
||||
|
||||
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int j, cpu = dev->id;
|
||||
int ret = -ENOMEM;
|
||||
struct cpufreq_policy *policy;
|
||||
unsigned long flags;
|
||||
bool recover_policy = cpufreq_suspended;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
struct cpufreq_policy *tpolicy;
|
||||
struct cpufreq_governor *gov;
|
||||
#endif
|
||||
|
||||
if (cpu_is_offline(cpu))
|
||||
@ -1075,9 +1090,9 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
* Restore the saved policy when doing light-weight init and fall back
|
||||
* to the full init if that fails.
|
||||
*/
|
||||
policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
|
||||
policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;
|
||||
if (!policy) {
|
||||
frozen = false;
|
||||
recover_policy = false;
|
||||
policy = cpufreq_policy_alloc();
|
||||
if (!policy)
|
||||
goto nomem_out;
|
||||
@ -1089,12 +1104,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
* the creation of a brand new one. So we need to perform this update
|
||||
* by invoking update_policy_cpu().
|
||||
*/
|
||||
if (frozen && cpu != policy->cpu)
|
||||
if (recover_policy && cpu != policy->cpu)
|
||||
update_policy_cpu(policy, cpu);
|
||||
else
|
||||
policy->cpu = cpu;
|
||||
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
cpumask_copy(policy->cpus, cpumask_of(cpu));
|
||||
|
||||
init_completion(&policy->kobj_unregister);
|
||||
@ -1118,7 +1132,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
*/
|
||||
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
|
||||
|
||||
if (!frozen) {
|
||||
if (!recover_policy) {
|
||||
policy->user_policy.min = policy->min;
|
||||
policy->user_policy.max = policy->max;
|
||||
}
|
||||
@ -1180,16 +1194,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_START, policy);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
|
||||
if (gov) {
|
||||
policy->governor = gov;
|
||||
pr_debug("Restoring governor %s for cpu %d\n",
|
||||
policy->governor->name, cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!frozen) {
|
||||
if (!recover_policy) {
|
||||
ret = cpufreq_add_dev_interface(policy, dev);
|
||||
if (ret)
|
||||
goto err_out_unregister;
|
||||
@ -1203,7 +1208,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
|
||||
cpufreq_init_policy(policy);
|
||||
|
||||
if (!frozen) {
|
||||
if (!recover_policy) {
|
||||
policy->user_policy.policy = policy->policy;
|
||||
policy->user_policy.governor = policy->governor;
|
||||
}
|
||||
@ -1226,7 +1231,7 @@ err_get_freq:
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(policy);
|
||||
err_set_policy_cpu:
|
||||
if (frozen) {
|
||||
if (recover_policy) {
|
||||
/* Do not leave stale fallback data behind. */
|
||||
per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
@ -1250,7 +1255,7 @@ nomem_out:
|
||||
*/
|
||||
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
|
||||
{
|
||||
return __cpufreq_add_dev(dev, sif, false);
|
||||
return __cpufreq_add_dev(dev, sif);
|
||||
}
|
||||
|
||||
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
@ -1265,7 +1270,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
|
||||
ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to move kobj: %d", __func__, ret);
|
||||
pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
|
||||
|
||||
down_write(&policy->rwsem);
|
||||
cpumask_set_cpu(old_cpu, policy->cpus);
|
||||
@ -1281,8 +1286,7 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
|
||||
}
|
||||
|
||||
static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int cpu = dev->id, cpus;
|
||||
int new_cpu, ret;
|
||||
@ -1296,7 +1300,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
policy = per_cpu(cpufreq_cpu_data, cpu);
|
||||
|
||||
/* Save the policy somewhere when doing a light-weight tear-down */
|
||||
if (frozen)
|
||||
if (cpufreq_suspended)
|
||||
per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
|
||||
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
@ -1314,11 +1318,9 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
if (!cpufreq_driver->setpolicy)
|
||||
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
|
||||
policy->governor->name, CPUFREQ_NAME_LEN);
|
||||
#endif
|
||||
|
||||
down_read(&policy->rwsem);
|
||||
cpus = cpumask_weight(policy->cpus);
|
||||
@ -1331,19 +1333,19 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
|
||||
if (new_cpu >= 0) {
|
||||
update_policy_cpu(policy, new_cpu);
|
||||
|
||||
if (!frozen) {
|
||||
if (!cpufreq_suspended)
|
||||
pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
|
||||
__func__, new_cpu, cpu);
|
||||
}
|
||||
__func__, new_cpu, cpu);
|
||||
}
|
||||
} else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
|
||||
cpufreq_driver->stop_cpu(policy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
struct subsys_interface *sif,
|
||||
bool frozen)
|
||||
struct subsys_interface *sif)
|
||||
{
|
||||
unsigned int cpu = dev->id, cpus;
|
||||
int ret;
|
||||
@ -1373,12 +1375,12 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to exit governor\n",
|
||||
__func__);
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frozen)
|
||||
if (!cpufreq_suspended)
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
|
||||
/*
|
||||
@ -1394,16 +1396,16 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
|
||||
list_del(&policy->policy_list);
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
if (!frozen)
|
||||
if (!cpufreq_suspended)
|
||||
cpufreq_policy_free(policy);
|
||||
} else {
|
||||
if (has_target()) {
|
||||
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
|
||||
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
|
||||
pr_err("%s: Failed to start governor\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
} else if (has_target()) {
|
||||
ret = __cpufreq_governor(policy, CPUFREQ_GOV_START);
|
||||
if (!ret)
|
||||
ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to start governor\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1424,10 +1426,10 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
|
||||
if (cpu_is_offline(cpu))
|
||||
return 0;
|
||||
|
||||
ret = __cpufreq_remove_dev_prepare(dev, sif, false);
|
||||
ret = __cpufreq_remove_dev_prepare(dev, sif);
|
||||
|
||||
if (!ret)
|
||||
ret = __cpufreq_remove_dev_finish(dev, sif, false);
|
||||
ret = __cpufreq_remove_dev_finish(dev, sif);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1458,8 +1460,8 @@ 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);
|
||||
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
|
||||
old_freq, new_freq);
|
||||
|
||||
freqs.old = old_freq;
|
||||
freqs.new = new_freq;
|
||||
@ -1570,83 +1572,104 @@ static struct subsys_interface cpufreq_interface = {
|
||||
.remove_dev = cpufreq_remove_dev,
|
||||
};
|
||||
|
||||
/**
|
||||
* cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
|
||||
*
|
||||
* This function is only executed for the boot processor. The other CPUs
|
||||
* have been put offline by means of CPU hotplug.
|
||||
/*
|
||||
* In case platform wants some specific frequency to be configured
|
||||
* during suspend..
|
||||
*/
|
||||
static int cpufreq_bp_suspend(void)
|
||||
int cpufreq_generic_suspend(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
pr_debug("suspending cpu %u\n", cpu);
|
||||
|
||||
/* If there's no policy for the boot CPU, we have nothing to do. */
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
return 0;
|
||||
|
||||
if (cpufreq_driver->suspend) {
|
||||
ret = cpufreq_driver->suspend(policy);
|
||||
if (ret)
|
||||
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
|
||||
"step on CPU %u\n", policy->cpu);
|
||||
if (!policy->suspend_freq) {
|
||||
pr_err("%s: suspend_freq can't be zero\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
pr_debug("%s: Setting suspend-freq: %u\n", __func__,
|
||||
policy->suspend_freq);
|
||||
|
||||
ret = __cpufreq_driver_target(policy, policy->suspend_freq,
|
||||
CPUFREQ_RELATION_H);
|
||||
if (ret)
|
||||
pr_err("%s: unable to set suspend-freq: %u. err: %d\n",
|
||||
__func__, policy->suspend_freq, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_generic_suspend);
|
||||
|
||||
/**
|
||||
* cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
|
||||
* cpufreq_suspend() - Suspend CPUFreq governors
|
||||
*
|
||||
* 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
|
||||
* 2.) schedule call cpufreq_update_policy() ASAP as interrupts are
|
||||
* restored. It will verify that the current freq is in sync with
|
||||
* what we believe it to be. This is a bit later than when it
|
||||
* should be, but nonethteless it's better than calling
|
||||
* cpufreq_driver->get() here which might re-enable interrupts...
|
||||
*
|
||||
* This function is only executed for the boot CPU. The other CPUs have not
|
||||
* been turned on yet.
|
||||
* Called during system wide Suspend/Hibernate cycles for suspending governors
|
||||
* as some platforms can't change frequency after this point in suspend cycle.
|
||||
* Because some of the devices (like: i2c, regulators, etc) they use for
|
||||
* changing frequency are suspended quickly after this point.
|
||||
*/
|
||||
static void cpufreq_bp_resume(void)
|
||||
void cpufreq_suspend(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
int cpu = smp_processor_id();
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
pr_debug("resuming cpu %u\n", cpu);
|
||||
|
||||
/* If there's no policy for the boot CPU, we have nothing to do. */
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
if (!cpufreq_driver)
|
||||
return;
|
||||
|
||||
if (cpufreq_driver->resume) {
|
||||
ret = cpufreq_driver->resume(policy);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "cpufreq: resume failed in ->resume "
|
||||
"step on CPU %u\n", policy->cpu);
|
||||
goto fail;
|
||||
}
|
||||
if (!has_target())
|
||||
return;
|
||||
|
||||
pr_debug("%s: Suspending Governors\n", __func__);
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
|
||||
pr_err("%s: Failed to stop governor for policy: %p\n",
|
||||
__func__, policy);
|
||||
else if (cpufreq_driver->suspend
|
||||
&& cpufreq_driver->suspend(policy))
|
||||
pr_err("%s: Failed to suspend driver: %p\n", __func__,
|
||||
policy);
|
||||
}
|
||||
|
||||
schedule_work(&policy->update);
|
||||
|
||||
fail:
|
||||
cpufreq_cpu_put(policy);
|
||||
cpufreq_suspended = true;
|
||||
}
|
||||
|
||||
static struct syscore_ops cpufreq_syscore_ops = {
|
||||
.suspend = cpufreq_bp_suspend,
|
||||
.resume = cpufreq_bp_resume,
|
||||
};
|
||||
/**
|
||||
* cpufreq_resume() - Resume CPUFreq governors
|
||||
*
|
||||
* Called during system wide Suspend/Hibernate cycle for resuming governors that
|
||||
* are suspended with cpufreq_suspend().
|
||||
*/
|
||||
void cpufreq_resume(void)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
if (!cpufreq_driver)
|
||||
return;
|
||||
|
||||
if (!has_target())
|
||||
return;
|
||||
|
||||
pr_debug("%s: Resuming Governors\n", __func__);
|
||||
|
||||
cpufreq_suspended = false;
|
||||
|
||||
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
|
||||
if (__cpufreq_governor(policy, CPUFREQ_GOV_START)
|
||||
|| __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))
|
||||
pr_err("%s: Failed to start governor for policy: %p\n",
|
||||
__func__, policy);
|
||||
else if (cpufreq_driver->resume
|
||||
&& cpufreq_driver->resume(policy))
|
||||
pr_err("%s: Failed to resume driver: %p\n", __func__,
|
||||
policy);
|
||||
|
||||
/*
|
||||
* schedule call cpufreq_update_policy() for boot CPU, i.e. last
|
||||
* policy in list. It will verify that the current freq is in
|
||||
* sync with what we believe it to be.
|
||||
*/
|
||||
if (list_is_last(&policy->policy_list, &cpufreq_policy_list))
|
||||
schedule_work(&policy->update);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cpufreq_get_current_driver - return current driver's name
|
||||
@ -1762,7 +1785,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
target_freq = policy->min;
|
||||
|
||||
pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
|
||||
policy->cpu, target_freq, relation, old_target_freq);
|
||||
policy->cpu, target_freq, relation, old_target_freq);
|
||||
|
||||
/*
|
||||
* This might look like a redundant call as we are checking it again
|
||||
@ -1807,8 +1830,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
freqs.flags = 0;
|
||||
|
||||
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
|
||||
__func__, policy->cpu, freqs.old,
|
||||
freqs.new);
|
||||
__func__, policy->cpu, freqs.old, freqs.new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs,
|
||||
CPUFREQ_PRECHANGE);
|
||||
@ -1817,7 +1839,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
retval = cpufreq_driver->target_index(policy, index);
|
||||
if (retval)
|
||||
pr_err("%s: Failed to change cpu frequency: %d\n",
|
||||
__func__, retval);
|
||||
__func__, retval);
|
||||
|
||||
if (notify)
|
||||
cpufreq_notify_post_transition(policy, &freqs, retval);
|
||||
@ -1863,17 +1885,18 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
||||
struct cpufreq_governor *gov = NULL;
|
||||
#endif
|
||||
|
||||
/* Don't start any governor operations if we are entering suspend */
|
||||
if (cpufreq_suspended)
|
||||
return 0;
|
||||
|
||||
if (policy->governor->max_transition_latency &&
|
||||
policy->cpuinfo.transition_latency >
|
||||
policy->governor->max_transition_latency) {
|
||||
if (!gov)
|
||||
return -EINVAL;
|
||||
else {
|
||||
printk(KERN_WARNING "%s governor failed, too long"
|
||||
" transition latency of HW, fallback"
|
||||
" to %s governor\n",
|
||||
policy->governor->name,
|
||||
gov->name);
|
||||
pr_warn("%s governor failed, too long transition latency of HW, fallback to %s governor\n",
|
||||
policy->governor->name, gov->name);
|
||||
policy->governor = gov;
|
||||
}
|
||||
}
|
||||
@ -1883,7 +1906,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
|
||||
return -EINVAL;
|
||||
|
||||
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_START)
|
||||
@ -1950,9 +1973,7 @@ EXPORT_SYMBOL_GPL(cpufreq_register_governor);
|
||||
|
||||
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
||||
{
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
int cpu;
|
||||
#endif
|
||||
|
||||
if (!governor)
|
||||
return;
|
||||
@ -1960,14 +1981,12 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
|
||||
if (cpufreq_disabled())
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
for_each_present_cpu(cpu) {
|
||||
if (cpu_online(cpu))
|
||||
continue;
|
||||
if (!strcmp(per_cpu(cpufreq_cpu_governor, cpu), governor->name))
|
||||
strcpy(per_cpu(cpufreq_cpu_governor, cpu), "\0");
|
||||
}
|
||||
#endif
|
||||
|
||||
mutex_lock(&cpufreq_governor_mutex);
|
||||
list_del(&governor->governor_list);
|
||||
@ -2012,22 +2031,21 @@ EXPORT_SYMBOL(cpufreq_get_policy);
|
||||
static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
struct cpufreq_policy *new_policy)
|
||||
{
|
||||
int ret = 0, failed = 1;
|
||||
struct cpufreq_governor *old_gov;
|
||||
int ret;
|
||||
|
||||
pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
|
||||
new_policy->min, new_policy->max);
|
||||
pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
|
||||
new_policy->cpu, new_policy->min, new_policy->max);
|
||||
|
||||
memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
|
||||
|
||||
if (new_policy->min > policy->max || new_policy->max < policy->min) {
|
||||
ret = -EINVAL;
|
||||
goto error_out;
|
||||
}
|
||||
if (new_policy->min > policy->max || new_policy->max < policy->min)
|
||||
return -EINVAL;
|
||||
|
||||
/* verify the cpu speed can be set within this limit */
|
||||
ret = cpufreq_driver->verify(new_policy);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
return ret;
|
||||
|
||||
/* adjust if necessary - all reasons */
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
@ -2043,7 +2061,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
*/
|
||||
ret = cpufreq_driver->verify(new_policy);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
return ret;
|
||||
|
||||
/* notification of the new policy */
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
@ -2053,63 +2071,53 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
policy->max = new_policy->max;
|
||||
|
||||
pr_debug("new min and max freqs are %u - %u kHz\n",
|
||||
policy->min, policy->max);
|
||||
policy->min, policy->max);
|
||||
|
||||
if (cpufreq_driver->setpolicy) {
|
||||
policy->policy = new_policy->policy;
|
||||
pr_debug("setting range\n");
|
||||
ret = cpufreq_driver->setpolicy(new_policy);
|
||||
} else {
|
||||
if (new_policy->governor != policy->governor) {
|
||||
/* save old, working values */
|
||||
struct cpufreq_governor *old_gov = policy->governor;
|
||||
|
||||
pr_debug("governor switch\n");
|
||||
|
||||
/* end old governor */
|
||||
if (policy->governor) {
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
/* start new governor */
|
||||
policy->governor = new_policy->governor;
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
|
||||
failed = 0;
|
||||
} else {
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
/* new governor failed, so re-start old one */
|
||||
pr_debug("starting governor %s failed\n",
|
||||
policy->governor->name);
|
||||
if (old_gov) {
|
||||
policy->governor = old_gov;
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_POLICY_INIT);
|
||||
__cpufreq_governor(policy,
|
||||
CPUFREQ_GOV_START);
|
||||
}
|
||||
ret = -EINVAL;
|
||||
goto error_out;
|
||||
}
|
||||
/* might be a policy change, too, so fall through */
|
||||
}
|
||||
pr_debug("governor: change or update limits\n");
|
||||
ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
return cpufreq_driver->setpolicy(new_policy);
|
||||
}
|
||||
|
||||
error_out:
|
||||
return ret;
|
||||
if (new_policy->governor == policy->governor)
|
||||
goto out;
|
||||
|
||||
pr_debug("governor switch\n");
|
||||
|
||||
/* save old, working values */
|
||||
old_gov = policy->governor;
|
||||
/* end old governor */
|
||||
if (old_gov) {
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
/* start new governor */
|
||||
policy->governor = new_policy->governor;
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
|
||||
if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))
|
||||
goto out;
|
||||
|
||||
up_write(&policy->rwsem);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
|
||||
down_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
/* new governor failed, so re-start old one */
|
||||
pr_debug("starting governor %s failed\n", policy->governor->name);
|
||||
if (old_gov) {
|
||||
policy->governor = old_gov;
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
|
||||
__cpufreq_governor(policy, CPUFREQ_GOV_START);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
out:
|
||||
pr_debug("governor: change or update limits\n");
|
||||
return __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2145,8 +2153,13 @@ int cpufreq_update_policy(unsigned int cpu)
|
||||
*/
|
||||
if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
|
||||
new_policy.cur = cpufreq_driver->get(cpu);
|
||||
if (WARN_ON(!new_policy.cur)) {
|
||||
ret = -EIO;
|
||||
goto no_policy;
|
||||
}
|
||||
|
||||
if (!policy->cur) {
|
||||
pr_debug("Driver did not initialize current freq");
|
||||
pr_debug("Driver did not initialize current freq\n");
|
||||
policy->cur = new_policy.cur;
|
||||
} else {
|
||||
if (policy->cur != new_policy.cur && has_target())
|
||||
@ -2170,30 +2183,24 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
|
||||
{
|
||||
unsigned int cpu = (unsigned long)hcpu;
|
||||
struct device *dev;
|
||||
bool frozen = false;
|
||||
|
||||
dev = get_cpu_device(cpu);
|
||||
if (dev) {
|
||||
|
||||
if (action & CPU_TASKS_FROZEN)
|
||||
frozen = true;
|
||||
|
||||
switch (action & ~CPU_TASKS_FROZEN) {
|
||||
case CPU_ONLINE:
|
||||
__cpufreq_add_dev(dev, NULL, frozen);
|
||||
cpufreq_update_policy(cpu);
|
||||
__cpufreq_add_dev(dev, NULL);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_PREPARE:
|
||||
__cpufreq_remove_dev_prepare(dev, NULL, frozen);
|
||||
__cpufreq_remove_dev_prepare(dev, NULL);
|
||||
break;
|
||||
|
||||
case CPU_POST_DEAD:
|
||||
__cpufreq_remove_dev_finish(dev, NULL, frozen);
|
||||
__cpufreq_remove_dev_finish(dev, NULL);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_FAILED:
|
||||
__cpufreq_add_dev(dev, NULL, frozen);
|
||||
__cpufreq_add_dev(dev, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2249,8 +2256,8 @@ int cpufreq_boost_trigger_state(int state)
|
||||
cpufreq_driver->boost_enabled = !state;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
pr_err("%s: Cannot %s BOOST\n", __func__,
|
||||
state ? "enable" : "disable");
|
||||
pr_err("%s: Cannot %s BOOST\n",
|
||||
__func__, state ? "enable" : "disable");
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -2295,7 +2302,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
|
||||
if (!driver_data || !driver_data->verify || !driver_data->init ||
|
||||
!(driver_data->setpolicy || driver_data->target_index ||
|
||||
driver_data->target))
|
||||
driver_data->target) ||
|
||||
(driver_data->setpolicy && (driver_data->target_index ||
|
||||
driver_data->target)))
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("trying to register driver %s\n", driver_data->name);
|
||||
@ -2322,7 +2331,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
ret = cpufreq_sysfs_create_file(&boost.attr);
|
||||
if (ret) {
|
||||
pr_err("%s: cannot register global BOOST sysfs file\n",
|
||||
__func__);
|
||||
__func__);
|
||||
goto err_null_driver;
|
||||
}
|
||||
}
|
||||
@ -2345,7 +2354,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
/* if all ->init() calls failed, unregister */
|
||||
if (ret) {
|
||||
pr_debug("no CPU initialized for driver %s\n",
|
||||
driver_data->name);
|
||||
driver_data->name);
|
||||
goto err_if_unreg;
|
||||
}
|
||||
}
|
||||
@ -2409,7 +2418,6 @@ static int __init cpufreq_core_init(void)
|
||||
|
||||
cpufreq_global_kobject = kobject_create();
|
||||
BUG_ON(!cpufreq_global_kobject);
|
||||
register_syscore_ops(&cpufreq_syscore_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -180,27 +180,25 @@ static void cpufreq_stats_free_table(unsigned int cpu)
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table)
|
||||
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i, j, count = 0, ret = 0;
|
||||
struct cpufreq_stats *stat;
|
||||
struct cpufreq_policy *current_policy;
|
||||
unsigned int alloc_size;
|
||||
unsigned int cpu = policy->cpu;
|
||||
struct cpufreq_frequency_table *table;
|
||||
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (unlikely(!table))
|
||||
return 0;
|
||||
|
||||
if (per_cpu(cpufreq_stats_table, cpu))
|
||||
return -EBUSY;
|
||||
stat = kzalloc(sizeof(*stat), GFP_KERNEL);
|
||||
if ((stat) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
current_policy = cpufreq_cpu_get(cpu);
|
||||
if (current_policy == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto error_get_fail;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(¤t_policy->kobj, &stats_attr_group);
|
||||
ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
@ -223,7 +221,7 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
|
||||
stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
|
||||
if (!stat->time_in_state) {
|
||||
ret = -ENOMEM;
|
||||
goto error_out;
|
||||
goto error_alloc;
|
||||
}
|
||||
stat->freq_table = (unsigned int *)(stat->time_in_state + count);
|
||||
|
||||
@ -243,11 +241,10 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
|
||||
stat->last_time = get_jiffies_64();
|
||||
stat->last_index = freq_table_get_index(stat, policy->cur);
|
||||
spin_unlock(&cpufreq_stats_lock);
|
||||
cpufreq_cpu_put(current_policy);
|
||||
return 0;
|
||||
error_alloc:
|
||||
sysfs_remove_group(&policy->kobj, &stats_attr_group);
|
||||
error_out:
|
||||
cpufreq_cpu_put(current_policy);
|
||||
error_get_fail:
|
||||
kfree(stat);
|
||||
per_cpu(cpufreq_stats_table, cpu) = NULL;
|
||||
return ret;
|
||||
@ -256,7 +253,6 @@ error_get_fail:
|
||||
static void cpufreq_stats_create_table(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_frequency_table *table;
|
||||
|
||||
/*
|
||||
* "likely(!policy)" because normally cpufreq_stats will be registered
|
||||
@ -266,9 +262,7 @@ static void cpufreq_stats_create_table(unsigned int cpu)
|
||||
if (likely(!policy))
|
||||
return;
|
||||
|
||||
table = cpufreq_frequency_get_table(policy->cpu);
|
||||
if (likely(table))
|
||||
__cpufreq_stats_create_table(policy, table);
|
||||
__cpufreq_stats_create_table(policy);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
@ -291,20 +285,14 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
|
||||
{
|
||||
int ret = 0;
|
||||
struct cpufreq_policy *policy = data;
|
||||
struct cpufreq_frequency_table *table;
|
||||
unsigned int cpu = policy->cpu;
|
||||
|
||||
if (val == CPUFREQ_UPDATE_POLICY_CPU) {
|
||||
cpufreq_stats_update_policy_cpu(policy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (!table)
|
||||
return 0;
|
||||
|
||||
if (val == CPUFREQ_CREATE_POLICY)
|
||||
ret = __cpufreq_stats_create_table(policy, table);
|
||||
ret = __cpufreq_stats_create_table(policy);
|
||||
else if (val == CPUFREQ_REMOVE_POLICY)
|
||||
__cpufreq_stats_free_table(policy);
|
||||
|
||||
|
@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = cris_freq_target,
|
||||
.init = cris_freq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "cris_freq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -57,7 +57,6 @@ static struct cpufreq_driver cris_freq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = cris_freq_target,
|
||||
.init = cris_freq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "cris_freq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -125,7 +125,6 @@ static struct cpufreq_driver davinci_driver = {
|
||||
.target_index = davinci_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = davinci_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "davinci",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -382,7 +382,6 @@ static int eps_cpu_exit(struct cpufreq_policy *policy)
|
||||
unsigned int cpu = policy->cpu;
|
||||
|
||||
/* Bye */
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
kfree(eps_cpu[cpu]);
|
||||
eps_cpu[cpu] = NULL;
|
||||
return 0;
|
||||
|
@ -198,7 +198,6 @@ static struct cpufreq_driver elanfreq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = elanfreq_target,
|
||||
.init = elanfreq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "elanfreq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/cpu.h>
|
||||
@ -24,12 +23,8 @@
|
||||
#include "exynos-cpufreq.h"
|
||||
|
||||
static struct exynos_dvfs_info *exynos_info;
|
||||
|
||||
static struct regulator *arm_regulator;
|
||||
|
||||
static unsigned int locking_frequency;
|
||||
static bool frequency_locked;
|
||||
static DEFINE_MUTEX(cpufreq_lock);
|
||||
|
||||
static int exynos_cpufreq_get_index(unsigned int freq)
|
||||
{
|
||||
@ -134,83 +129,13 @@ out:
|
||||
|
||||
static int exynos_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&cpufreq_lock);
|
||||
|
||||
if (frequency_locked)
|
||||
goto out;
|
||||
|
||||
ret = exynos_cpufreq_scale(freq_table[index].frequency);
|
||||
|
||||
out:
|
||||
mutex_unlock(&cpufreq_lock);
|
||||
|
||||
return ret;
|
||||
return exynos_cpufreq_scale(exynos_info->freq_table[index].frequency);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_cpufreq_resume(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* exynos_cpufreq_pm_notifier - block CPUFREQ's activities in suspend-resume
|
||||
* context
|
||||
* @notifier
|
||||
* @pm_event
|
||||
* @v
|
||||
*
|
||||
* While frequency_locked == true, target() ignores every frequency but
|
||||
* locking_frequency. The locking_frequency value is the initial frequency,
|
||||
* which is set by the bootloader. In order to eliminate possible
|
||||
* inconsistency in clock values, we save and restore frequencies during
|
||||
* suspend and resume and block CPUFREQ activities. Note that the standard
|
||||
* suspend/resume cannot be used as they are too deep (syscore_ops) for
|
||||
* regulator actions.
|
||||
*/
|
||||
static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
|
||||
unsigned long pm_event, void *v)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (pm_event) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
mutex_lock(&cpufreq_lock);
|
||||
frequency_locked = true;
|
||||
mutex_unlock(&cpufreq_lock);
|
||||
|
||||
ret = exynos_cpufreq_scale(locking_frequency);
|
||||
if (ret < 0)
|
||||
return NOTIFY_BAD;
|
||||
|
||||
break;
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
mutex_lock(&cpufreq_lock);
|
||||
frequency_locked = false;
|
||||
mutex_unlock(&cpufreq_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block exynos_cpufreq_nb = {
|
||||
.notifier_call = exynos_cpufreq_pm_notifier,
|
||||
};
|
||||
|
||||
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
policy->clk = exynos_info->cpu_clk;
|
||||
policy->suspend_freq = locking_frequency;
|
||||
return cpufreq_generic_init(policy, exynos_info->freq_table, 100000);
|
||||
}
|
||||
|
||||
@ -220,15 +145,13 @@ static struct cpufreq_driver exynos_driver = {
|
||||
.target_index = exynos_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = exynos_cpufreq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "exynos_cpufreq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
#ifdef CONFIG_ARM_EXYNOS_CPU_FREQ_BOOST_SW
|
||||
.boost_supported = true,
|
||||
#endif
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = exynos_cpufreq_suspend,
|
||||
.resume = exynos_cpufreq_resume,
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -263,19 +186,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
|
||||
goto err_vdd_arm;
|
||||
}
|
||||
|
||||
/* Done here as we want to capture boot frequency */
|
||||
locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
|
||||
|
||||
register_pm_notifier(&exynos_cpufreq_nb);
|
||||
|
||||
if (cpufreq_register_driver(&exynos_driver)) {
|
||||
pr_err("%s: failed to register cpufreq driver\n", __func__);
|
||||
goto err_cpufreq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_cpufreq:
|
||||
unregister_pm_notifier(&exynos_cpufreq_nb);
|
||||
if (!cpufreq_register_driver(&exynos_driver))
|
||||
return 0;
|
||||
|
||||
pr_err("%s: failed to register cpufreq driver\n", __func__);
|
||||
regulator_put(arm_regulator);
|
||||
err_vdd_arm:
|
||||
kfree(exynos_info);
|
||||
|
@ -312,7 +312,6 @@ static struct cpufreq_driver exynos_driver = {
|
||||
.target_index = exynos_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = exynos_cpufreq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = CPUFREQ_NAME,
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -91,8 +91,8 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
|
||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
|
||||
|
||||
/*
|
||||
* Generic routine to verify policy & frequency table, requires driver to call
|
||||
* cpufreq_frequency_table_get_attr() prior to it.
|
||||
* Generic routine to verify policy & frequency table, requires driver to set
|
||||
* policy->freq_table prior to it.
|
||||
*/
|
||||
int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
|
||||
{
|
||||
@ -203,8 +203,6 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
|
||||
|
||||
static DEFINE_PER_CPU(struct cpufreq_frequency_table *, cpufreq_show_table);
|
||||
|
||||
/**
|
||||
* show_available_freqs - show available frequencies for the specified CPU
|
||||
*/
|
||||
@ -212,15 +210,12 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
|
||||
bool show_boost)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int cpu = policy->cpu;
|
||||
ssize_t count = 0;
|
||||
struct cpufreq_frequency_table *table;
|
||||
struct cpufreq_frequency_table *table = policy->freq_table;
|
||||
|
||||
if (!per_cpu(cpufreq_show_table, cpu))
|
||||
if (!table)
|
||||
return -ENODEV;
|
||||
|
||||
table = per_cpu(cpufreq_show_table, cpu);
|
||||
|
||||
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
@ -283,49 +278,24 @@ struct freq_attr *cpufreq_generic_attr[] = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
|
||||
|
||||
/*
|
||||
* if you use these, you must assure that the frequency table is valid
|
||||
* all the time between get_attr and put_attr!
|
||||
*/
|
||||
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
|
||||
unsigned int cpu)
|
||||
{
|
||||
pr_debug("setting show_table for cpu %u to %p\n", cpu, table);
|
||||
per_cpu(cpufreq_show_table, cpu) = table;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
|
||||
|
||||
void cpufreq_frequency_table_put_attr(unsigned int cpu)
|
||||
{
|
||||
pr_debug("clearing show_table for cpu %u\n", cpu);
|
||||
per_cpu(cpufreq_show_table, cpu) = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
|
||||
|
||||
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table)
|
||||
{
|
||||
int ret = cpufreq_frequency_table_cpuinfo(policy, table);
|
||||
|
||||
if (!ret)
|
||||
cpufreq_frequency_table_get_attr(table, policy->cpu);
|
||||
policy->freq_table = table;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
|
||||
|
||||
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy)
|
||||
{
|
||||
pr_debug("Updating show_table for new_cpu %u from last_cpu %u\n",
|
||||
policy->cpu, policy->last_cpu);
|
||||
per_cpu(cpufreq_show_table, policy->cpu) = per_cpu(cpufreq_show_table,
|
||||
policy->last_cpu);
|
||||
per_cpu(cpufreq_show_table, policy->last_cpu) = NULL;
|
||||
}
|
||||
struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
|
||||
|
||||
struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
|
||||
{
|
||||
return per_cpu(cpufreq_show_table, cpu);
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
|
||||
return policy ? policy->freq_table : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
|
||||
|
||||
|
@ -332,7 +332,6 @@ acpi_cpufreq_cpu_exit (
|
||||
pr_debug("acpi_cpufreq_cpu_exit\n");
|
||||
|
||||
if (data) {
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
acpi_io_data[policy->cpu] = NULL;
|
||||
acpi_processor_unregister_performance(&data->acpi_data,
|
||||
policy->cpu);
|
||||
|
@ -144,7 +144,6 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
|
||||
.target_index = imx6q_set_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = imx6q_cpufreq_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "imx6q-cpufreq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -99,8 +99,7 @@ struct cpudata {
|
||||
u64 prev_aperf;
|
||||
u64 prev_mperf;
|
||||
unsigned long long prev_tsc;
|
||||
int sample_ptr;
|
||||
struct sample samples[SAMPLE_COUNT];
|
||||
struct sample sample;
|
||||
};
|
||||
|
||||
static struct cpudata **all_cpu_data;
|
||||
@ -154,7 +153,7 @@ static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
|
||||
pid->setpoint = setpoint;
|
||||
pid->deadband = deadband;
|
||||
pid->integral = int_tofp(integral);
|
||||
pid->last_err = setpoint - busy;
|
||||
pid->last_err = int_tofp(setpoint) - int_tofp(busy);
|
||||
}
|
||||
|
||||
static inline void pid_p_gain_set(struct _pid *pid, int percent)
|
||||
@ -447,7 +446,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
|
||||
if (limits.no_turbo)
|
||||
val |= (u64)1 << 32;
|
||||
|
||||
wrmsrl(MSR_IA32_PERF_CTL, val);
|
||||
wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
|
||||
}
|
||||
|
||||
static struct cpu_defaults core_params = {
|
||||
@ -586,15 +585,14 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
|
||||
mperf = mperf >> FRAC_BITS;
|
||||
tsc = tsc >> FRAC_BITS;
|
||||
|
||||
cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
|
||||
cpu->samples[cpu->sample_ptr].aperf = aperf;
|
||||
cpu->samples[cpu->sample_ptr].mperf = mperf;
|
||||
cpu->samples[cpu->sample_ptr].tsc = tsc;
|
||||
cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
|
||||
cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
|
||||
cpu->samples[cpu->sample_ptr].tsc -= cpu->prev_tsc;
|
||||
cpu->sample.aperf = aperf;
|
||||
cpu->sample.mperf = mperf;
|
||||
cpu->sample.tsc = tsc;
|
||||
cpu->sample.aperf -= cpu->prev_aperf;
|
||||
cpu->sample.mperf -= cpu->prev_mperf;
|
||||
cpu->sample.tsc -= cpu->prev_tsc;
|
||||
|
||||
intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
|
||||
intel_pstate_calc_busy(cpu, &cpu->sample);
|
||||
|
||||
cpu->prev_aperf = aperf;
|
||||
cpu->prev_mperf = mperf;
|
||||
@ -614,7 +612,7 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
|
||||
{
|
||||
int32_t core_busy, max_pstate, current_pstate;
|
||||
|
||||
core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
|
||||
core_busy = cpu->sample.core_pct_busy;
|
||||
max_pstate = int_tofp(cpu->pstate.max_pstate);
|
||||
current_pstate = int_tofp(cpu->pstate.current_pstate);
|
||||
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
|
||||
@ -648,7 +646,7 @@ static void intel_pstate_timer_func(unsigned long __data)
|
||||
|
||||
intel_pstate_sample(cpu);
|
||||
|
||||
sample = &cpu->samples[cpu->sample_ptr];
|
||||
sample = &cpu->sample;
|
||||
|
||||
intel_pstate_adjust_busy_pstate(cpu);
|
||||
|
||||
@ -729,7 +727,7 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
|
||||
cpu = all_cpu_data[cpu_num];
|
||||
if (!cpu)
|
||||
return 0;
|
||||
sample = &cpu->samples[cpu->sample_ptr];
|
||||
sample = &cpu->sample;
|
||||
return sample->freq;
|
||||
}
|
||||
|
||||
@ -773,14 +771,17 @@ static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
|
||||
static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
|
||||
{
|
||||
int cpu = policy->cpu;
|
||||
int cpu_num = policy->cpu;
|
||||
struct cpudata *cpu = all_cpu_data[cpu_num];
|
||||
|
||||
del_timer(&all_cpu_data[cpu]->timer);
|
||||
kfree(all_cpu_data[cpu]);
|
||||
all_cpu_data[cpu] = NULL;
|
||||
return 0;
|
||||
pr_info("intel_pstate CPU %d exiting\n", cpu_num);
|
||||
|
||||
del_timer(&all_cpu_data[cpu_num]->timer);
|
||||
intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
|
||||
kfree(all_cpu_data[cpu_num]);
|
||||
all_cpu_data[cpu_num] = NULL;
|
||||
}
|
||||
|
||||
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||
@ -818,7 +819,7 @@ static struct cpufreq_driver intel_pstate_driver = {
|
||||
.setpolicy = intel_pstate_set_policy,
|
||||
.get = intel_pstate_get,
|
||||
.init = intel_pstate_cpu_init,
|
||||
.exit = intel_pstate_cpu_exit,
|
||||
.stop_cpu = intel_pstate_stop_cpu,
|
||||
.name = "intel_pstate",
|
||||
};
|
||||
|
||||
|
@ -102,7 +102,6 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = kirkwood_cpufreq_target,
|
||||
.init = kirkwood_cpufreq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "kirkwood-cpufreq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -913,7 +913,6 @@ static struct cpufreq_driver longhaul_driver = {
|
||||
.target_index = longhaul_target,
|
||||
.get = longhaul_get,
|
||||
.init = longhaul_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "longhaul",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -104,7 +104,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
|
||||
static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
clk_put(policy->clk);
|
||||
return 0;
|
||||
}
|
||||
|
@ -143,7 +143,6 @@ fail:
|
||||
|
||||
static int omap_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
freq_table_free();
|
||||
clk_put(policy->clk);
|
||||
return 0;
|
||||
|
@ -237,7 +237,6 @@ static struct cpufreq_driver p4clockmod_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = cpufreq_p4_target,
|
||||
.init = cpufreq_p4_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.get = cpufreq_p4_get,
|
||||
.name = "p4-clockmod",
|
||||
.attr = cpufreq_generic_attr,
|
||||
|
@ -234,7 +234,6 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
if (sdcpwr_mapbase)
|
||||
iounmap(sdcpwr_mapbase);
|
||||
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,6 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
|
||||
if (i == max_multiplier)
|
||||
powernow_k6_target(policy, i);
|
||||
}
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -664,8 +664,6 @@ static int powernow_cpu_init(struct cpufreq_policy *policy)
|
||||
|
||||
static int powernow_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
|
||||
#ifdef CONFIG_X86_POWERNOW_K7_ACPI
|
||||
if (acpi_processor_perf) {
|
||||
acpi_processor_unregister_performance(acpi_processor_perf, 0);
|
||||
|
@ -1164,8 +1164,6 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
|
||||
|
||||
powernow_k8_cpu_exit_acpi(data);
|
||||
|
||||
cpufreq_frequency_table_put_attr(pol->cpu);
|
||||
|
||||
kfree(data->powernow_table);
|
||||
kfree(data);
|
||||
for_each_cpu(cpu, pol->cpus)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
|
||||
/**
|
||||
* struct cpu_data - per CPU data struct
|
||||
@ -205,7 +206,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
for_each_cpu(i, per_cpu(cpu_mask, cpu))
|
||||
per_cpu(cpu_data, i) = data;
|
||||
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
policy->cpuinfo.transition_latency =
|
||||
(12 * NSEC_PER_SEC) / fsl_get_sys_freq();
|
||||
of_node_put(np);
|
||||
|
||||
return 0;
|
||||
@ -228,7 +230,6 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
|
||||
unsigned int cpu;
|
||||
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
of_node_put(data->parent);
|
||||
kfree(data->table);
|
||||
kfree(data);
|
||||
|
@ -141,7 +141,6 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = cbe_cpufreq_target,
|
||||
.init = cbe_cpufreq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "cbe-cpufreq",
|
||||
.flags = CPUFREQ_CONST_LOOPS,
|
||||
};
|
||||
|
@ -427,7 +427,6 @@ static struct cpufreq_driver pxa_cpufreq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = pxa_set_target,
|
||||
.init = pxa_cpufreq_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.get = pxa_cpufreq_get,
|
||||
.name = "PXA2xx",
|
||||
};
|
||||
|
@ -205,7 +205,6 @@ static struct cpufreq_driver pxa3xx_cpufreq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = pxa3xx_cpufreq_set,
|
||||
.init = pxa3xx_cpufreq_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.get = pxa3xx_cpufreq_get,
|
||||
.name = "pxa3xx-cpufreq",
|
||||
};
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/regs-clock.h>
|
||||
@ -435,18 +434,6 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check_mem_type(void __iomem *dmc_reg)
|
||||
{
|
||||
unsigned long val;
|
||||
@ -502,6 +489,7 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
|
||||
s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000);
|
||||
s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
|
||||
|
||||
policy->suspend_freq = SLEEP_FREQ;
|
||||
return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
|
||||
|
||||
out_dmc1:
|
||||
@ -511,32 +499,6 @@ out_dmc0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s5pv210_cpufreq_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case PM_SUSPEND_PREPARE:
|
||||
ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
|
||||
if (ret < 0)
|
||||
return NOTIFY_BAD;
|
||||
|
||||
/* Disable updation of cpu frequency */
|
||||
no_cpufreq_access = true;
|
||||
return NOTIFY_OK;
|
||||
case PM_POST_RESTORE:
|
||||
case PM_POST_SUSPEND:
|
||||
/* Enable updation of cpu frequency */
|
||||
no_cpufreq_access = false;
|
||||
cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
@ -558,15 +520,11 @@ static struct cpufreq_driver s5pv210_driver = {
|
||||
.init = s5pv210_cpu_init,
|
||||
.name = "s5pv210",
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = s5pv210_cpufreq_suspend,
|
||||
.resume = s5pv210_cpufreq_resume,
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
.resume = cpufreq_generic_suspend, /* We need to set SLEEP FREQ again */
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct notifier_block s5pv210_cpufreq_notifier = {
|
||||
.notifier_call = s5pv210_cpufreq_notifier_event,
|
||||
};
|
||||
|
||||
static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
|
||||
.notifier_call = s5pv210_cpufreq_reboot_notifier_event,
|
||||
};
|
||||
@ -586,7 +544,6 @@ static int __init s5pv210_cpufreq_init(void)
|
||||
return PTR_ERR(int_regulator);
|
||||
}
|
||||
|
||||
register_pm_notifier(&s5pv210_cpufreq_notifier);
|
||||
register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
|
||||
|
||||
return cpufreq_register_driver(&s5pv210_driver);
|
||||
|
@ -93,7 +93,6 @@ static struct cpufreq_driver sc520_freq_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = sc520_freq_target,
|
||||
.init = sc520_freq_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "sc520_freq",
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -143,7 +143,6 @@ static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
unsigned int cpu = policy->cpu;
|
||||
struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
|
||||
|
||||
cpufreq_frequency_table_put_attr(cpu);
|
||||
clk_put(cpuclk);
|
||||
|
||||
return 0;
|
||||
|
@ -301,10 +301,8 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
|
||||
|
||||
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (cpufreq_us2e_driver) {
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
if (cpufreq_us2e_driver)
|
||||
us2e_freq_target(policy, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -156,10 +156,8 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
|
||||
|
||||
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (cpufreq_us3_driver) {
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
if (cpufreq_us3_driver)
|
||||
us3_freq_target(policy, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
@ -163,11 +164,10 @@ static struct cpufreq_driver spear_cpufreq_driver = {
|
||||
.target_index = spear_cpufreq_target,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = spear_cpufreq_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
||||
static int spear_cpufreq_driver_init(void)
|
||||
static int spear_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np;
|
||||
const struct property *prop;
|
||||
@ -235,7 +235,15 @@ out_put_node:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
late_initcall(spear_cpufreq_driver_init);
|
||||
|
||||
static struct platform_driver spear_cpufreq_platdrv = {
|
||||
.driver = {
|
||||
.name = "spear-cpufreq",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = spear_cpufreq_probe,
|
||||
};
|
||||
module_platform_driver(spear_cpufreq_platdrv);
|
||||
|
||||
MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>");
|
||||
MODULE_DESCRIPTION("SPEAr CPUFreq driver");
|
||||
|
@ -406,8 +406,6 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
|
||||
if (!per_cpu(centrino_model, cpu))
|
||||
return -ENODEV;
|
||||
|
||||
cpufreq_frequency_table_put_attr(cpu);
|
||||
|
||||
per_cpu(centrino_model, cpu) = NULL;
|
||||
|
||||
return 0;
|
||||
|
@ -311,7 +311,6 @@ static struct cpufreq_driver speedstep_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = speedstep_target,
|
||||
.init = speedstep_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.get = speedstep_get,
|
||||
.attr = cpufreq_generic_attr,
|
||||
};
|
||||
|
@ -280,7 +280,6 @@ static struct cpufreq_driver speedstep_driver = {
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = speedstep_target,
|
||||
.init = speedstep_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.get = speedstep_get,
|
||||
.resume = speedstep_resume,
|
||||
.attr = cpufreq_generic_attr,
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
static struct cpufreq_frequency_table freq_table[] = {
|
||||
{ .frequency = 216000 },
|
||||
@ -47,9 +46,6 @@ static struct clk *pll_x_clk;
|
||||
static struct clk *pll_p_clk;
|
||||
static struct clk *emc_clk;
|
||||
|
||||
static DEFINE_MUTEX(tegra_cpu_lock);
|
||||
static bool is_suspended;
|
||||
|
||||
static int tegra_cpu_clk_set_rate(unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
@ -112,42 +108,9 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
|
||||
|
||||
static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
int ret = -EBUSY;
|
||||
|
||||
mutex_lock(&tegra_cpu_lock);
|
||||
|
||||
if (!is_suspended)
|
||||
ret = tegra_update_cpu_speed(policy,
|
||||
freq_table[index].frequency);
|
||||
|
||||
mutex_unlock(&tegra_cpu_lock);
|
||||
return ret;
|
||||
return tegra_update_cpu_speed(policy, freq_table[index].frequency);
|
||||
}
|
||||
|
||||
static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
|
||||
void *dummy)
|
||||
{
|
||||
mutex_lock(&tegra_cpu_lock);
|
||||
if (event == PM_SUSPEND_PREPARE) {
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
|
||||
is_suspended = true;
|
||||
pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
|
||||
freq_table[0].frequency);
|
||||
if (clk_get_rate(cpu_clk) / 1000 != freq_table[0].frequency)
|
||||
tegra_update_cpu_speed(policy, freq_table[0].frequency);
|
||||
cpufreq_cpu_put(policy);
|
||||
} else if (event == PM_POST_SUSPEND) {
|
||||
is_suspended = false;
|
||||
}
|
||||
mutex_unlock(&tegra_cpu_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block tegra_cpu_pm_notifier = {
|
||||
.notifier_call = tegra_pm_notify,
|
||||
};
|
||||
|
||||
static int tegra_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret;
|
||||
@ -166,16 +129,13 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (policy->cpu == 0)
|
||||
register_pm_notifier(&tegra_cpu_pm_notifier);
|
||||
|
||||
policy->clk = cpu_clk;
|
||||
policy->suspend_freq = freq_table[0].frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
clk_disable_unprepare(cpu_clk);
|
||||
clk_disable_unprepare(emc_clk);
|
||||
return 0;
|
||||
@ -190,6 +150,9 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
|
||||
.exit = tegra_cpu_exit,
|
||||
.name = "tegra",
|
||||
.attr = cpufreq_generic_attr,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init tegra_cpufreq_init(void)
|
||||
|
@ -125,9 +125,6 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
|
||||
if (freqs->new < freqs->old)
|
||||
sa1100_pcmcia_set_mecr(skt, freqs->new);
|
||||
break;
|
||||
case CPUFREQ_RESUMECHANGE:
|
||||
sa1100_pcmcia_set_mecr(skt, freqs->new);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1041,8 +1041,7 @@ static int sci_notifier(struct notifier_block *self,
|
||||
|
||||
sci_port = container_of(self, struct sci_port, freq_transition);
|
||||
|
||||
if ((phase == CPUFREQ_POSTCHANGE) ||
|
||||
(phase == CPUFREQ_RESUMECHANGE)) {
|
||||
if (phase == CPUFREQ_POSTCHANGE) {
|
||||
struct uart_port *port = &sci_port->port;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
@ -74,6 +74,8 @@ struct cpufreq_policy {
|
||||
unsigned int max; /* in kHz */
|
||||
unsigned int cur; /* in kHz, only needed if cpufreq
|
||||
* governors are used */
|
||||
unsigned int suspend_freq; /* freq to set during suspend */
|
||||
|
||||
unsigned int policy; /* see above */
|
||||
struct cpufreq_governor *governor; /* see below */
|
||||
void *governor_data;
|
||||
@ -83,6 +85,7 @@ struct cpufreq_policy {
|
||||
* called, but you're in IRQ context */
|
||||
|
||||
struct cpufreq_real_policy user_policy;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
|
||||
struct list_head policy_list;
|
||||
struct kobject kobj;
|
||||
@ -224,6 +227,7 @@ struct cpufreq_driver {
|
||||
int (*bios_limit) (int cpu, unsigned int *limit);
|
||||
|
||||
int (*exit) (struct cpufreq_policy *policy);
|
||||
void (*stop_cpu) (struct cpufreq_policy *policy);
|
||||
int (*suspend) (struct cpufreq_policy *policy);
|
||||
int (*resume) (struct cpufreq_policy *policy);
|
||||
struct freq_attr **attr;
|
||||
@ -296,6 +300,15 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
|
||||
policy->cpuinfo.max_freq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
void cpufreq_suspend(void);
|
||||
void cpufreq_resume(void);
|
||||
int cpufreq_generic_suspend(struct cpufreq_policy *policy);
|
||||
#else
|
||||
static inline void cpufreq_suspend(void) {}
|
||||
static inline void cpufreq_resume(void) {}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* CPUFREQ NOTIFIER INTERFACE *
|
||||
*********************************************************************/
|
||||
@ -306,8 +319,6 @@ cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
|
||||
/* Transition notifiers */
|
||||
#define CPUFREQ_PRECHANGE (0)
|
||||
#define CPUFREQ_POSTCHANGE (1)
|
||||
#define CPUFREQ_RESUMECHANGE (8)
|
||||
#define CPUFREQ_SUSPENDCHANGE (9)
|
||||
|
||||
/* Policy Notifiers */
|
||||
#define CPUFREQ_ADJUST (0)
|
||||
@ -463,7 +474,6 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
|
||||
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
|
||||
unsigned int freq);
|
||||
|
||||
void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
|
||||
ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
@ -490,9 +500,6 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
|
||||
/* the following are really really optional */
|
||||
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
|
||||
extern struct freq_attr *cpufreq_generic_attr[];
|
||||
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
|
||||
unsigned int cpu);
|
||||
void cpufreq_frequency_table_put_attr(unsigned int cpu);
|
||||
int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table);
|
||||
|
||||
@ -500,10 +507,4 @@ unsigned int cpufreq_generic_get(unsigned int cpu);
|
||||
int cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table,
|
||||
unsigned int transition_latency);
|
||||
static inline int cpufreq_generic_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_CPUFREQ_H */
|
||||
|
Loading…
Reference in New Issue
Block a user