You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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:
@@ -200,3 +200,27 @@ Description: address and size of the percpu note.
|
||||
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
|
||||
|
||||
@@ -17,8 +17,8 @@ Introduction
|
||||
Some CPUs support a functionality to raise the operating frequency of
|
||||
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
|
||||
budget. This is done without operating system control by a combination
|
||||
of hardware and firmware.
|
||||
budget. The decision about boost disable/enable is made either at hardware
|
||||
(e.g. x86) or software (e.g ARM).
|
||||
On Intel CPUs this is called "Turbo Boost", AMD calls it "Turbo-Core",
|
||||
in technical documentation "Core performance boost". In Linux we use
|
||||
the term "boost" for convenience.
|
||||
@@ -48,24 +48,24 @@ be desirable:
|
||||
User controlled switch
|
||||
----------------------
|
||||
|
||||
To allow the user to toggle the boosting functionality, the acpi-cpufreq
|
||||
driver exports a sysfs knob to disable it. There is a file:
|
||||
To allow the user to toggle the boosting functionality, the cpufreq core
|
||||
driver exports a sysfs knob to enable or disable it. There is a file:
|
||||
/sys/devices/system/cpu/cpufreq/boost
|
||||
which can either read "0" (boosting disabled) or "1" (boosting enabled).
|
||||
Reading the file is always supported, even if the processor does not
|
||||
support boosting. In this case the file will be read-only and always
|
||||
reads as "0". Explicitly changing the permissions and writing to that
|
||||
file anyway will return EINVAL.
|
||||
The file is exported only when cpufreq driver supports boosting.
|
||||
Explicitly changing the permissions and writing to that file anyway will
|
||||
return EINVAL.
|
||||
|
||||
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
|
||||
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
|
||||
CPU (and the firmware) to boost at their discretion. Some implementations
|
||||
take external factors like the chip's temperature into account, so
|
||||
boosting once does not necessarily mean that it will occur every time
|
||||
even using the exact same software setup.
|
||||
CPU to boost at their discretion. Some implementations take external
|
||||
factors like the chip's temperature into account, so boosting once does
|
||||
not necessarily mean that it will occur every time even using the exact
|
||||
same software setup.
|
||||
|
||||
|
||||
AMD legacy cpb switch
|
||||
|
||||
@@ -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
|
||||
@@ -303,6 +303,11 @@ void __init exynos_cpuidle_init(void)
|
||||
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)
|
||||
{
|
||||
if (of_machine_is_compatible("samsung,exynos5440"))
|
||||
|
||||
@@ -22,6 +22,7 @@ void exynos_init_io(void);
|
||||
void exynos4_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_cpufreq_init(void);
|
||||
void exynos_init_late(void);
|
||||
|
||||
void exynos_firmware_init(void);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
static void __init exynos4_dt_machine_init(void)
|
||||
{
|
||||
exynos_cpuidle_init();
|
||||
exynos_cpufreq_init();
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ static void __init exynos5_dt_machine_init(void)
|
||||
}
|
||||
|
||||
exynos_cpuidle_init();
|
||||
exynos_cpufreq_init();
|
||||
|
||||
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,13 @@ struct clk clk_##_name = { \
|
||||
|
||||
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)
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -20,6 +20,10 @@ if CPU_FREQ
|
||||
config CPU_FREQ_GOV_COMMON
|
||||
bool
|
||||
|
||||
config CPU_FREQ_BOOST_SW
|
||||
bool
|
||||
depends on THERMAL
|
||||
|
||||
config CPU_FREQ_STAT
|
||||
tristate "CPU frequency translation statistics"
|
||||
default y
|
||||
@@ -181,7 +185,8 @@ config CPU_FREQ_GOV_CONSERVATIVE
|
||||
|
||||
config GENERIC_CPUFREQ_CPU0
|
||||
tristate "Generic CPU0 cpufreq driver"
|
||||
depends on HAVE_CLK && REGULATOR && PM_OPP && OF
|
||||
depends on HAVE_CLK && REGULATOR && OF
|
||||
select PM_OPP
|
||||
help
|
||||
This adds a generic cpufreq driver for CPU0 frequency management.
|
||||
It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
config ARM_BIG_LITTLE_CPUFREQ
|
||||
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
|
||||
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
|
||||
|
||||
@@ -54,7 +55,8 @@ config ARM_EXYNOS5250_CPUFREQ
|
||||
config ARM_EXYNOS5440_CPUFREQ
|
||||
bool "SAMSUNG EXYNOS5440"
|
||||
depends on SOC_EXYNOS5440
|
||||
depends on HAVE_CLK && PM_OPP && OF
|
||||
depends on HAVE_CLK && OF
|
||||
select PM_OPP
|
||||
default y
|
||||
help
|
||||
This adds the CPUFreq driver for Samsung EXYNOS5440
|
||||
@@ -64,6 +66,21 @@ config ARM_EXYNOS5440_CPUFREQ
|
||||
|
||||
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
|
||||
tristate "Calxeda Highbank-based"
|
||||
depends on ARCH_HIGHBANK
|
||||
@@ -79,11 +96,11 @@ config ARM_HIGHBANK_CPUFREQ
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_IMX6Q_CPUFREQ
|
||||
tristate "Freescale i.MX6Q cpufreq support"
|
||||
depends on SOC_IMX6Q
|
||||
tristate "Freescale i.MX6 cpufreq support"
|
||||
depends on ARCH_MXC
|
||||
depends on REGULATOR_ANATOP
|
||||
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.
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
|
||||
static struct cpufreq_driver acpi_cpufreq_driver;
|
||||
|
||||
static unsigned int acpi_pstate_strict;
|
||||
static bool boost_enabled, boost_supported;
|
||||
static struct msr __percpu *msrs;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
boost_set_msrs(val, cpu_online_mask);
|
||||
|
||||
put_online_cpus();
|
||||
|
||||
boost_enabled = val;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
#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,
|
||||
size_t count)
|
||||
{
|
||||
return _store_boost(buf, count);
|
||||
return store_boost(buf, count);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -554,7 +537,7 @@ static int boost_notify(struct notifier_block *nb, unsigned long action,
|
||||
switch (action) {
|
||||
case CPU_UP_PREPARE:
|
||||
case CPU_UP_PREPARE_FROZEN:
|
||||
boost_set_msrs(boost_enabled, cpumask);
|
||||
boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_PREPARE:
|
||||
@@ -911,6 +894,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
|
||||
.resume = acpi_cpufreq_resume,
|
||||
.name = "acpi-cpufreq",
|
||||
.attr = acpi_cpufreq_attr,
|
||||
.set_boost = _store_boost,
|
||||
};
|
||||
|
||||
static void __init acpi_cpufreq_boost_init(void)
|
||||
@@ -921,33 +905,22 @@ static void __init acpi_cpufreq_boost_init(void)
|
||||
if (!msrs)
|
||||
return;
|
||||
|
||||
boost_supported = true;
|
||||
boost_enabled = boost_state(0);
|
||||
|
||||
acpi_cpufreq_driver.boost_supported = true;
|
||||
acpi_cpufreq_driver.boost_enabled = boost_state(0);
|
||||
get_online_cpus();
|
||||
|
||||
/* 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);
|
||||
|
||||
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)
|
||||
{
|
||||
cpufreq_sysfs_remove_file(&(global_boost.attr));
|
||||
|
||||
if (msrs) {
|
||||
unregister_cpu_notifier(&boost_nb);
|
||||
|
||||
@@ -993,12 +966,11 @@ static int __init acpi_cpufreq_init(void)
|
||||
*iter = &cpb;
|
||||
}
|
||||
#endif
|
||||
acpi_cpufreq_boost_init();
|
||||
|
||||
ret = cpufreq_register_driver(&acpi_cpufreq_driver);
|
||||
if (ret)
|
||||
free_acpi_perf_data();
|
||||
else
|
||||
acpi_cpufreq_boost_init();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -488,7 +488,8 @@ static int bL_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
static struct cpufreq_driver bL_cpufreq_driver = {
|
||||
.name = "arm-big-little",
|
||||
.flags = CPUFREQ_STICKY |
|
||||
CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
|
||||
CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
|
||||
CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = bL_cpufreq_set_target,
|
||||
.get = bL_cpufreq_get_rate,
|
||||
|
||||
@@ -21,17 +21,8 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static struct clk *cpuclk;
|
||||
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 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;
|
||||
|
||||
old_freq = at32_get_speed(0);
|
||||
old_freq = policy->cur;
|
||||
new_freq = freq_table[index].frequency;
|
||||
|
||||
if (!ref_freq) {
|
||||
@@ -50,7 +41,7 @@ static int at32_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
if (old_freq < new_freq)
|
||||
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
|
||||
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)
|
||||
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
|
||||
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)
|
||||
{
|
||||
unsigned int frequency, rate, min_freq;
|
||||
static struct clk *cpuclk;
|
||||
int retval, steps, i;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
@@ -103,6 +95,7 @@ static int at32_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||
frequency /= 2;
|
||||
}
|
||||
|
||||
policy->clk = cpuclk;
|
||||
freq_table[steps - 1].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
retval = cpufreq_table_validate_and_show(policy, freq_table);
|
||||
@@ -123,7 +116,7 @@ static struct cpufreq_driver at32_driver = {
|
||||
.init = at32_cpufreq_driver_init,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = at32_set_target,
|
||||
.get = at32_get_speed,
|
||||
.get = cpufreq_generic_get,
|
||||
.flags = CPUFREQ_STICKY,
|
||||
};
|
||||
|
||||
|
||||
@@ -30,11 +30,6 @@ static struct clk *cpu_clk;
|
||||
static struct regulator *cpu_reg;
|
||||
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)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
@@ -44,7 +39,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
int ret;
|
||||
|
||||
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_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)
|
||||
{
|
||||
policy->clk = cpu_clk;
|
||||
return cpufreq_generic_init(policy, freq_table, transition_latency);
|
||||
}
|
||||
|
||||
@@ -107,7 +103,7 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
|
||||
.flags = CPUFREQ_STICKY,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = cpu0_set_target,
|
||||
.get = cpu0_get_speed,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = cpu0_cpufreq_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "generic_cpu0",
|
||||
|
||||
+199
-19
@@ -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_fallback);
|
||||
static DEFINE_RWLOCK(cpufreq_driver_lock);
|
||||
static DEFINE_MUTEX(cpufreq_governor_lock);
|
||||
DEFINE_MUTEX(cpufreq_governor_lock);
|
||||
static LIST_HEAD(cpufreq_policy_list);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
@@ -176,6 +176,20 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
}
|
||||
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 *policy = NULL;
|
||||
@@ -320,10 +334,51 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
}
|
||||
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 *
|
||||
*********************************************************************/
|
||||
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)
|
||||
{
|
||||
@@ -929,6 +984,9 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
|
||||
struct kobject *kobj;
|
||||
struct completion *cmp;
|
||||
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_REMOVE_POLICY, policy);
|
||||
|
||||
down_read(&policy->rwsem);
|
||||
kobj = &policy->kobj;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
policy->cur = cpufreq_driver->get(policy->cpu);
|
||||
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 */
|
||||
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
|
||||
|
||||
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) {
|
||||
ret = cpufreq_add_dev_interface(policy, dev);
|
||||
if (ret)
|
||||
goto err_out_unregister;
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_CREATE_POLICY, policy);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
err_out_unregister:
|
||||
err_get_freq:
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
for_each_cpu(j, policy->cpus)
|
||||
per_cpu(cpufreq_cpu_data, j) = NULL;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
err_get_freq:
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(policy);
|
||||
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",
|
||||
__func__, retval);
|
||||
|
||||
if (notify) {
|
||||
/*
|
||||
* Notify with old freq in case we failed to change
|
||||
* frequency
|
||||
*/
|
||||
if (retval)
|
||||
freqs.new = freqs.old;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs,
|
||||
CPUFREQ_POSTCHANGE);
|
||||
}
|
||||
if (notify)
|
||||
cpufreq_notify_post_transition(policy, &freqs, retval);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -2119,6 +2210,73 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
|
||||
.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 *
|
||||
*********************************************************************/
|
||||
@@ -2159,9 +2317,25 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
cpufreq_driver = driver_data;
|
||||
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);
|
||||
if (ret)
|
||||
goto err_null_driver;
|
||||
goto err_boost_unreg;
|
||||
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
|
||||
int i;
|
||||
@@ -2188,6 +2362,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
return 0;
|
||||
err_if_unreg:
|
||||
subsys_interface_unregister(&cpufreq_interface);
|
||||
err_boost_unreg:
|
||||
if (cpufreq_boost_supported())
|
||||
cpufreq_sysfs_remove_file(&boost.attr);
|
||||
err_null_driver:
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
cpufreq_driver = NULL;
|
||||
@@ -2214,6 +2391,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
|
||||
pr_debug("unregistering driver %s\n", driver->name);
|
||||
|
||||
subsys_interface_unregister(&cpufreq_interface);
|
||||
if (cpufreq_boost_supported())
|
||||
cpufreq_sysfs_remove_file(&boost.attr);
|
||||
|
||||
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
|
||||
|
||||
down_write(&cpufreq_rwsem);
|
||||
|
||||
@@ -119,8 +119,9 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&cpufreq_governor_lock);
|
||||
if (!policy->governor_enabled)
|
||||
return;
|
||||
goto out_unlock;
|
||||
|
||||
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)
|
||||
__gov_queue_work(i, dbs_data, delay);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&cpufreq_governor_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gov_queue_work);
|
||||
|
||||
|
||||
@@ -257,6 +257,8 @@ static ssize_t show_sampling_rate_min_gov_pol \
|
||||
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);
|
||||
bool need_load_eval(struct cpu_dbs_common_info *cdbs,
|
||||
unsigned int sampling_rate);
|
||||
|
||||
@@ -151,44 +151,36 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* should be called late in the CPU removal sequence so that the stats
|
||||
* memory is still available in case someone tries to use it.
|
||||
*/
|
||||
static void cpufreq_stats_free_table(unsigned int cpu)
|
||||
static void __cpufreq_stats_free_table(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
|
||||
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
|
||||
|
||||
if (stat) {
|
||||
pr_debug("%s: Free stat table\n", __func__);
|
||||
kfree(stat->time_in_state);
|
||||
kfree(stat);
|
||||
per_cpu(cpufreq_stats_table, cpu) = NULL;
|
||||
}
|
||||
if (!stat)
|
||||
return;
|
||||
|
||||
pr_debug("%s: Free stat table\n", __func__);
|
||||
|
||||
sysfs_remove_group(&policy->kobj, &stats_attr_group);
|
||||
kfree(stat->time_in_state);
|
||||
kfree(stat);
|
||||
per_cpu(cpufreq_stats_table, policy->cpu) = NULL;
|
||||
}
|
||||
|
||||
/* must be called early in the CPU removal sequence (before
|
||||
* cpufreq_remove_dev) so that policy is still valid.
|
||||
*/
|
||||
static void cpufreq_stats_free_sysfs(unsigned int cpu)
|
||||
static void cpufreq_stats_free_table(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
return;
|
||||
|
||||
if (!cpufreq_frequency_get_table(cpu))
|
||||
goto put_ref;
|
||||
if (cpufreq_frequency_get_table(policy->cpu))
|
||||
__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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned int i, j, count = 0, ret = 0;
|
||||
@@ -261,6 +253,26 @@ error_get_fail:
|
||||
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)
|
||||
{
|
||||
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,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct cpufreq_policy *policy = data;
|
||||
struct cpufreq_frequency_table *table;
|
||||
unsigned int cpu = policy->cpu;
|
||||
@@ -287,15 +299,16 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val != CPUFREQ_NOTIFY)
|
||||
return 0;
|
||||
table = cpufreq_frequency_get_table(cpu);
|
||||
if (!table)
|
||||
return 0;
|
||||
ret = cpufreq_stats_create_table(policy, table);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.notifier_call = cpufreq_stat_notifier_policy
|
||||
};
|
||||
@@ -376,14 +366,14 @@ static int __init cpufreq_stats_init(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
|
||||
for_each_online_cpu(cpu)
|
||||
cpufreq_stats_create_table(cpu);
|
||||
|
||||
ret = cpufreq_register_notifier(¬ifier_trans_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
if (ret) {
|
||||
cpufreq_unregister_notifier(¬ifier_policy_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
|
||||
for_each_online_cpu(cpu)
|
||||
cpufreq_stats_free_table(cpu);
|
||||
return ret;
|
||||
@@ -399,11 +389,8 @@ static void __exit cpufreq_stats_exit(void)
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
cpufreq_unregister_notifier(¬ifier_trans_block,
|
||||
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_sysfs(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
|
||||
|
||||
@@ -58,14 +58,6 @@ static int davinci_verify_speed(struct cpufreq_policy *policy)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
old_freq = davinci_getspeed(0);
|
||||
old_freq = policy->cur;
|
||||
new_freq = pdata->freq_table[idx].frequency;
|
||||
|
||||
/* if moving to higher frequency, up the voltage beforehand */
|
||||
@@ -116,6 +108,8 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
|
||||
return result;
|
||||
}
|
||||
|
||||
policy->clk = cpufreq.armclk;
|
||||
|
||||
/*
|
||||
* Time measurement across the target() function yields ~1500-1800us
|
||||
* 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 = {
|
||||
.flags = CPUFREQ_STICKY,
|
||||
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||
.verify = davinci_verify_speed,
|
||||
.target_index = davinci_target,
|
||||
.get = davinci_getspeed,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = davinci_cpu_init,
|
||||
.exit = cpufreq_generic_exit,
|
||||
.name = "davinci",
|
||||
|
||||
@@ -26,32 +26,18 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
|
||||
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)
|
||||
{
|
||||
policy->clk = armss_clk;
|
||||
return cpufreq_generic_init(policy, freq_table, 20 * 1000);
|
||||
}
|
||||
|
||||
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,
|
||||
.target_index = dbx500_cpufreq_target,
|
||||
.get = dbx500_cpufreq_getspeed,
|
||||
.get = cpufreq_generic_get,
|
||||
.init = dbx500_cpufreq_init,
|
||||
.name = "DBX500",
|
||||
.attr = cpufreq_generic_attr,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user