Merge branch 'pm-cpufreq'

* pm-cpufreq: (40 commits)
  thermal: exynos: boost: Automatic enable/disable of BOOST feature (at Exynos4412)
  cpufreq: exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ
  Documentation: cpufreq / boost: Update BOOST documentation
  cpufreq: exynos: Extend Exynos cpufreq driver to support boost
  cpufreq / boost: Kconfig: Support for software-managed BOOST
  acpi-cpufreq: Adjust the code to use the common boost attribute
  cpufreq: Add boost frequency support in core
  intel_pstate: Add trace point to report internal state.
  cpufreq: introduce cpufreq_generic_get() routine
  ARM: SA1100: Create dummy clk_get_rate() to avoid build failures
  cpufreq: stats: create sysfs entries when cpufreq_stats is a module
  cpufreq: stats: free table and remove sysfs entry in a single routine
  cpufreq: stats: remove hotplug notifiers
  cpufreq: stats: handle cpufreq_unregister_driver() and suspend/resume properly
  cpufreq: speedstep: remove unused speedstep_get_state
  powernow-k6: reorder frequencies
  powernow-k6: correctly initialize default parameters
  powernow-k6: disable cache when changing frequency
  Documentation: add ABI entry for intel_pstate
  cpufreq: exynos: Convert exynos-cpufreq to platform driver
  ...
