Skip to content

Commit

Permalink
Merge back earlier 'pm-cpufreq' material.
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafael J. Wysocki committed Jan 14, 2014
2 parents 6cbd7ee + 22c7379 commit 51c4c4c
Show file tree
Hide file tree
Showing 40 changed files with 511 additions and 206 deletions.
24 changes: 24 additions & 0 deletions Documentation/ABI/testing/sysfs-devices-system-cpu
Original file line number Diff line number Diff line change
Expand Up @@ -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
40 changes: 40 additions & 0 deletions Documentation/cpu-freq/intel-pstate.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions arch/arm/mach-exynos/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-exynos/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-exynos/mach-exynos4-dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-exynos/mach-exynos5-dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/cpufreq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,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)
Expand Down
12 changes: 7 additions & 5 deletions drivers/cpufreq/Kconfig.arm
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand All @@ -79,11 +81,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.

Expand Down
3 changes: 2 additions & 1 deletion drivers/cpufreq/arm_big_little.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/cpufreq-cpu0.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,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;
Expand Down
69 changes: 57 additions & 12 deletions drivers/cpufreq/cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -320,6 +320,20 @@ 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 *
Expand Down Expand Up @@ -1059,6 +1073,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);

Expand Down Expand Up @@ -1725,17 +1779,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:
Expand Down
6 changes: 5 additions & 1 deletion drivers/cpufreq/cpufreq_governor.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
/*
Expand All @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions drivers/cpufreq/cpufreq_governor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/cpufreq/davinci-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ 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,
Expand Down
3 changes: 2 additions & 1 deletion drivers/cpufreq/dbx500-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ static int dbx500_cpufreq_init(struct cpufreq_policy *policy)
}

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,
Expand Down
15 changes: 12 additions & 3 deletions drivers/cpufreq/exynos-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/regulator/consumer.h>
#include <linux/cpufreq.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>

#include <plat/cpu.h>

Expand Down Expand Up @@ -218,7 +219,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
}

static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY,
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify,
.target_index = exynos_target,
.get = exynos_getspeed,
Expand All @@ -232,7 +233,7 @@ static struct cpufreq_driver exynos_driver = {
#endif
};

static int __init exynos_cpufreq_init(void)
static int exynos_cpufreq_probe(struct platform_device *pdev)
{
int ret = -EINVAL;

Expand Down Expand Up @@ -281,4 +282,12 @@ static int __init exynos_cpufreq_init(void)
kfree(exynos_info);
return -EINVAL;
}
late_initcall(exynos_cpufreq_init);

static struct platform_driver exynos_cpufreq_platdrv = {
.driver = {
.name = "exynos-cpufreq",
.owner = THIS_MODULE,
},
.probe = exynos_cpufreq_probe,
};
module_platform_driver(exynos_cpufreq_platdrv);
Loading

0 comments on commit 51c4c4c

Please sign in to comment.