ACPI and power management updates for 3.15-rc1

- Device PM QoS support for latency tolerance constraints on systems with
    hardware interfaces allowing such constraints to be specified.  That is
    necessary to prevent hardware-driven power management from becoming
    overly aggressive on some systems and to prevent power management
    features leading to excessive latencies from being used in some cases.
 
  - Consolidation of the handling of ACPI hotplug notifications for device
    objects.  This causes all device hotplug notifications to go through
    the root notify handler (that was executed for all of them anyway
    before) that propagates them to individual subsystems, if necessary,
    by executing callbacks provided by those subsystems (those callbacks
    are associated with struct acpi_device objects during device
    enumeration).  As a result, the code in question becomes both smaller
    in size and more straightforward and all of those changes should not
    affect users.
 
  - ACPICA update, including fixes related to the handling of _PRT in cases
    when it is broken and the addition of "Windows 2013" to the list of
    supported "features" for _OSI (which is necessary to support systems
    that work incorrectly or don't even boot without it).  Changes from
    Bob Moore and Lv Zheng.
 
  - Consolidation of ACPI _OST handling from Jiang Liu.
 
  - ACPI battery and AC fixes allowing unusual system configurations to
    be handled by that code from Alexander Mezin.
 
  - New device IDs for the ACPI LPSS driver from Chiau Ee Chew.
 
  - ACPI fan and thermal optimizations related to system suspend and resume
    from Aaron Lu.
 
  - Cleanups related to ACPI video from Jean Delvare.
 
  - Assorted ACPI fixes and cleanups from Al Stone, Hanjun Guo, Lan Tianyu,
    Paul Bolle, Tomasz Nowicki.
 
  - Intel RAPL (Running Average Power Limits) driver cleanups from Jacob Pan.
 
  - intel_pstate fixes and cleanups from Dirk Brandewie.
 
  - cpufreq fixes related to system suspend/resume handling from Viresh Kumar.
 
  - cpufreq core fixes and cleanups from Viresh Kumar, Stratos Karafotis,
    Saravana Kannan, Rashika Kheria, Joe Perches.
 
  - cpufreq drivers updates from Viresh Kumar, Zhuoyu Zhang, Rob Herring.
 
  - cpuidle fixes related to the menu governor from Tuukka Tikkanen.
 
  - cpuidle fix related to coupled CPUs handling from Paul Burton.
 
  - Asynchronous execution of all device suspend and resume callbacks,
    except for ->prepare and ->complete, during system suspend and resume
    from Chuansheng Liu.
 
  - Delayed resuming of runtime-suspended devices during system suspend for
    the PCI bus type and ACPI PM domain.
 
  - New set of PM helper routines to allow device runtime PM callbacks to
    be used during system suspend and resume more easily from Ulf Hansson.
 
  - Assorted fixes and cleanups in the PM core from Geert Uytterhoeven,
    Prabhakar Lad, Philipp Zabel, Rashika Kheria, Sebastian Capella.
 
  - devfreq fix from Saravana Kannan.
 
 /
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJTLgB1AAoJEILEb/54YlRxfs4P/35fIu9h8ClNWUPXqi3nlGIt
 yMyumKvF1VdsOKLbjTtFq6B3UOlhqDijYTCQd7Xt7X8ONTk/ND9ec2t/5xGkSdUI
 q46fa0qZXeqUn0Kt2t+kl6tgVQOkDj94aNlEh+7Ya3Uu6WYDDfmZtOBOFAMk6D8l
 ND4rHJpX+eUsRLBrcxaUxxdD8AW5guGcPKyeyzsXv1bY1BZnpLFrZ3PhuI5dn2CL
 L/zmk3A+wG6+ZlQxnwDdrKa3E6uhRSIDeF0vI4Byspa1wi5zXknJG2J7MoQ9JEE9
 VQpBXlqach5wgXqJ8PAqAeaB6Ie26/F7PYG8r446zKw/5UUtdNUx+0dkjQ7Mz8Tu
 ajuVxfwrrPhZeQqmVBxlH5Gg7Ez2KBKEfDxTdRnzI7FoA7PE5XDcg3kO64bhj8LJ
 yugnV/ToU9wMztZnPC7CoGPwUgxMJvr9LwmxS4aeKcVUBES05eg0vS3lwdZMgqkV
 iO0QkWTmhZ952qZCqZxbh0JqaaX8Wgx2kpX2tf1G2GJqLMZco289bLh6njNT+8CH
 EzdQKYYyn6G6+Qg2M0f/6So3qU17x9XtE4ZBWQdGDpqYOGZhjZAOs/VnB1Ysw/K3
 cDBzswlJd0CyyUps9B+qbf49OpbWVwl5kKeuHUuPxugEVryhpSp9AuG+tNil74Sj
 JuGTGR4fyFjDBX5cvAPm
 =ywR6
 -----END PGP SIGNATURE-----

Merge tag 'pm+acpi-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI and power management updates from Rafael Wysocki:
 "The majority of this material spent some time in linux-next, some of
  it even several weeks.  There are a few relatively fresh commits in
  it, but they are mostly fixes and simple cleanups.

  ACPI took the lead this time, both in terms of the number of commits
  and the number of modified lines of code, cpufreq follows and there
  are a few changes in the PM core and in cpuidle too.

  A new feature that already got some LWN.net's attention is the device
  PM QoS extension allowing latency tolerance requirements to be
  propagated from leaf devices to their ancestors with hardware
  interfaces for specifying latency tolerance.  That should help systems
  with hardware-driven power management to avoid going too far with it
  in cases when there are latency tolerance constraints.

  There also are some significant changes in the ACPI core related to
  the way in which hotplug notifications are handled.  They affect PCI
  hotplug (ACPIPHP) and the ACPI dock station code too.  The bottom line
  is that all those notification now go through the root notify handler
  and are propagated to the interested subsystems by means of callbacks
  instead of having to install a notify handler for each device object
  that we can potentially get hotplug notifications for.

  In addition to that ACPICA will now advertise "Windows 2013"
  compatibility for _OSI, because some systems out there don't work
  correctly if that is not done (some of them don't even boot).

  On the system suspend side of things, all of the device suspend and
  resume callbacks, except for ->prepare() and ->complete(), are now
  going to be executed asynchronously as that turns out to speed up
  system suspend and resume on some platforms quite significantly and we
  have a few more optimizations in that area.

  Apart from that, there are some new device IDs and fixes and cleanups
  all over.  In particular, the system suspend and resume handling by
  cpufreq should be improved and the cpuidle menu governor should be a
  bit more robust now.

  Specifics:

   - Device PM QoS support for latency tolerance constraints on systems
     with hardware interfaces allowing such constraints to be specified.
     That is necessary to prevent hardware-driven power management from
     becoming overly aggressive on some systems and to prevent power
     management features leading to excessive latencies from being used
     in some cases.

   - Consolidation of the handling of ACPI hotplug notifications for
     device objects.  This causes all device hotplug notifications to go
     through the root notify handler (that was executed for all of them
     anyway before) that propagates them to individual subsystems, if
     necessary, by executing callbacks provided by those subsystems
     (those callbacks are associated with struct acpi_device objects
     during device enumeration).  As a result, the code in question
     becomes both smaller in size and more straightforward and all of
     those changes should not affect users.

   - ACPICA update, including fixes related to the handling of _PRT in
     cases when it is broken and the addition of "Windows 2013" to the
     list of supported "features" for _OSI (which is necessary to
     support systems that work incorrectly or don't even boot without
     it).  Changes from Bob Moore and Lv Zheng.

   - Consolidation of ACPI _OST handling from Jiang Liu.

   - ACPI battery and AC fixes allowing unusual system configurations to
     be handled by that code from Alexander Mezin.

   - New device IDs for the ACPI LPSS driver from Chiau Ee Chew.

   - ACPI fan and thermal optimizations related to system suspend and
     resume from Aaron Lu.

   - Cleanups related to ACPI video from Jean Delvare.

   - Assorted ACPI fixes and cleanups from Al Stone, Hanjun Guo, Lan
     Tianyu, Paul Bolle, Tomasz Nowicki.

   - Intel RAPL (Running Average Power Limits) driver cleanups from
     Jacob Pan.

   - intel_pstate fixes and cleanups from Dirk Brandewie.

   - cpufreq fixes related to system suspend/resume handling from Viresh
     Kumar.

   - cpufreq core fixes and cleanups from Viresh Kumar, Stratos
     Karafotis, Saravana Kannan, Rashika Kheria, Joe Perches.

   - cpufreq drivers updates from Viresh Kumar, Zhuoyu Zhang, Rob
     Herring.

   - cpuidle fixes related to the menu governor from Tuukka Tikkanen.

   - cpuidle fix related to coupled CPUs handling from Paul Burton.

   - Asynchronous execution of all device suspend and resume callbacks,
     except for ->prepare and ->complete, during system suspend and
     resume from Chuansheng Liu.

   - Delayed resuming of runtime-suspended devices during system suspend
     for the PCI bus type and ACPI PM domain.

   - New set of PM helper routines to allow device runtime PM callbacks
     to be used during system suspend and resume more easily from Ulf
     Hansson.

   - Assorted fixes and cleanups in the PM core from Geert Uytterhoeven,
     Prabhakar Lad, Philipp Zabel, Rashika Kheria, Sebastian Capella.

   - devfreq fix from Saravana Kannan"

* tag 'pm+acpi-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (162 commits)
  PM / devfreq: Rewrite devfreq_update_status() to fix multiple bugs
  PM / sleep: Correct whitespace errors in <linux/pm.h>
  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
  MAINTAINERS: Reorder maintainer addresses for PM and ACPI
  PM / Runtime: Update runtime_idle() documentation for return value meaning
  video / output: Drop display output class support
  fujitsu-laptop: Drop unneeded include
  acer-wmi: Stop selecting VIDEO_OUTPUT_CONTROL
  ACPI / gpu / drm: Stop selecting VIDEO_OUTPUT_CONTROL
  ACPI / video: fix ACPI_VIDEO dependencies
  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
  ACPI / button: Add ACPI Button event via netlink routine
  ACPI: Remove duplicate definitions of PREFIX
  ...
This commit is contained in:
Linus Torvalds 2014-04-01 12:48:54 -07:00
commit 4dedde7c7a
331 changed files with 3140 additions and 2764 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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;
}

View file

@ -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(&current_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);

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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;

View file

@ -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,
};

View file

@ -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);

View file

@ -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,
};

View file

@ -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);

View file

@ -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);

View file

@ -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,
};

View file

@ -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",
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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;
}

View file

@ -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;

View file

@ -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,

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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,
};

View file

@ -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",
};

View file

@ -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",
};

View file

@ -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);

View file

@ -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,
};

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 <[email protected]>");
MODULE_DESCRIPTION("SPEAr CPUFreq driver");

View file

@ -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;

View file

@ -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,
};

View file

@ -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,

View file

@ -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)