This commit is contained in:
Rafael J. Wysocki
2014-01-17 02:01:32 +01:00
51 changed files with 1020 additions and 610 deletions
@@ -200,3 +200,27 @@ Description: address and size of the percpu note.
note of cpu#. note of cpu#.
crash_notes_size: size of the note of cpu#. crash_notes_size: size of the note of cpu#.
What: /sys/devices/system/cpu/intel_pstate/max_perf_pct
/sys/devices/system/cpu/intel_pstate/min_perf_pct
/sys/devices/system/cpu/intel_pstate/no_turbo
Date: February 2013
Contact: linux-pm@vger.kernel.org
Description: Parameters for the Intel P-state driver
Logic for selecting the current P-state in Intel
Sandybridge+ processors. The three knobs control
limits for the P-state that will be requested by the
driver.
max_perf_pct: limits the maximum P state that will be requested by
the driver stated as a percentage of the available performance.
min_perf_pct: limits the minimum P state that will be requested by
the driver stated as a percentage of the available performance.
no_turbo: limits the driver to selecting P states below the turbo
frequency range.
More details can be found in Documentation/cpu-freq/intel-pstate.txt
+13 -13
View File
@@ -17,8 +17,8 @@ Introduction
Some CPUs support a functionality to raise the operating frequency of Some CPUs support a functionality to raise the operating frequency of
some cores in a multi-core package if certain conditions apply, mostly some cores in a multi-core package if certain conditions apply, mostly
if the whole chip is not fully utilized and below it's intended thermal if the whole chip is not fully utilized and below it's intended thermal
budget. This is done without operating system control by a combination budget. The decision about boost disable/enable is made either at hardware
of hardware and firmware. (e.g. x86) or software (e.g ARM).
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core", On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
in technical documentation "Core performance boost". In Linux we use in technical documentation "Core performance boost". In Linux we use
the term "boost" for convenience. the term "boost" for convenience.
@@ -48,24 +48,24 @@ be desirable:
User controlled switch User controlled switch
---------------------- ----------------------
To allow the user to toggle the boosting functionality, the acpi-cpufreq To allow the user to toggle the boosting functionality, the cpufreq core
driver exports a sysfs knob to disable it. There is a file: driver exports a sysfs knob to enable or disable it. There is a file:
/sys/devices/system/cpu/cpufreq/boost /sys/devices/system/cpu/cpufreq/boost
which can either read "0" (boosting disabled) or "1" (boosting enabled). which can either read "0" (boosting disabled) or "1" (boosting enabled).
Reading the file is always supported, even if the processor does not The file is exported only when cpufreq driver supports boosting.
support boosting. In this case the file will be read-only and always Explicitly changing the permissions and writing to that file anyway will
reads as "0". Explicitly changing the permissions and writing to that return EINVAL.
file anyway will return EINVAL.
On supported CPUs one can write either a "0" or a "1" into this file. On supported CPUs one can write either a "0" or a "1" into this file.
This will either disable the boost functionality on all cores in the This will either disable the boost functionality on all cores in the
whole system (0) or will allow the hardware to boost at will (1). whole system (0) or will allow the software or hardware to boost at will
(1).
Writing a "1" does not explicitly boost the system, but just allows the Writing a "1" does not explicitly boost the system, but just allows the
CPU (and the firmware) to boost at their discretion. Some implementations CPU to boost at their discretion. Some implementations take external
take external factors like the chip's temperature into account, so factors like the chip's temperature into account, so boosting once does
boosting once does not necessarily mean that it will occur every time not necessarily mean that it will occur every time even using the exact
even using the exact same software setup. same software setup.
AMD legacy cpb switch AMD legacy cpb switch
+40
View File
@@ -0,0 +1,40 @@
Intel P-state driver
--------------------
This driver implements a scaling driver with an internal governor for
Intel Core processors. The driver follows the same model as the
Transmeta scaling driver (longrun.c) and implements the setpolicy()
instead of target(). Scaling drivers that implement setpolicy() are
assumed to implement internal governors by the cpufreq core. All the
logic for selecting the current P state is contained within the
driver; no external governor is used by the cpufreq core.
Intel SandyBridge+ processors are supported.
New sysfs files for controlling P state selection have been added to
/sys/devices/system/cpu/intel_pstate/
max_perf_pct: limits the maximum P state that will be requested by
the driver stated as a percentage of the available performance.
min_perf_pct: limits the minimum P state that will be requested by
the driver stated as a percentage of the available performance.
no_turbo: limits the driver to selecting P states below the turbo
frequency range.
For contemporary Intel processors, the frequency is controlled by the
processor itself and the P-states exposed to software are related to
performance levels. The idea that frequency can be set to a single
frequency is fiction for Intel Core processors. Even if the scaling
driver selects a single P state the actual frequency the processor
will run at is selected by the processor itself.
New debugfs files have also been added to /sys/kernel/debug/pstate_snb/
deadband
d_gain_pct
i_gain_pct
p_gain_pct
sample_rate_ms
setpoint
+5
View File
@@ -303,6 +303,11 @@ void __init exynos_cpuidle_init(void)
platform_device_register(&exynos_cpuidle); platform_device_register(&exynos_cpuidle);
} }
void __init exynos_cpufreq_init(void)
{
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
}
void __init exynos_init_late(void) void __init exynos_init_late(void)
{ {
if (of_machine_is_compatible("samsung,exynos5440")) if (of_machine_is_compatible("samsung,exynos5440"))
+1
View File
@@ -22,6 +22,7 @@ void exynos_init_io(void);
void exynos4_restart(enum reboot_mode mode, const char *cmd); void exynos4_restart(enum reboot_mode mode, const char *cmd);
void exynos5_restart(enum reboot_mode mode, const char *cmd); void exynos5_restart(enum reboot_mode mode, const char *cmd);
void exynos_cpuidle_init(void); void exynos_cpuidle_init(void);
void exynos_cpufreq_init(void);
void exynos_init_late(void); void exynos_init_late(void);
void exynos_firmware_init(void); void exynos_firmware_init(void);
+1
View File
@@ -22,6 +22,7 @@
static void __init exynos4_dt_machine_init(void) static void __init exynos4_dt_machine_init(void)
{ {
exynos_cpuidle_init(); exynos_cpuidle_init();
exynos_cpufreq_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
} }
+1
View File
@@ -44,6 +44,7 @@ static void __init exynos5_dt_machine_init(void)
} }
exynos_cpuidle_init(); exynos_cpuidle_init();
exynos_cpufreq_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
} }
+7
View File
@@ -33,6 +33,13 @@ struct clk clk_##_name = { \
static DEFINE_SPINLOCK(clocks_lock); static DEFINE_SPINLOCK(clocks_lock);
/* Dummy clk routine to build generic kernel parts that may be using them */
unsigned long clk_get_rate(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_get_rate);
static void clk_gpio27_enable(struct clk *clk) static void clk_gpio27_enable(struct clk *clk)
{ {
/* /*
+6 -1
View File
@@ -20,6 +20,10 @@ if CPU_FREQ
config CPU_FREQ_GOV_COMMON config CPU_FREQ_GOV_COMMON
bool bool
config CPU_FREQ_BOOST_SW
bool
depends on THERMAL
config CPU_FREQ_STAT config CPU_FREQ_STAT
tristate "CPU frequency translation statistics" tristate "CPU frequency translation statistics"
default y default y
@@ -181,7 +185,8 @@ config CPU_FREQ_GOV_CONSERVATIVE
config GENERIC_CPUFREQ_CPU0 config GENERIC_CPUFREQ_CPU0
tristate "Generic CPU0 cpufreq driver" tristate "Generic CPU0 cpufreq driver"
depends on HAVE_CLK && REGULATOR && PM_OPP && OF depends on HAVE_CLK && REGULATOR && OF
select PM_OPP
help help
This adds a generic cpufreq driver for CPU0 frequency management. This adds a generic cpufreq driver for CPU0 frequency management.
It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
+22 -5
View File
@@ -4,7 +4,8 @@
config ARM_BIG_LITTLE_CPUFREQ config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver" tristate "Generic ARM big LITTLE CPUfreq driver"
depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
select PM_OPP
help help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
@@ -54,7 +55,8 @@ config ARM_EXYNOS5250_CPUFREQ
config ARM_EXYNOS5440_CPUFREQ config ARM_EXYNOS5440_CPUFREQ
bool "SAMSUNG EXYNOS5440" bool "SAMSUNG EXYNOS5440"
depends on SOC_EXYNOS5440 depends on SOC_EXYNOS5440
depends on HAVE_CLK && PM_OPP && OF depends on HAVE_CLK && OF
select PM_OPP
default y default y
help help
This adds the CPUFreq driver for Samsung EXYNOS5440 This adds the CPUFreq driver for Samsung EXYNOS5440
@@ -64,6 +66,21 @@ config ARM_EXYNOS5440_CPUFREQ
If in doubt, say N. If in doubt, say N.
config ARM_EXYNOS_CPU_FREQ_BOOST_SW
bool "EXYNOS Frequency Overclocking - Software"
depends on ARM_EXYNOS_CPUFREQ
select CPU_FREQ_BOOST_SW
select EXYNOS_THERMAL
help
This driver supports software managed overclocking (BOOST).
It allows usage of special frequencies for Samsung Exynos
processors if thermal conditions are appropriate.
It reguires, for safe operation, thermal framework with properly
defined trip points.
If in doubt, say N.
config ARM_HIGHBANK_CPUFREQ config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based" tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK depends on ARCH_HIGHBANK
@@ -79,11 +96,11 @@ config ARM_HIGHBANK_CPUFREQ
If in doubt, say N. If in doubt, say N.
config ARM_IMX6Q_CPUFREQ config ARM_IMX6Q_CPUFREQ
tristate "Freescale i.MX6Q cpufreq support" tristate "Freescale i.MX6 cpufreq support"
depends on SOC_IMX6Q depends on ARCH_MXC
depends on REGULATOR_ANATOP depends on REGULATOR_ANATOP
help help
This adds cpufreq driver support for Freescale i.MX6Q SOC. This adds cpufreq driver support for Freescale i.MX6 series SoCs.
If in doubt, say N. If in doubt, say N.
+29 -57
View File
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver; static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict; static unsigned int acpi_pstate_strict;
static bool boost_enabled, boost_supported;
static struct msr __percpu *msrs; static struct msr __percpu *msrs;
static bool boost_state(unsigned int cpu) static bool boost_state(unsigned int cpu)
@@ -133,49 +132,16 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
wrmsr_on_cpus(cpumask, msr_addr, msrs); wrmsr_on_cpus(cpumask, msr_addr, msrs);
} }
static ssize_t _store_boost(const char *buf, size_t count) static int _store_boost(int val)
{ {
int ret;
unsigned long val = 0;
if (!boost_supported)
return -EINVAL;
ret = kstrtoul(buf, 10, &val);
if (ret || (val > 1))
return -EINVAL;
if ((val && boost_enabled) || (!val && !boost_enabled))
return count;
get_online_cpus(); get_online_cpus();
boost_set_msrs(val, cpu_online_mask); boost_set_msrs(val, cpu_online_mask);
put_online_cpus(); put_online_cpus();
boost_enabled = val;
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis"); pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
return count; return 0;
} }
static ssize_t store_global_boost(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
return _store_boost(buf, count);
}
static ssize_t show_global_boost(struct kobject *kobj,
struct attribute *attr, char *buf)
{
return sprintf(buf, "%u\n", boost_enabled);
}
static struct global_attr global_boost = __ATTR(boost, 0644,
show_global_boost,
store_global_boost);
static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf) static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
{ {
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
@@ -186,15 +152,32 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
cpufreq_freq_attr_ro(freqdomain_cpus); cpufreq_freq_attr_ro(freqdomain_cpus);
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB #ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
static ssize_t store_boost(const char *buf, size_t count)
{
int ret;
unsigned long val = 0;
if (!acpi_cpufreq_driver.boost_supported)
return -EINVAL;
ret = kstrtoul(buf, 10, &val);
if (ret || (val > 1))
return -EINVAL;
_store_boost((int) val);
return count;
}
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf, static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count) size_t count)
{ {
return _store_boost(buf, count); return store_boost(buf, count);
} }
static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf) static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
{ {
return sprintf(buf, "%u\n", boost_enabled); return sprintf(buf, "%u\n", acpi_cpufreq_driver.boost_enabled);
} }
cpufreq_freq_attr_rw(cpb); cpufreq_freq_attr_rw(cpb);
@@ -554,7 +537,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
switch (action) { switch (action) {
case CPU_UP_PREPARE: case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN: case CPU_UP_PREPARE_FROZEN:
boost_set_msrs(boost_enabled, cpumask); boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
break; break;
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
@@ -911,6 +894,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.resume = acpi_cpufreq_resume, .resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq", .name = "acpi-cpufreq",
.attr = acpi_cpufreq_attr, .attr = acpi_cpufreq_attr,
.set_boost = _store_boost,
}; };
static void __init acpi_cpufreq_boost_init(void) static void __init acpi_cpufreq_boost_init(void)
@@ -921,33 +905,22 @@ static void __init acpi_cpufreq_boost_init(void)
if (!msrs) if (!msrs)
return; return;
boost_supported = true; acpi_cpufreq_driver.boost_supported = true;
boost_enabled = boost_state(0); acpi_cpufreq_driver.boost_enabled = boost_state(0);
get_online_cpus(); get_online_cpus();
/* Force all MSRs to the same value */ /* Force all MSRs to the same value */
boost_set_msrs(boost_enabled, cpu_online_mask); boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
cpu_online_mask);
register_cpu_notifier(&boost_nb); register_cpu_notifier(&boost_nb);
put_online_cpus(); put_online_cpus();
} else }
global_boost.attr.mode = 0444;
/* We create the boost file in any case, though for systems without
* hardware support it will be read-only and hardwired to return 0.
*/
if (cpufreq_sysfs_create_file(&(global_boost.attr)))
pr_warn(PFX "could not register global boost sysfs file\n");
else
pr_debug("registered global boost sysfs file\n");
} }
static void __exit acpi_cpufreq_boost_exit(void) static void __exit acpi_cpufreq_boost_exit(void)
{ {
cpufreq_sysfs_remove_file(&(global_boost.attr));
if (msrs) { if (msrs) {
unregister_cpu_notifier(&boost_nb); unregister_cpu_notifier(&boost_nb);
@@ -993,12 +966,11 @@ static int __init acpi_cpufreq_init(void)
*iter = &cpb; *iter = &cpb;
} }
#endif #endif
acpi_cpufreq_boost_init();
ret = cpufreq_register_driver(&acpi_cpufreq_driver); ret = cpufreq_register_driver(&acpi_cpufreq_driver);
if (ret) if (ret)
free_acpi_perf_data(); free_acpi_perf_data();
else
acpi_cpufreq_boost_init();
return ret; return ret;
} }
+2 -1
View File
@@ -488,7 +488,8 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
static struct cpufreq_driver bL_cpufreq_driver = { static struct cpufreq_driver bL_cpufreq_driver = {
.name = "arm-big-little", .name = "arm-big-little",
.flags = CPUFREQ_STICKY | .flags = CPUFREQ_STICKY |
CPUFREQ_HAVE_GOVERNOR_PER_POLICY, CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = bL_cpufreq_set_target, .target_index = bL_cpufreq_set_target,
.get = bL_cpufreq_get_rate, .get = bL_cpufreq_get_rate,
+5 -12
View File
@@ -21,17 +21,8 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
static struct clk *cpuclk;
static struct cpufreq_frequency_table *freq_table; static struct cpufreq_frequency_table *freq_table;
static unsigned int at32_get_speed(unsigned int cpu)
{
/* No SMP support */
if (cpu)
return 0;
return (unsigned int)((clk_get_rate(cpuclk) + 500) / 1000);
}
static unsigned int ref_freq; static unsigned int ref_freq;
static unsigned long loops_per_jiffy_ref; static unsigned long loops_per_jiffy_ref;
@@ -39,7 +30,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
unsigned int old_freq, new_freq; unsigned int old_freq, new_freq;
old_freq = at32_get_speed(0); old_freq = policy->cur;
new_freq = freq_table[index].frequency; new_freq = freq_table[index].frequency;
if (!ref_freq) { if (!ref_freq) {
@@ -50,7 +41,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index)
if (old_freq < new_freq) if (old_freq < new_freq)
boot_cpu_data.loops_per_jiffy = cpufreq_scale( boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, new_freq); loops_per_jiffy_ref, ref_freq, new_freq);
clk_set_rate(cpuclk, new_freq * 1000); clk_set_rate(policy->clk, new_freq * 1000);
if (new_freq < old_freq) if (new_freq < old_freq)
boot_cpu_data.loops_per_jiffy = cpufreq_scale( boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, new_freq); loops_per_jiffy_ref, ref_freq, new_freq);
@@ -61,6 +52,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index)
static int at32_cpufreq_driver_init(struct cpufreq_policy *policy) static int at32_cpufreq_driver_init(struct cpufreq_policy *policy)
{ {
unsigned int frequency, rate, min_freq; unsigned int frequency, rate, min_freq;
static struct clk *cpuclk;
int retval, steps, i; int retval, steps, i;
if (policy->cpu != 0) if (policy->cpu != 0)
@@ -103,6 +95,7 @@ static int at32_cpufreq_driver_init(struct cpufreq_policy *policy)
frequency /= 2; frequency /= 2;
} }
policy->clk = cpuclk;
freq_table[steps - 1].frequency = CPUFREQ_TABLE_END; freq_table[steps - 1].frequency = CPUFREQ_TABLE_END;
retval = cpufreq_table_validate_and_show(policy, freq_table); retval = cpufreq_table_validate_and_show(policy, freq_table);
@@ -123,7 +116,7 @@ static struct cpufreq_driver at32_driver = {
.init = at32_cpufreq_driver_init, .init = at32_cpufreq_driver_init,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = at32_set_target, .target_index = at32_set_target,
.get = at32_get_speed, .get = cpufreq_generic_get,
.flags = CPUFREQ_STICKY, .flags = CPUFREQ_STICKY,
}; };
+3 -7
View File
@@ -30,11 +30,6 @@ static struct clk *cpu_clk;
static struct regulator *cpu_reg; static struct regulator *cpu_reg;
static struct cpufreq_frequency_table *freq_table; static struct cpufreq_frequency_table *freq_table;
static unsigned int cpu0_get_speed(unsigned int cpu)
{
return clk_get_rate(cpu_clk) / 1000;
}
static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
@@ -44,7 +39,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
int ret; int ret;
freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
if (freq_Hz < 0) if (freq_Hz <= 0)
freq_Hz = freq_table[index].frequency * 1000; freq_Hz = freq_table[index].frequency * 1000;
freq_exact = freq_Hz; freq_exact = freq_Hz;
@@ -100,6 +95,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
static int cpu0_cpufreq_init(struct cpufreq_policy *policy) static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
{ {
policy->clk = cpu_clk;
return cpufreq_generic_init(policy, freq_table, transition_latency); return cpufreq_generic_init(policy, freq_table, transition_latency);
} }
@@ -107,7 +103,7 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
.flags = CPUFREQ_STICKY, .flags = CPUFREQ_STICKY,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = cpu0_set_target, .target_index = cpu0_set_target,
.get = cpu0_get_speed, .get = cpufreq_generic_get,
.init = cpu0_cpufreq_init, .init = cpu0_cpufreq_init,
.exit = cpufreq_generic_exit, .exit = cpufreq_generic_exit,
.name = "generic_cpu0", .name = "generic_cpu0",
+199 -19
View File
@@ -39,7 +39,7 @@ static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
static DEFINE_RWLOCK(cpufreq_driver_lock); static DEFINE_RWLOCK(cpufreq_driver_lock);
static DEFINE_MUTEX(cpufreq_governor_lock); DEFINE_MUTEX(cpufreq_governor_lock);
static LIST_HEAD(cpufreq_policy_list); static LIST_HEAD(cpufreq_policy_list);
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
@@ -176,6 +176,20 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
} }
EXPORT_SYMBOL_GPL(cpufreq_generic_init); EXPORT_SYMBOL_GPL(cpufreq_generic_init);
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);
return 0;
}
return clk_get_rate(policy->clk) / 1000;
}
EXPORT_SYMBOL_GPL(cpufreq_generic_get);
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{ {
struct cpufreq_policy *policy = NULL; struct cpufreq_policy *policy = NULL;
@@ -320,10 +334,51 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
} }
EXPORT_SYMBOL_GPL(cpufreq_notify_transition); EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
/* Do post notifications when there are chances that transition has failed */
void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, int transition_failed)
{
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
if (!transition_failed)
return;
swap(freqs->old, freqs->new);
cpufreq_notify_transition(policy, freqs, CPUFREQ_PRECHANGE);
cpufreq_notify_transition(policy, freqs, CPUFREQ_POSTCHANGE);
}
EXPORT_SYMBOL_GPL(cpufreq_notify_post_transition);
/********************************************************************* /*********************************************************************
* SYSFS INTERFACE * * SYSFS INTERFACE *
*********************************************************************/ *********************************************************************/
ssize_t show_boost(struct kobject *kobj,
struct attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", cpufreq_driver->boost_enabled);
}
static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
int ret, enable;
ret = sscanf(buf, "%d", &enable);
if (ret != 1 || enable < 0 || enable > 1)
return -EINVAL;
if (cpufreq_boost_trigger_state(enable)) {
pr_err("%s: Cannot %s BOOST!\n", __func__,
enable ? "enable" : "disable");
return -EINVAL;
}
pr_debug("%s: cpufreq BOOST %s\n", __func__,
enable ? "enabled" : "disabled");
return count;
}
define_one_global_rw(boost);
static struct cpufreq_governor *__find_governor(const char *str_governor) static struct cpufreq_governor *__find_governor(const char *str_governor)
{ {
@@ -929,6 +984,9 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
struct kobject *kobj; struct kobject *kobj;
struct completion *cmp; struct completion *cmp;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_REMOVE_POLICY, policy);
down_read(&policy->rwsem); down_read(&policy->rwsem);
kobj = &policy->kobj; kobj = &policy->kobj;
cmp = &policy->kobj_unregister; cmp = &policy->kobj_unregister;
@@ -1051,6 +1109,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
goto err_set_policy_cpu; goto err_set_policy_cpu;
} }
write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (cpufreq_driver->get) { if (cpufreq_driver->get) {
policy->cur = cpufreq_driver->get(policy->cpu); policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) { if (!policy->cur) {
@@ -1059,6 +1122,46 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
} }
} }
/*
* Sometimes boot loaders set CPU frequency to a value outside of
* frequency table present with cpufreq core. In such cases CPU might be
* unstable if it has to run on that frequency for long duration of time
* and so its better to set it to a frequency which is specified in
* freq-table. This also makes cpufreq stats inconsistent as
* cpufreq-stats would fail to register because current frequency of CPU
* isn't found in freq-table.
*
* Because we don't want this change to effect boot process badly, we go
* for the next freq which is >= policy->cur ('cur' must be set by now,
* otherwise we will end up setting freq to lowest of the table as 'cur'
* is initialized to zero).
*
* We are passing target-freq as "policy->cur - 1" otherwise
* __cpufreq_driver_target() would simply fail, as policy->cur will be
* equal to target-freq.
*/
if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK)
&& has_target()) {
/* Are we running at unknown frequency ? */
ret = cpufreq_frequency_table_get_index(policy, policy->cur);
if (ret == -EINVAL) {
/* Warn user and fix it */
pr_warn("%s: CPU%d: Running at unlisted freq: %u KHz\n",
__func__, policy->cpu, policy->cur);
ret = __cpufreq_driver_target(policy, policy->cur - 1,
CPUFREQ_RELATION_L);
/*
* Reaching here after boot in a few seconds may not
* mean that system will remain stable at "unknown"
* frequency for longer duration. Hence, a BUG_ON().
*/
BUG_ON(ret);
pr_warn("%s: CPU%d: Unlisted initial frequency changed to: %u KHz\n",
__func__, policy->cpu, policy->cur);
}
}
/* related cpus should atleast have policy->cpus */ /* related cpus should atleast have policy->cpus */
cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
@@ -1085,15 +1188,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
} }
#endif #endif
write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!frozen) { if (!frozen) {
ret = cpufreq_add_dev_interface(policy, dev); ret = cpufreq_add_dev_interface(policy, dev);
if (ret) if (ret)
goto err_out_unregister; goto err_out_unregister;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_CREATE_POLICY, policy);
} }
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
@@ -1115,12 +1215,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
return 0; return 0;
err_out_unregister: err_out_unregister:
err_get_freq:
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = NULL; per_cpu(cpufreq_cpu_data, j) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
err_get_freq:
if (cpufreq_driver->exit) if (cpufreq_driver->exit)
cpufreq_driver->exit(policy); cpufreq_driver->exit(policy);
err_set_policy_cpu: err_set_policy_cpu:
@@ -1725,17 +1825,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
pr_err("%s: Failed to change cpu frequency: %d\n", pr_err("%s: Failed to change cpu frequency: %d\n",
__func__, retval); __func__, retval);
if (notify) { if (notify)
/* cpufreq_notify_post_transition(policy, &freqs, retval);
* Notify with old freq in case we failed to change
* frequency
*/
if (retval)
freqs.new = freqs.old;
cpufreq_notify_transition(policy, &freqs,
CPUFREQ_POSTCHANGE);
}
} }
out: out:
@@ -2119,6 +2210,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
.notifier_call = cpufreq_cpu_callback, .notifier_call = cpufreq_cpu_callback,
}; };
/*********************************************************************
* BOOST *
*********************************************************************/
static int cpufreq_boost_set_sw(int state)
{
struct cpufreq_frequency_table *freq_table;
struct cpufreq_policy *policy;
int ret = -EINVAL;
list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
freq_table = cpufreq_frequency_get_table(policy->cpu);
if (freq_table) {
ret = cpufreq_frequency_table_cpuinfo(policy,
freq_table);
if (ret) {
pr_err("%s: Policy frequency update failed\n",
__func__);
break;
}
policy->user_policy.max = policy->max;
__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
}
}
return ret;
}
int cpufreq_boost_trigger_state(int state)
{
unsigned long flags;
int ret = 0;
if (cpufreq_driver->boost_enabled == state)
return 0;
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver->boost_enabled = state;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
ret = cpufreq_driver->set_boost(state);
if (ret) {
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver->boost_enabled = !state;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
pr_err("%s: Cannot %s BOOST\n", __func__,
state ? "enable" : "disable");
}
return ret;
}
int cpufreq_boost_supported(void)
{
if (likely(cpufreq_driver))
return cpufreq_driver->boost_supported;
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_boost_supported);
int cpufreq_boost_enabled(void)
{
return cpufreq_driver->boost_enabled;
}
EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
/********************************************************************* /*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER * * REGISTER / UNREGISTER CPUFREQ DRIVER *
*********************************************************************/ *********************************************************************/
@@ -2159,9 +2317,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data; cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags); write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (cpufreq_boost_supported()) {
/*
* Check if driver provides function to enable boost -
* if not, use cpufreq_boost_set_sw as default
*/
if (!cpufreq_driver->set_boost)
cpufreq_driver->set_boost = cpufreq_boost_set_sw;
ret = cpufreq_sysfs_create_file(&boost.attr);
if (ret) {
pr_err("%s: cannot register global BOOST sysfs file\n",
__func__);
goto err_null_driver;
}
}
ret = subsys_interface_register(&cpufreq_interface); ret = subsys_interface_register(&cpufreq_interface);
if (ret) if (ret)
goto err_null_driver; goto err_boost_unreg;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) { if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i; int i;
@@ -2188,6 +2362,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
return 0; return 0;
err_if_unreg: err_if_unreg:
subsys_interface_unregister(&cpufreq_interface); subsys_interface_unregister(&cpufreq_interface);
err_boost_unreg:
if (cpufreq_boost_supported())
cpufreq_sysfs_remove_file(&boost.attr);
err_null_driver: err_null_driver:
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL; cpufreq_driver = NULL;
@@ -2214,6 +2391,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
pr_debug("unregistering driver %s\n", driver->name); pr_debug("unregistering driver %s\n", driver->name);
subsys_interface_unregister(&cpufreq_interface); subsys_interface_unregister(&cpufreq_interface);
if (cpufreq_boost_supported())
cpufreq_sysfs_remove_file(&boost.attr);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier); unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
down_write(&cpufreq_rwsem); down_write(&cpufreq_rwsem);
+5 -1
View File
@@ -119,8 +119,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
{ {
int i; int i;
mutex_lock(&cpufreq_governor_lock);
if (!policy->governor_enabled) if (!policy->governor_enabled)
return; goto out_unlock;
if (!all_cpus) { if (!all_cpus) {
/* /*
@@ -135,6 +136,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
for_each_cpu(i, policy->cpus) for_each_cpu(i, policy->cpus)
__gov_queue_work(i, dbs_data, delay); __gov_queue_work(i, dbs_data, delay);
} }
out_unlock:
mutex_unlock(&cpufreq_governor_lock);
} }
EXPORT_SYMBOL_GPL(gov_queue_work); EXPORT_SYMBOL_GPL(gov_queue_work);
+2
View File
@@ -257,6 +257,8 @@ static ssize_t show_sampling_rate_min_gov_pol \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
} }
extern struct mutex cpufreq_governor_lock;
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
bool need_load_eval(struct cpu_dbs_common_info *cdbs, bool need_load_eval(struct cpu_dbs_common_info *cdbs,
unsigned int sampling_rate); unsigned int sampling_rate);
+44 -57
View File
@@ -151,44 +151,36 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1; return -1;
} }
/* should be called late in the CPU removal sequence so that the stats static void __cpufreq_stats_free_table(struct cpufreq_policy *policy)
* memory is still available in case someone tries to use it.
*/
static void cpufreq_stats_free_table(unsigned int cpu)
{ {
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
if (!stat)
return;
if (stat) {
pr_debug("%s: Free stat table\n", __func__); pr_debug("%s: Free stat table\n", __func__);
sysfs_remove_group(&policy->kobj, &stats_attr_group);
kfree(stat->time_in_state); kfree(stat->time_in_state);
kfree(stat); kfree(stat);
per_cpu(cpufreq_stats_table, cpu) = NULL; per_cpu(cpufreq_stats_table, policy->cpu) = NULL;
}
} }
/* must be called early in the CPU removal sequence (before static void cpufreq_stats_free_table(unsigned int cpu)
* cpufreq_remove_dev) so that policy is still valid.
*/
static void cpufreq_stats_free_sysfs(unsigned int cpu)
{ {
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); struct cpufreq_policy *policy;
policy = cpufreq_cpu_get(cpu);
if (!policy) if (!policy)
return; return;
if (!cpufreq_frequency_get_table(cpu)) if (cpufreq_frequency_get_table(policy->cpu))
goto put_ref; __cpufreq_stats_free_table(policy);
if (!policy_is_shared(policy)) {
pr_debug("%s: Free sysfs stat\n", __func__);
sysfs_remove_group(&policy->kobj, &stats_attr_group);
}
put_ref:
cpufreq_cpu_put(policy); cpufreq_cpu_put(policy);
} }
static int cpufreq_stats_create_table(struct cpufreq_policy *policy, static int __cpufreq_stats_create_table(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table) struct cpufreq_frequency_table *table)
{ {
unsigned int i, j, count = 0, ret = 0; unsigned int i, j, count = 0, ret = 0;
@@ -261,6 +253,26 @@ error_get_fail:
return ret; return ret;
} }
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
* before cpufreq driver
*/
policy = cpufreq_cpu_get(cpu);
if (likely(!policy))
return;
table = cpufreq_frequency_get_table(policy->cpu);
if (likely(table))
__cpufreq_stats_create_table(policy, table);
cpufreq_cpu_put(policy);
}
static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy) static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
{ {
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
@@ -277,7 +289,7 @@ static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
static int cpufreq_stat_notifier_policy(struct notifier_block *nb, static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
unsigned long val, void *data) unsigned long val, void *data)
{ {
int ret; int ret = 0;
struct cpufreq_policy *policy = data; struct cpufreq_policy *policy = data;
struct cpufreq_frequency_table *table; struct cpufreq_frequency_table *table;
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
@@ -287,15 +299,16 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
return 0; return 0;
} }
if (val != CPUFREQ_NOTIFY)
return 0;
table = cpufreq_frequency_get_table(cpu); table = cpufreq_frequency_get_table(cpu);
if (!table) if (!table)
return 0; return 0;
ret = cpufreq_stats_create_table(policy, table);
if (ret) if (val == CPUFREQ_CREATE_POLICY)
ret = __cpufreq_stats_create_table(policy, table);
else if (val == CPUFREQ_REMOVE_POLICY)
__cpufreq_stats_free_table(policy);
return ret; return ret;
return 0;
} }
static int cpufreq_stat_notifier_trans(struct notifier_block *nb, static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
@@ -334,29 +347,6 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
return 0; return 0;
} }
static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
switch (action) {
case CPU_DOWN_PREPARE:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
cpufreq_stats_free_table(cpu);
break;
}
return NOTIFY_OK;
}
/* priority=1 so this will get called before cpufreq_remove_dev */
static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
.notifier_call = cpufreq_stat_cpu_callback,
.priority = 1,
};
static struct notifier_block notifier_policy_block = { static struct notifier_block notifier_policy_block = {
.notifier_call = cpufreq_stat_notifier_policy .notifier_call = cpufreq_stat_notifier_policy
}; };
@@ -376,14 +366,14 @@ static int __init cpufreq_stats_init(void)
if (ret) if (ret)
return ret; return ret;
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu)
cpufreq_stats_create_table(cpu);
ret = cpufreq_register_notifier(&notifier_trans_block, ret = cpufreq_register_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
if (ret) { if (ret) {
cpufreq_unregister_notifier(&notifier_policy_block, cpufreq_unregister_notifier(&notifier_policy_block,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) for_each_online_cpu(cpu)
cpufreq_stats_free_table(cpu); cpufreq_stats_free_table(cpu);
return ret; return ret;
@@ -399,11 +389,8 @@ static void __exit cpufreq_stats_exit(void)
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
cpufreq_unregister_notifier(&notifier_trans_block, cpufreq_unregister_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu)
for_each_online_cpu(cpu) {
cpufreq_stats_free_table(cpu); cpufreq_stats_free_table(cpu);
cpufreq_stats_free_sysfs(cpu);
}
} }
MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>"); MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
+5 -11
View File
@@ -58,14 +58,6 @@ static int davinci_verify_speed(struct cpufreq_policy *policy)
return 0; return 0;
} }
static unsigned int davinci_getspeed(unsigned int cpu)
{
if (cpu)
return 0;
return clk_get_rate(cpufreq.armclk) / 1000;
}
static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
{ {
struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data; struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
@@ -73,7 +65,7 @@ static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
unsigned int old_freq, new_freq; unsigned int old_freq, new_freq;
int ret = 0; int ret = 0;
old_freq = davinci_getspeed(0); old_freq = policy->cur;
new_freq = pdata->freq_table[idx].frequency; new_freq = pdata->freq_table[idx].frequency;
/* if moving to higher frequency, up the voltage beforehand */ /* if moving to higher frequency, up the voltage beforehand */
@@ -116,6 +108,8 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
return result; return result;
} }
policy->clk = cpufreq.armclk;
/* /*
* Time measurement across the target() function yields ~1500-1800us * Time measurement across the target() function yields ~1500-1800us
* time taken with no drivers on notification list. * time taken with no drivers on notification list.
@@ -126,10 +120,10 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
} }
static struct cpufreq_driver davinci_driver = { static struct cpufreq_driver davinci_driver = {
.flags = CPUFREQ_STICKY, .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = davinci_verify_speed, .verify = davinci_verify_speed,
.target_index = davinci_target, .target_index = davinci_target,
.get = davinci_getspeed, .get = cpufreq_generic_get,
.init = davinci_cpu_init, .init = davinci_cpu_init,
.exit = cpufreq_generic_exit, .exit = cpufreq_generic_exit,
.name = "davinci", .name = "davinci",
+4 -18
View File
@@ -26,32 +26,18 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
return clk_set_rate(armss_clk, freq_table[index].frequency * 1000); return clk_set_rate(armss_clk, freq_table[index].frequency * 1000);
} }
static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
{
int i = 0;
unsigned long freq = clk_get_rate(armss_clk) / 1000;
/* The value is rounded to closest frequency in the defined table. */
while (freq_table[i + 1].frequency != CPUFREQ_TABLE_END) {
if (freq < freq_table[i].frequency +
(freq_table[i + 1].frequency - freq_table[i].frequency) / 2)
return freq_table[i].frequency;
i++;
}
return freq_table[i].frequency;
}
static int dbx500_cpufreq_init(struct cpufreq_policy *policy) static int dbx500_cpufreq_init(struct cpufreq_policy *policy)
{ {
policy->clk = armss_clk;
return cpufreq_generic_init(policy, freq_table, 20 * 1000); return cpufreq_generic_init(policy, freq_table, 20 * 1000);
} }
static struct cpufreq_driver dbx500_cpufreq_driver = { static struct cpufreq_driver dbx500_cpufreq_driver = {
.flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS, .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS |
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = dbx500_cpufreq_target, .target_index = dbx500_cpufreq_target,
.get = dbx500_cpufreq_getspeed, .get = cpufreq_generic_get,
.init = dbx500_cpufreq_init, .init = dbx500_cpufreq_init,
.name = "DBX500", .name = "DBX500",
.attr = cpufreq_generic_attr, .attr = cpufreq_generic_attr,

Some files were not shown because too many files have changed in this diff Show More