Merge branches 'pm-cpufreq' and 'pm-cpuidle'
* pm-cpufreq: cpufreq: postfix policy directory with the first CPU in related_cpus cpufreq: create cpu/cpufreq/policyX directories cpufreq: remove cpufreq_sysfs_{create|remove}_file() cpufreq: create cpu/cpufreq at boot time cpufreq: Use cpumask_copy instead of cpumask_or to copy a mask cpufreq: ondemand: Drop unnecessary locks from update_sampling_rate() cpufreq: intel_pstate: Fix intel_pstate powersave min_perf_pct value cpufreq: intel_pstate: Avoid calculation for max/min Documentation: kernel_parameters for Intel P state driver cpufreq: intel_pstate: Use ACPI perf configuration cpufreq: intel-pstate: Use separate max pstate for scaling cpufreq: intel_pstate: get P1 from TAR when available cpufreq: Drop redundant check for inactive policies cpufreq : powernv: Report Pmax throttling if capped below nominal frequency cpufreq: imx: update the clock switch flow to support imx6ul cpufreq: tegra20: remove superfluous CONFIG_PM ifdefs cpufreq: conservative: remove 'enable' field cpufreq: integrator: Fix module autoload for OF platform driver * pm-cpuidle: cpuidle: mvebu: disable the bind/unbind attributes and use builtin_platform_driver cpuidle: mvebu: clean up multiple platform drivers
This commit is contained in:
commit
69f8947b8c
|
@ -1547,6 +1547,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
hwp_only
|
||||
Only load intel_pstate on systems which support
|
||||
hardware P state control (HWP) if available.
|
||||
no_acpi
|
||||
Don't use ACPI processor performance control objects
|
||||
_PSS and _PPC specified limits.
|
||||
|
||||
intremap= [X86-64, Intel-IOMMU]
|
||||
on enable Interrupt Remapping (default)
|
||||
|
|
|
@ -206,6 +206,13 @@
|
|||
#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0
|
||||
#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1
|
||||
|
||||
/* Config TDP MSRs */
|
||||
#define MSR_CONFIG_TDP_NOMINAL 0x00000648
|
||||
#define MSR_CONFIG_TDP_LEVEL1 0x00000649
|
||||
#define MSR_CONFIG_TDP_LEVEL2 0x0000064A
|
||||
#define MSR_CONFIG_TDP_CONTROL 0x0000064B
|
||||
#define MSR_TURBO_ACTIVATION_RATIO 0x0000064C
|
||||
|
||||
/* Hardware P state interface */
|
||||
#define MSR_PPERF 0x0000064e
|
||||
#define MSR_PERF_LIMIT_REASONS 0x0000064f
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
config X86_INTEL_PSTATE
|
||||
bool "Intel P state control"
|
||||
depends on X86
|
||||
select ACPI_PROCESSOR if ACPI
|
||||
help
|
||||
This driver provides a P state for Intel core processors.
|
||||
The driver implements an internal governor and will become
|
||||
|
|
|
@ -843,18 +843,11 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
|
|||
|
||||
down_write(&policy->rwsem);
|
||||
|
||||
/* Updating inactive policies is invalid, so avoid doing that. */
|
||||
if (unlikely(policy_is_inactive(policy))) {
|
||||
ret = -EBUSY;
|
||||
goto unlock_policy_rwsem;
|
||||
}
|
||||
|
||||
if (fattr->store)
|
||||
ret = fattr->store(policy, buf, count);
|
||||
else
|
||||
ret = -EIO;
|
||||
|
||||
unlock_policy_rwsem:
|
||||
up_write(&policy->rwsem);
|
||||
unlock:
|
||||
put_online_cpus();
|
||||
|
@ -880,49 +873,6 @@ static struct kobj_type ktype_cpufreq = {
|
|||
.release = cpufreq_sysfs_release,
|
||||
};
|
||||
|
||||
struct kobject *cpufreq_global_kobject;
|
||||
EXPORT_SYMBOL(cpufreq_global_kobject);
|
||||
|
||||
static int cpufreq_global_kobject_usage;
|
||||
|
||||
int cpufreq_get_global_kobject(void)
|
||||
{
|
||||
if (!cpufreq_global_kobject_usage++)
|
||||
return kobject_add(cpufreq_global_kobject,
|
||||
&cpu_subsys.dev_root->kobj, "%s", "cpufreq");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_get_global_kobject);
|
||||
|
||||
void cpufreq_put_global_kobject(void)
|
||||
{
|
||||
if (!--cpufreq_global_kobject_usage)
|
||||
kobject_del(cpufreq_global_kobject);
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_put_global_kobject);
|
||||
|
||||
int cpufreq_sysfs_create_file(const struct attribute *attr)
|
||||
{
|
||||
int ret = cpufreq_get_global_kobject();
|
||||
|
||||
if (!ret) {
|
||||
ret = sysfs_create_file(cpufreq_global_kobject, attr);
|
||||
if (ret)
|
||||
cpufreq_put_global_kobject();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_sysfs_create_file);
|
||||
|
||||
void cpufreq_sysfs_remove_file(const struct attribute *attr)
|
||||
{
|
||||
sysfs_remove_file(cpufreq_global_kobject, attr);
|
||||
cpufreq_put_global_kobject();
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
|
||||
|
||||
static int add_cpu_dev_symlink(struct cpufreq_policy *policy, int cpu)
|
||||
{
|
||||
struct device *cpu_dev;
|
||||
|
@ -960,9 +910,6 @@ static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
|
|||
|
||||
/* Some related CPUs might not be present (physically hotplugged) */
|
||||
for_each_cpu(j, policy->real_cpus) {
|
||||
if (j == policy->kobj_cpu)
|
||||
continue;
|
||||
|
||||
ret = add_cpu_dev_symlink(policy, j);
|
||||
if (ret)
|
||||
break;
|
||||
|
@ -976,12 +923,8 @@ static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy)
|
|||
unsigned int j;
|
||||
|
||||
/* Some related CPUs might not be present (physically hotplugged) */
|
||||
for_each_cpu(j, policy->real_cpus) {
|
||||
if (j == policy->kobj_cpu)
|
||||
continue;
|
||||
|
||||
for_each_cpu(j, policy->real_cpus)
|
||||
remove_cpu_dev_symlink(policy, j);
|
||||
}
|
||||
}
|
||||
|
||||
static int cpufreq_add_dev_interface(struct cpufreq_policy *policy)
|
||||
|
@ -1079,7 +1022,6 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
|||
{
|
||||
struct device *dev = get_cpu_device(cpu);
|
||||
struct cpufreq_policy *policy;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!dev))
|
||||
return NULL;
|
||||
|
@ -1097,13 +1039,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
|||
if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
|
||||
goto err_free_rcpumask;
|
||||
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &dev->kobj,
|
||||
"cpufreq");
|
||||
if (ret) {
|
||||
pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
|
||||
goto err_free_real_cpus;
|
||||
}
|
||||
|
||||
kobject_init(&policy->kobj, &ktype_cpufreq);
|
||||
INIT_LIST_HEAD(&policy->policy_list);
|
||||
init_rwsem(&policy->rwsem);
|
||||
spin_lock_init(&policy->transition_lock);
|
||||
|
@ -1112,14 +1048,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
|||
INIT_WORK(&policy->update, handle_update);
|
||||
|
||||
policy->cpu = cpu;
|
||||
|
||||
/* Set this once on allocation */
|
||||
policy->kobj_cpu = cpu;
|
||||
|
||||
return policy;
|
||||
|
||||
err_free_real_cpus:
|
||||
free_cpumask_var(policy->real_cpus);
|
||||
err_free_rcpumask:
|
||||
free_cpumask_var(policy->related_cpus);
|
||||
err_free_cpumask:
|
||||
|
@ -1221,9 +1151,19 @@ static int cpufreq_online(unsigned int cpu)
|
|||
|
||||
if (new_policy) {
|
||||
/* related_cpus should at least include policy->cpus. */
|
||||
cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
|
||||
cpumask_copy(policy->related_cpus, policy->cpus);
|
||||
/* Remember CPUs present at the policy creation time. */
|
||||
cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask);
|
||||
|
||||
/* Name and add the kobject */
|
||||
ret = kobject_add(&policy->kobj, cpufreq_global_kobject,
|
||||
"policy%u",
|
||||
cpumask_first(policy->related_cpus));
|
||||
if (ret) {
|
||||
pr_err("%s: failed to add policy->kobj: %d\n", __func__,
|
||||
ret);
|
||||
goto out_exit_policy;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1467,22 +1407,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
|
|||
return;
|
||||
}
|
||||
|
||||
if (cpu != policy->kobj_cpu) {
|
||||
remove_cpu_dev_symlink(policy, cpu);
|
||||
} else {
|
||||
/*
|
||||
* The CPU owning the policy object is going away. Move it to
|
||||
* another suitable CPU.
|
||||
*/
|
||||
unsigned int new_cpu = cpumask_first(policy->real_cpus);
|
||||
struct device *new_dev = get_cpu_device(new_cpu);
|
||||
|
||||
dev_dbg(dev, "%s: Moving policy object to CPU%u\n", __func__, new_cpu);
|
||||
|
||||
sysfs_remove_link(&new_dev->kobj, "cpufreq");
|
||||
policy->kobj_cpu = new_cpu;
|
||||
WARN_ON(kobject_move(&policy->kobj, &new_dev->kobj));
|
||||
}
|
||||
remove_cpu_dev_symlink(policy, cpu);
|
||||
}
|
||||
|
||||
static void handle_update(struct work_struct *work)
|
||||
|
@ -2425,7 +2350,7 @@ static int create_boost_sysfs_file(void)
|
|||
if (!cpufreq_driver->set_boost)
|
||||
cpufreq_driver->set_boost = cpufreq_boost_set_sw;
|
||||
|
||||
ret = cpufreq_sysfs_create_file(&boost.attr);
|
||||
ret = sysfs_create_file(cpufreq_global_kobject, &boost.attr);
|
||||
if (ret)
|
||||
pr_err("%s: cannot register global BOOST sysfs file\n",
|
||||
__func__);
|
||||
|
@ -2436,7 +2361,7 @@ static int create_boost_sysfs_file(void)
|
|||
static void remove_boost_sysfs_file(void)
|
||||
{
|
||||
if (cpufreq_boost_supported())
|
||||
cpufreq_sysfs_remove_file(&boost.attr);
|
||||
sysfs_remove_file(cpufreq_global_kobject, &boost.attr);
|
||||
}
|
||||
|
||||
int cpufreq_enable_boost_support(void)
|
||||
|
@ -2584,12 +2509,15 @@ static struct syscore_ops cpufreq_syscore_ops = {
|
|||
.shutdown = cpufreq_suspend,
|
||||
};
|
||||
|
||||
struct kobject *cpufreq_global_kobject;
|
||||
EXPORT_SYMBOL(cpufreq_global_kobject);
|
||||
|
||||
static int __init cpufreq_core_init(void)
|
||||
{
|
||||
if (cpufreq_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
cpufreq_global_kobject = kobject_create();
|
||||
cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
|
||||
BUG_ON(!cpufreq_global_kobject);
|
||||
|
||||
register_syscore_ops(&cpufreq_syscore_ops);
|
||||
|
|
|
@ -23,6 +23,19 @@
|
|||
|
||||
static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);
|
||||
|
||||
static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
unsigned int event);
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
|
||||
static
|
||||
#endif
|
||||
struct cpufreq_governor cpufreq_gov_conservative = {
|
||||
.name = "conservative",
|
||||
.governor = cs_cpufreq_governor_dbs,
|
||||
.max_transition_latency = TRANSITION_LATENCY_LIMIT,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
|
@ -119,12 +132,14 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
|||
struct cpufreq_freqs *freq = data;
|
||||
struct cs_cpu_dbs_info_s *dbs_info =
|
||||
&per_cpu(cs_cpu_dbs_info, freq->cpu);
|
||||
struct cpufreq_policy *policy;
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(freq->cpu);
|
||||
|
||||
if (!dbs_info->enable)
|
||||
if (!policy)
|
||||
return 0;
|
||||
|
||||
policy = dbs_info->cdbs.shared->policy;
|
||||
/* policy isn't governed by conservative governor */
|
||||
if (policy->governor != &cpufreq_gov_conservative)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* we only care if our internally tracked freq moves outside the 'valid'
|
||||
|
@ -367,16 +382,6 @@ static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
|||
return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
|
||||
static
|
||||
#endif
|
||||
struct cpufreq_governor cpufreq_gov_conservative = {
|
||||
.name = "conservative",
|
||||
.governor = cs_cpufreq_governor_dbs,
|
||||
.max_transition_latency = TRANSITION_LATENCY_LIMIT,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init cpufreq_gov_dbs_init(void)
|
||||
{
|
||||
return cpufreq_register_governor(&cpufreq_gov_conservative);
|
||||
|
|
|
@ -348,29 +348,21 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy,
|
|||
set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
|
||||
latency * LATENCY_MULTIPLIER));
|
||||
|
||||
if (!have_governor_per_policy()) {
|
||||
if (WARN_ON(cpufreq_get_global_kobject())) {
|
||||
ret = -EINVAL;
|
||||
goto cdata_exit;
|
||||
}
|
||||
if (!have_governor_per_policy())
|
||||
cdata->gdbs_data = dbs_data;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(get_governor_parent_kobj(policy),
|
||||
get_sysfs_attr(dbs_data));
|
||||
if (ret)
|
||||
goto put_kobj;
|
||||
goto reset_gdbs_data;
|
||||
|
||||
policy->governor_data = dbs_data;
|
||||
|
||||
return 0;
|
||||
|
||||
put_kobj:
|
||||
if (!have_governor_per_policy()) {
|
||||
reset_gdbs_data:
|
||||
if (!have_governor_per_policy())
|
||||
cdata->gdbs_data = NULL;
|
||||
cpufreq_put_global_kobject();
|
||||
}
|
||||
cdata_exit:
|
||||
cdata->exit(dbs_data, !policy->governor->initialized);
|
||||
free_common_dbs_info:
|
||||
free_common_dbs_info(policy, cdata);
|
||||
|
@ -394,10 +386,8 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy,
|
|||
sysfs_remove_group(get_governor_parent_kobj(policy),
|
||||
get_sysfs_attr(dbs_data));
|
||||
|
||||
if (!have_governor_per_policy()) {
|
||||
if (!have_governor_per_policy())
|
||||
cdata->gdbs_data = NULL;
|
||||
cpufreq_put_global_kobject();
|
||||
}
|
||||
|
||||
cdata->exit(dbs_data, policy->governor->initialized == 1);
|
||||
kfree(dbs_data);
|
||||
|
@ -463,7 +453,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy,
|
|||
cdata->get_cpu_dbs_info_s(cpu);
|
||||
|
||||
cs_dbs_info->down_skip = 0;
|
||||
cs_dbs_info->enable = 1;
|
||||
cs_dbs_info->requested_freq = policy->cur;
|
||||
} else {
|
||||
struct od_ops *od_ops = cdata->gov_ops;
|
||||
|
@ -482,9 +471,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy,
|
|||
static int cpufreq_governor_stop(struct cpufreq_policy *policy,
|
||||
struct dbs_data *dbs_data)
|
||||
{
|
||||
struct common_dbs_data *cdata = dbs_data->cdata;
|
||||
unsigned int cpu = policy->cpu;
|
||||
struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu);
|
||||
struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(policy->cpu);
|
||||
struct cpu_common_dbs_info *shared = cdbs->shared;
|
||||
|
||||
/* State should be equivalent to START */
|
||||
|
@ -493,13 +480,6 @@ static int cpufreq_governor_stop(struct cpufreq_policy *policy,
|
|||
|
||||
gov_cancel_work(dbs_data, policy);
|
||||
|
||||
if (cdata->governor == GOV_CONSERVATIVE) {
|
||||
struct cs_cpu_dbs_info_s *cs_dbs_info =
|
||||
cdata->get_cpu_dbs_info_s(cpu);
|
||||
|
||||
cs_dbs_info->enable = 0;
|
||||
}
|
||||
|
||||
shared->policy = NULL;
|
||||
mutex_destroy(&shared->timer_mutex);
|
||||
return 0;
|
||||
|
|
|
@ -170,7 +170,6 @@ struct cs_cpu_dbs_info_s {
|
|||
struct cpu_dbs_info cdbs;
|
||||
unsigned int down_skip;
|
||||
unsigned int requested_freq;
|
||||
unsigned int enable:1;
|
||||
};
|
||||
|
||||
/* Per policy Governors sysfs tunables */
|
||||
|
|
|
@ -267,27 +267,19 @@ static void update_sampling_rate(struct dbs_data *dbs_data,
|
|||
dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
|
||||
cpufreq_cpu_put(policy);
|
||||
|
||||
mutex_lock(&dbs_info->cdbs.shared->timer_mutex);
|
||||
|
||||
if (!delayed_work_pending(&dbs_info->cdbs.dwork)) {
|
||||
mutex_unlock(&dbs_info->cdbs.shared->timer_mutex);
|
||||
if (!delayed_work_pending(&dbs_info->cdbs.dwork))
|
||||
continue;
|
||||
}
|
||||
|
||||
next_sampling = jiffies + usecs_to_jiffies(new_rate);
|
||||
appointed_at = dbs_info->cdbs.dwork.timer.expires;
|
||||
|
||||
if (time_before(next_sampling, appointed_at)) {
|
||||
|
||||
mutex_unlock(&dbs_info->cdbs.shared->timer_mutex);
|
||||
cancel_delayed_work_sync(&dbs_info->cdbs.dwork);
|
||||
mutex_lock(&dbs_info->cdbs.shared->timer_mutex);
|
||||
|
||||
gov_queue_work(dbs_data, policy,
|
||||
usecs_to_jiffies(new_rate), true);
|
||||
|
||||
}
|
||||
mutex_unlock(&dbs_info->cdbs.shared->timer_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,10 @@ static struct clk *pll1_sw_clk;
|
|||
static struct clk *step_clk;
|
||||
static struct clk *pll2_pfd2_396m_clk;
|
||||
|
||||
/* clk used by i.MX6UL */
|
||||
static struct clk *pll2_bus_clk;
|
||||
static struct clk *secondary_sel_clk;
|
||||
|
||||
static struct device *cpu_dev;
|
||||
static bool free_opp;
|
||||
static struct cpufreq_frequency_table *freq_table;
|
||||
|
@ -91,16 +95,36 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
|||
* The setpoints are selected per PLL/PDF frequencies, so we need to
|
||||
* reprogram PLL for frequency scaling. The procedure of reprogramming
|
||||
* PLL1 is as below.
|
||||
*
|
||||
* For i.MX6UL, it has a secondary clk mux, the cpu frequency change
|
||||
* flow is slightly different from other i.MX6 OSC.
|
||||
* The cpu frequeny change flow for i.MX6(except i.MX6UL) is as below:
|
||||
* - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
|
||||
* - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
|
||||
* - Disable pll2_pfd2_396m_clk
|
||||
*/
|
||||
clk_set_parent(step_clk, pll2_pfd2_396m_clk);
|
||||
clk_set_parent(pll1_sw_clk, step_clk);
|
||||
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
|
||||
clk_set_rate(pll1_sys_clk, new_freq * 1000);
|
||||
if (of_machine_is_compatible("fsl,imx6ul")) {
|
||||
/*
|
||||
* When changing pll1_sw_clk's parent to pll1_sys_clk,
|
||||
* CPU may run at higher than 528MHz, this will lead to
|
||||
* the system unstable if the voltage is lower than the
|
||||
* voltage of 528MHz, so lower the CPU frequency to one
|
||||
* half before changing CPU frequency.
|
||||
*/
|
||||
clk_set_rate(arm_clk, (old_freq >> 1) * 1000);
|
||||
clk_set_parent(pll1_sw_clk, pll1_sys_clk);
|
||||
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk))
|
||||
clk_set_parent(secondary_sel_clk, pll2_bus_clk);
|
||||
else
|
||||
clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk);
|
||||
clk_set_parent(step_clk, secondary_sel_clk);
|
||||
clk_set_parent(pll1_sw_clk, step_clk);
|
||||
} else {
|
||||
clk_set_parent(step_clk, pll2_pfd2_396m_clk);
|
||||
clk_set_parent(pll1_sw_clk, step_clk);
|
||||
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
|
||||
clk_set_rate(pll1_sys_clk, new_freq * 1000);
|
||||
clk_set_parent(pll1_sw_clk, pll1_sys_clk);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure the arm clock divider is what we expect */
|
||||
|
@ -186,6 +210,16 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
|||
goto put_clk;
|
||||
}
|
||||
|
||||
if (of_machine_is_compatible("fsl,imx6ul")) {
|
||||
pll2_bus_clk = clk_get(cpu_dev, "pll2_bus");
|
||||
secondary_sel_clk = clk_get(cpu_dev, "secondary_sel");
|
||||
if (IS_ERR(pll2_bus_clk) || IS_ERR(secondary_sel_clk)) {
|
||||
dev_err(cpu_dev, "failed to get clocks specific to imx6ul\n");
|
||||
ret = -ENOENT;
|
||||
goto put_clk;
|
||||
}
|
||||
}
|
||||
|
||||
arm_reg = regulator_get(cpu_dev, "arm");
|
||||
pu_reg = regulator_get_optional(cpu_dev, "pu");
|
||||
soc_reg = regulator_get(cpu_dev, "soc");
|
||||
|
@ -331,6 +365,10 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
|||
clk_put(step_clk);
|
||||
if (!IS_ERR(pll2_pfd2_396m_clk))
|
||||
clk_put(pll2_pfd2_396m_clk);
|
||||
if (!IS_ERR(pll2_bus_clk))
|
||||
clk_put(pll2_bus_clk);
|
||||
if (!IS_ERR(secondary_sel_clk))
|
||||
clk_put(secondary_sel_clk);
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
@ -350,6 +388,8 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
|
|||
clk_put(pll1_sw_clk);
|
||||
clk_put(step_clk);
|
||||
clk_put(pll2_pfd2_396m_clk);
|
||||
clk_put(pll2_bus_clk);
|
||||
clk_put(secondary_sel_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -221,6 +221,8 @@ static const struct of_device_id integrator_cpufreq_match[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, integrator_cpufreq_match);
|
||||
|
||||
static struct platform_driver integrator_cpufreq_driver = {
|
||||
.driver = {
|
||||
.name = "integrator-cpufreq",
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
#include <acpi/processor.h>
|
||||
#endif
|
||||
|
||||
#define BYT_RATIOS 0x66a
|
||||
#define BYT_VIDS 0x66b
|
||||
#define BYT_TURBO_RATIOS 0x66c
|
||||
|
@ -43,7 +47,6 @@
|
|||
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
|
||||
#define fp_toint(X) ((X) >> FRAC_BITS)
|
||||
|
||||
|
||||
static inline int32_t mul_fp(int32_t x, int32_t y)
|
||||
{
|
||||
return ((int64_t)x * (int64_t)y) >> FRAC_BITS;
|
||||
|
@ -78,6 +81,7 @@ struct pstate_data {
|
|||
int current_pstate;
|
||||
int min_pstate;
|
||||
int max_pstate;
|
||||
int max_pstate_physical;
|
||||
int scaling;
|
||||
int turbo_pstate;
|
||||
};
|
||||
|
@ -113,6 +117,9 @@ struct cpudata {
|
|||
u64 prev_mperf;
|
||||
u64 prev_tsc;
|
||||
struct sample sample;
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
struct acpi_processor_performance acpi_perf_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct cpudata **all_cpu_data;
|
||||
|
@ -127,6 +134,7 @@ struct pstate_adjust_policy {
|
|||
|
||||
struct pstate_funcs {
|
||||
int (*get_max)(void);
|
||||
int (*get_max_physical)(void);
|
||||
int (*get_min)(void);
|
||||
int (*get_turbo)(void);
|
||||
int (*get_scaling)(void);
|
||||
|
@ -142,6 +150,7 @@ struct cpu_defaults {
|
|||
static struct pstate_adjust_policy pid_params;
|
||||
static struct pstate_funcs pstate_funcs;
|
||||
static int hwp_active;
|
||||
static int no_acpi_perf;
|
||||
|
||||
struct perf_limits {
|
||||
int no_turbo;
|
||||
|
@ -154,9 +163,24 @@ struct perf_limits {
|
|||
int max_sysfs_pct;
|
||||
int min_policy_pct;
|
||||
int min_sysfs_pct;
|
||||
int max_perf_ctl;
|
||||
int min_perf_ctl;
|
||||
};
|
||||
|
||||
static struct perf_limits limits = {
|
||||
static struct perf_limits performance_limits = {
|
||||
.no_turbo = 0,
|
||||
.turbo_disabled = 0,
|
||||
.max_perf_pct = 100,
|
||||
.max_perf = int_tofp(1),
|
||||
.min_perf_pct = 100,
|
||||
.min_perf = int_tofp(1),
|
||||
.max_policy_pct = 100,
|
||||
.max_sysfs_pct = 100,
|
||||
.min_policy_pct = 0,
|
||||
.min_sysfs_pct = 0,
|
||||
};
|
||||
|
||||
static struct perf_limits powersave_limits = {
|
||||
.no_turbo = 0,
|
||||
.turbo_disabled = 0,
|
||||
.max_perf_pct = 100,
|
||||
|
@ -167,8 +191,163 @@ static struct perf_limits limits = {
|
|||
.max_sysfs_pct = 100,
|
||||
.min_policy_pct = 0,
|
||||
.min_sysfs_pct = 0,
|
||||
.max_perf_ctl = 0,
|
||||
.min_perf_ctl = 0,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
|
||||
static struct perf_limits *limits = &performance_limits;
|
||||
#else
|
||||
static struct perf_limits *limits = &powersave_limits;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
/*
|
||||
* The max target pstate ratio is a 8 bit value in both PLATFORM_INFO MSR and
|
||||
* in TURBO_RATIO_LIMIT MSR, which pstate driver stores in max_pstate and
|
||||
* max_turbo_pstate fields. The PERF_CTL MSR contains 16 bit value for P state
|
||||
* ratio, out of it only high 8 bits are used. For example 0x1700 is setting
|
||||
* target ratio 0x17. The _PSS control value stores in a format which can be
|
||||
* directly written to PERF_CTL MSR. But in intel_pstate driver this shift
|
||||
* occurs during write to PERF_CTL (E.g. for cores core_set_pstate()).
|
||||
* This function converts the _PSS control value to intel pstate driver format
|
||||
* for comparison and assignment.
|
||||
*/
|
||||
static int convert_to_native_pstate_format(struct cpudata *cpu, int index)
|
||||
{
|
||||
return cpu->acpi_perf_data.states[index].control >> 8;
|
||||
}
|
||||
|
||||
static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpudata *cpu;
|
||||
int ret;
|
||||
bool turbo_absent = false;
|
||||
int max_pstate_index;
|
||||
int min_pss_ctl, max_pss_ctl, turbo_pss_ctl;
|
||||
int i;
|
||||
|
||||
cpu = all_cpu_data[policy->cpu];
|
||||
|
||||
pr_debug("intel_pstate: default limits 0x%x 0x%x 0x%x\n",
|
||||
cpu->pstate.min_pstate, cpu->pstate.max_pstate,
|
||||
cpu->pstate.turbo_pstate);
|
||||
|
||||
if (!cpu->acpi_perf_data.shared_cpu_map &&
|
||||
zalloc_cpumask_var_node(&cpu->acpi_perf_data.shared_cpu_map,
|
||||
GFP_KERNEL, cpu_to_node(policy->cpu))) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = acpi_processor_register_performance(&cpu->acpi_perf_data,
|
||||
policy->cpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check if the control value in _PSS is for PERF_CTL MSR, which should
|
||||
* guarantee that the states returned by it map to the states in our
|
||||
* list directly.
|
||||
*/
|
||||
if (cpu->acpi_perf_data.control_register.space_id !=
|
||||
ACPI_ADR_SPACE_FIXED_HARDWARE)
|
||||
return -EIO;
|
||||
|
||||
pr_debug("intel_pstate: CPU%u - ACPI _PSS perf data\n", policy->cpu);
|
||||
for (i = 0; i < cpu->acpi_perf_data.state_count; i++)
|
||||
pr_debug(" %cP%d: %u MHz, %u mW, 0x%x\n",
|
||||
(i == cpu->acpi_perf_data.state ? '*' : ' '), i,
|
||||
(u32) cpu->acpi_perf_data.states[i].core_frequency,
|
||||
(u32) cpu->acpi_perf_data.states[i].power,
|
||||
(u32) cpu->acpi_perf_data.states[i].control);
|
||||
|
||||
/*
|
||||
* If there is only one entry _PSS, simply ignore _PSS and continue as
|
||||
* usual without taking _PSS into account
|
||||
*/
|
||||
if (cpu->acpi_perf_data.state_count < 2)
|
||||
return 0;
|
||||
|
||||
turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
|
||||
min_pss_ctl = convert_to_native_pstate_format(cpu,
|
||||
cpu->acpi_perf_data.state_count - 1);
|
||||
/* Check if there is a turbo freq in _PSS */
|
||||
if (turbo_pss_ctl <= cpu->pstate.max_pstate &&
|
||||
turbo_pss_ctl > cpu->pstate.min_pstate) {
|
||||
pr_debug("intel_pstate: no turbo range exists in _PSS\n");
|
||||
limits->no_turbo = limits->turbo_disabled = 1;
|
||||
cpu->pstate.turbo_pstate = cpu->pstate.max_pstate;
|
||||
turbo_absent = true;
|
||||
}
|
||||
|
||||
/* Check if the max non turbo p state < Intel P state max */
|
||||
max_pstate_index = turbo_absent ? 0 : 1;
|
||||
max_pss_ctl = convert_to_native_pstate_format(cpu, max_pstate_index);
|
||||
if (max_pss_ctl < cpu->pstate.max_pstate &&
|
||||
max_pss_ctl > cpu->pstate.min_pstate)
|
||||
cpu->pstate.max_pstate = max_pss_ctl;
|
||||
|
||||
/* check If min perf > Intel P State min */
|
||||
if (min_pss_ctl > cpu->pstate.min_pstate &&
|
||||
min_pss_ctl < cpu->pstate.max_pstate) {
|
||||
cpu->pstate.min_pstate = min_pss_ctl;
|
||||
policy->cpuinfo.min_freq = min_pss_ctl * cpu->pstate.scaling;
|
||||
}
|
||||
|
||||
if (turbo_absent)
|
||||
policy->cpuinfo.max_freq = cpu->pstate.max_pstate *
|
||||
cpu->pstate.scaling;
|
||||
else {
|
||||
policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate *
|
||||
cpu->pstate.scaling;
|
||||
/*
|
||||
* The _PSS table doesn't contain whole turbo frequency range.
|
||||
* This just contains +1 MHZ above the max non turbo frequency,
|
||||
* with control value corresponding to max turbo ratio. But
|
||||
* when cpufreq set policy is called, it will call with this
|
||||
* max frequency, which will cause a reduced performance as
|
||||
* this driver uses real max turbo frequency as the max
|
||||
* frequeny. So correct this frequency in _PSS table to
|
||||
* correct max turbo frequency based on the turbo ratio.
|
||||
* Also need to convert to MHz as _PSS freq is in MHz.
|
||||
*/
|
||||
cpu->acpi_perf_data.states[0].core_frequency =
|
||||
turbo_pss_ctl * 100;
|
||||
}
|
||||
|
||||
pr_debug("intel_pstate: Updated limits using _PSS 0x%x 0x%x 0x%x\n",
|
||||
cpu->pstate.min_pstate, cpu->pstate.max_pstate,
|
||||
cpu->pstate.turbo_pstate);
|
||||
pr_debug("intel_pstate: policy max_freq=%d Khz min_freq = %d KHz\n",
|
||||
policy->cpuinfo.max_freq, policy->cpuinfo.min_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpudata *cpu;
|
||||
|
||||
if (!no_acpi_perf)
|
||||
return 0;
|
||||
|
||||
cpu = all_cpu_data[policy->cpu];
|
||||
acpi_processor_unregister_performance(policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
|
||||
int deadband, int integral) {
|
||||
pid->setpoint = setpoint;
|
||||
|
@ -255,7 +434,7 @@ static inline void update_turbo_state(void)
|
|||
|
||||
cpu = all_cpu_data[0];
|
||||
rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
|
||||
limits.turbo_disabled =
|
||||
limits->turbo_disabled =
|
||||
(misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ||
|
||||
cpu->pstate.max_pstate == cpu->pstate.turbo_pstate);
|
||||
}
|
||||
|
@ -274,14 +453,14 @@ static void intel_pstate_hwp_set(void)
|
|||
|
||||
for_each_online_cpu(cpu) {
|
||||
rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
|
||||
adj_range = limits.min_perf_pct * range / 100;
|
||||
adj_range = limits->min_perf_pct * range / 100;
|
||||
min = hw_min + adj_range;
|
||||
value &= ~HWP_MIN_PERF(~0L);
|
||||
value |= HWP_MIN_PERF(min);
|
||||
|
||||
adj_range = limits.max_perf_pct * range / 100;
|
||||
adj_range = limits->max_perf_pct * range / 100;
|
||||
max = hw_min + adj_range;
|
||||
if (limits.no_turbo) {
|
||||
if (limits->no_turbo) {
|
||||
hw_max = HWP_GUARANTEED_PERF(cap);
|
||||
if (hw_max < max)
|
||||
max = hw_max;
|
||||
|
@ -350,7 +529,7 @@ static void __init intel_pstate_debug_expose_params(void)
|
|||
static ssize_t show_##file_name \
|
||||
(struct kobject *kobj, struct attribute *attr, char *buf) \
|
||||
{ \
|
||||
return sprintf(buf, "%u\n", limits.object); \
|
||||
return sprintf(buf, "%u\n", limits->object); \
|
||||
}
|
||||
|
||||
static ssize_t show_turbo_pct(struct kobject *kobj,
|
||||
|
@ -386,10 +565,10 @@ static ssize_t show_no_turbo(struct kobject *kobj,
|
|||
ssize_t ret;
|
||||
|
||||
update_turbo_state();
|
||||
if (limits.turbo_disabled)
|
||||
ret = sprintf(buf, "%u\n", limits.turbo_disabled);
|
||||
if (limits->turbo_disabled)
|
||||
ret = sprintf(buf, "%u\n", limits->turbo_disabled);
|
||||
else
|
||||
ret = sprintf(buf, "%u\n", limits.no_turbo);
|
||||
ret = sprintf(buf, "%u\n", limits->no_turbo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -405,12 +584,12 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
|
|||
return -EINVAL;
|
||||
|
||||
update_turbo_state();
|
||||
if (limits.turbo_disabled) {
|
||||
if (limits->turbo_disabled) {
|
||||
pr_warn("intel_pstate: Turbo disabled by BIOS or unavailable on processor\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
limits.no_turbo = clamp_t(int, input, 0, 1);
|
||||
limits->no_turbo = clamp_t(int, input, 0, 1);
|
||||
|
||||
if (hwp_active)
|
||||
intel_pstate_hwp_set();
|
||||
|
@ -428,11 +607,15 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
|
|||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
limits.max_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
|
||||
limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct);
|
||||
limits.max_perf_pct = max(limits.min_perf_pct, limits.max_perf_pct);
|
||||
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
|
||||
limits->max_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits->max_perf_pct = min(limits->max_policy_pct,
|
||||
limits->max_sysfs_pct);
|
||||
limits->max_perf_pct = max(limits->min_policy_pct,
|
||||
limits->max_perf_pct);
|
||||
limits->max_perf_pct = max(limits->min_perf_pct,
|
||||
limits->max_perf_pct);
|
||||
limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
|
||||
int_tofp(100));
|
||||
|
||||
if (hwp_active)
|
||||
intel_pstate_hwp_set();
|
||||
|
@ -449,11 +632,15 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
|
|||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
limits.min_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct);
|
||||
limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct);
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
limits->min_sysfs_pct = clamp_t(int, input, 0 , 100);
|
||||
limits->min_perf_pct = max(limits->min_policy_pct,
|
||||
limits->min_sysfs_pct);
|
||||
limits->min_perf_pct = min(limits->max_policy_pct,
|
||||
limits->min_perf_pct);
|
||||
limits->min_perf_pct = min(limits->max_perf_pct,
|
||||
limits->min_perf_pct);
|
||||
limits->min_perf = div_fp(int_tofp(limits->min_perf_pct),
|
||||
int_tofp(100));
|
||||
|
||||
if (hwp_active)
|
||||
intel_pstate_hwp_set();
|
||||
|
@ -533,7 +720,7 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate)
|
|||
u32 vid;
|
||||
|
||||
val = (u64)pstate << 8;
|
||||
if (limits.no_turbo && !limits.turbo_disabled)
|
||||
if (limits->no_turbo && !limits->turbo_disabled)
|
||||
val |= (u64)1 << 32;
|
||||
|
||||
vid_fp = cpudata->vid.min + mul_fp(
|
||||
|
@ -591,7 +778,7 @@ static int core_get_min_pstate(void)
|
|||
return (value >> 40) & 0xFF;
|
||||
}
|
||||
|
||||
static int core_get_max_pstate(void)
|
||||
static int core_get_max_pstate_physical(void)
|
||||
{
|
||||
u64 value;
|
||||
|
||||
|
@ -599,6 +786,46 @@ static int core_get_max_pstate(void)
|
|||
return (value >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static int core_get_max_pstate(void)
|
||||
{
|
||||
u64 tar;
|
||||
u64 plat_info;
|
||||
int max_pstate;
|
||||
int err;
|
||||
|
||||
rdmsrl(MSR_PLATFORM_INFO, plat_info);
|
||||
max_pstate = (plat_info >> 8) & 0xFF;
|
||||
|
||||
err = rdmsrl_safe(MSR_TURBO_ACTIVATION_RATIO, &tar);
|
||||
if (!err) {
|
||||
/* Do some sanity checking for safety */
|
||||
if (plat_info & 0x600000000) {
|
||||
u64 tdp_ctrl;
|
||||
u64 tdp_ratio;
|
||||
int tdp_msr;
|
||||
|
||||
err = rdmsrl_safe(MSR_CONFIG_TDP_CONTROL, &tdp_ctrl);
|
||||
if (err)
|
||||
goto skip_tar;
|
||||
|
||||
tdp_msr = MSR_CONFIG_TDP_NOMINAL + tdp_ctrl;
|
||||
err = rdmsrl_safe(tdp_msr, &tdp_ratio);
|
||||
if (err)
|
||||
goto skip_tar;
|
||||
|
||||
if (tdp_ratio - 1 == tar) {
|
||||
max_pstate = tar;
|
||||
pr_debug("max_pstate=TAC %x\n", max_pstate);
|
||||
} else {
|
||||
goto skip_tar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skip_tar:
|
||||
return max_pstate;
|
||||
}
|
||||
|
||||
static int core_get_turbo_pstate(void)
|
||||
{
|
||||
u64 value;
|
||||
|
@ -622,7 +849,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
|
|||
u64 val;
|
||||
|
||||
val = (u64)pstate << 8;
|
||||
if (limits.no_turbo && !limits.turbo_disabled)
|
||||
if (limits->no_turbo && !limits->turbo_disabled)
|
||||
val |= (u64)1 << 32;
|
||||
|
||||
wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
|
||||
|
@ -652,6 +879,7 @@ static struct cpu_defaults core_params = {
|
|||
},
|
||||
.funcs = {
|
||||
.get_max = core_get_max_pstate,
|
||||
.get_max_physical = core_get_max_pstate_physical,
|
||||
.get_min = core_get_min_pstate,
|
||||
.get_turbo = core_get_turbo_pstate,
|
||||
.get_scaling = core_get_scaling,
|
||||
|
@ -670,6 +898,7 @@ static struct cpu_defaults byt_params = {
|
|||
},
|
||||
.funcs = {
|
||||
.get_max = byt_get_max_pstate,
|
||||
.get_max_physical = byt_get_max_pstate,
|
||||
.get_min = byt_get_min_pstate,
|
||||
.get_turbo = byt_get_turbo_pstate,
|
||||
.set = byt_set_pstate,
|
||||
|
@ -689,6 +918,7 @@ static struct cpu_defaults knl_params = {
|
|||
},
|
||||
.funcs = {
|
||||
.get_max = core_get_max_pstate,
|
||||
.get_max_physical = core_get_max_pstate_physical,
|
||||
.get_min = core_get_min_pstate,
|
||||
.get_turbo = knl_get_turbo_pstate,
|
||||
.get_scaling = core_get_scaling,
|
||||
|
@ -702,7 +932,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
|
|||
int max_perf_adj;
|
||||
int min_perf;
|
||||
|
||||
if (limits.no_turbo || limits.turbo_disabled)
|
||||
if (limits->no_turbo || limits->turbo_disabled)
|
||||
max_perf = cpu->pstate.max_pstate;
|
||||
|
||||
/*
|
||||
|
@ -710,12 +940,23 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
|
|||
* policy, or by cpu specific default values determined through
|
||||
* experimentation.
|
||||
*/
|
||||
max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits.max_perf));
|
||||
*max = clamp_t(int, max_perf_adj,
|
||||
cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
|
||||
if (limits->max_perf_ctl && limits->max_sysfs_pct >=
|
||||
limits->max_policy_pct) {
|
||||
*max = limits->max_perf_ctl;
|
||||
} else {
|
||||
max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf),
|
||||
limits->max_perf));
|
||||
*max = clamp_t(int, max_perf_adj, cpu->pstate.min_pstate,
|
||||
cpu->pstate.turbo_pstate);
|
||||
}
|
||||
|
||||
min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf));
|
||||
*min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
|
||||
if (limits->min_perf_ctl) {
|
||||
*min = limits->min_perf_ctl;
|
||||
} else {
|
||||
min_perf = fp_toint(mul_fp(int_tofp(max_perf),
|
||||
limits->min_perf));
|
||||
*min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force)
|
||||
|
@ -743,6 +984,7 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
|
|||
{
|
||||
cpu->pstate.min_pstate = pstate_funcs.get_min();
|
||||
cpu->pstate.max_pstate = pstate_funcs.get_max();
|
||||
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical();
|
||||
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
|
||||
cpu->pstate.scaling = pstate_funcs.get_scaling();
|
||||
|
||||
|
@ -761,7 +1003,8 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
|
|||
|
||||
sample->freq = fp_toint(
|
||||
mul_fp(int_tofp(
|
||||
cpu->pstate.max_pstate * cpu->pstate.scaling / 100),
|
||||
cpu->pstate.max_pstate_physical *
|
||||
cpu->pstate.scaling / 100),
|
||||
core_pct));
|
||||
|
||||
sample->core_pct_busy = (int32_t)core_pct;
|
||||
|
@ -834,7 +1077,7 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
|
|||
* specified pstate.
|
||||
*/
|
||||
core_busy = cpu->sample.core_pct_busy;
|
||||
max_pstate = int_tofp(cpu->pstate.max_pstate);
|
||||
max_pstate = int_tofp(cpu->pstate.max_pstate_physical);
|
||||
current_pstate = int_tofp(cpu->pstate.current_pstate);
|
||||
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
|
||||
|
||||
|
@ -988,37 +1231,63 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
|
|||
|
||||
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
struct cpudata *cpu;
|
||||
int i;
|
||||
#endif
|
||||
pr_debug("intel_pstate: %s max %u policy->max %u\n", __func__,
|
||||
policy->cpuinfo.max_freq, policy->max);
|
||||
if (!policy->cpuinfo.max_freq)
|
||||
return -ENODEV;
|
||||
|
||||
if (policy->policy == CPUFREQ_POLICY_PERFORMANCE &&
|
||||
policy->max >= policy->cpuinfo.max_freq) {
|
||||
limits.min_policy_pct = 100;
|
||||
limits.min_perf_pct = 100;
|
||||
limits.min_perf = int_tofp(1);
|
||||
limits.max_policy_pct = 100;
|
||||
limits.max_perf_pct = 100;
|
||||
limits.max_perf = int_tofp(1);
|
||||
limits.no_turbo = 0;
|
||||
pr_debug("intel_pstate: set performance\n");
|
||||
limits = &performance_limits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100);
|
||||
limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
|
||||
limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100);
|
||||
pr_debug("intel_pstate: set powersave\n");
|
||||
limits = &powersave_limits;
|
||||
limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
|
||||
limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100);
|
||||
limits->max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
|
||||
limits->max_policy_pct = clamp_t(int, limits->max_policy_pct, 0 , 100);
|
||||
|
||||
/* Normalize user input to [min_policy_pct, max_policy_pct] */
|
||||
limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
|
||||
limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct);
|
||||
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
|
||||
limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct);
|
||||
limits->min_perf_pct = max(limits->min_policy_pct,
|
||||
limits->min_sysfs_pct);
|
||||
limits->min_perf_pct = min(limits->max_policy_pct,
|
||||
limits->min_perf_pct);
|
||||
limits->max_perf_pct = min(limits->max_policy_pct,
|
||||
limits->max_sysfs_pct);
|
||||
limits->max_perf_pct = max(limits->min_policy_pct,
|
||||
limits->max_perf_pct);
|
||||
|
||||
/* Make sure min_perf_pct <= max_perf_pct */
|
||||
limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct);
|
||||
limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct);
|
||||
|
||||
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
|
||||
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
|
||||
limits->min_perf = div_fp(int_tofp(limits->min_perf_pct),
|
||||
int_tofp(100));
|
||||
limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
|
||||
int_tofp(100));
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
cpu = all_cpu_data[policy->cpu];
|
||||
for (i = 0; i < cpu->acpi_perf_data.state_count; i++) {
|
||||
int control;
|
||||
|
||||
control = convert_to_native_pstate_format(cpu, i);
|
||||
if (control * cpu->pstate.scaling == policy->max)
|
||||
limits->max_perf_ctl = control;
|
||||
if (control * cpu->pstate.scaling == policy->min)
|
||||
limits->min_perf_ctl = control;
|
||||
}
|
||||
|
||||
pr_debug("intel_pstate: max %u policy_max %u perf_ctl [0x%x-0x%x]\n",
|
||||
policy->cpuinfo.max_freq, policy->max, limits->min_perf_ctl,
|
||||
limits->max_perf_ctl);
|
||||
#endif
|
||||
|
||||
if (hwp_active)
|
||||
intel_pstate_hwp_set();
|
||||
|
@ -1062,7 +1331,7 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
|
|||
|
||||
cpu = all_cpu_data[policy->cpu];
|
||||
|
||||
if (limits.min_perf_pct == 100 && limits.max_perf_pct == 100)
|
||||
if (limits->min_perf_pct == 100 && limits->max_perf_pct == 100)
|
||||
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
|
||||
else
|
||||
policy->policy = CPUFREQ_POLICY_POWERSAVE;
|
||||
|
@ -1074,18 +1343,30 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
|
|||
policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
|
||||
policy->cpuinfo.max_freq =
|
||||
cpu->pstate.turbo_pstate * cpu->pstate.scaling;
|
||||
if (!no_acpi_perf)
|
||||
intel_pstate_init_perf_limits(policy);
|
||||
/*
|
||||
* If there is no acpi perf data or error, we ignore and use Intel P
|
||||
* state calculated limits, So this is not fatal error.
|
||||
*/
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
cpumask_set_cpu(policy->cpu, policy->cpus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
return intel_pstate_exit_perf_limits(policy);
|
||||
}
|
||||
|
||||
static struct cpufreq_driver intel_pstate_driver = {
|
||||
.flags = CPUFREQ_CONST_LOOPS,
|
||||
.verify = intel_pstate_verify_policy,
|
||||
.setpolicy = intel_pstate_set_policy,
|
||||
.get = intel_pstate_get,
|
||||
.init = intel_pstate_cpu_init,
|
||||
.exit = intel_pstate_cpu_exit,
|
||||
.stop_cpu = intel_pstate_stop_cpu,
|
||||
.name = "intel_pstate",
|
||||
};
|
||||
|
@ -1118,6 +1399,7 @@ static void copy_pid_params(struct pstate_adjust_policy *policy)
|
|||
static void copy_cpu_funcs(struct pstate_funcs *funcs)
|
||||
{
|
||||
pstate_funcs.get_max = funcs->get_max;
|
||||
pstate_funcs.get_max_physical = funcs->get_max_physical;
|
||||
pstate_funcs.get_min = funcs->get_min;
|
||||
pstate_funcs.get_turbo = funcs->get_turbo;
|
||||
pstate_funcs.get_scaling = funcs->get_scaling;
|
||||
|
@ -1126,7 +1408,6 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
|
|||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
#include <acpi/processor.h>
|
||||
|
||||
static bool intel_pstate_no_acpi_pss(void)
|
||||
{
|
||||
|
@ -1318,6 +1599,9 @@ static int __init intel_pstate_setup(char *str)
|
|||
force_load = 1;
|
||||
if (!strcmp(str, "hwp_only"))
|
||||
hwp_only = 1;
|
||||
if (!strcmp(str, "no_acpi"))
|
||||
no_acpi_perf = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("intel_pstate", intel_pstate_setup);
|
||||
|
|
|
@ -327,8 +327,14 @@ static void powernv_cpufreq_throttle_check(void *data)
|
|||
if (chips[i].throttled)
|
||||
goto next;
|
||||
chips[i].throttled = true;
|
||||
pr_info("CPU %d on Chip %u has Pmax reduced to %d\n", cpu,
|
||||
chips[i].id, pmsr_pmax);
|
||||
if (pmsr_pmax < powernv_pstate_info.nominal)
|
||||
pr_crit("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
|
||||
cpu, chips[i].id, pmsr_pmax,
|
||||
powernv_pstate_info.nominal);
|
||||
else
|
||||
pr_info("CPU %d on Chip %u has Pmax reduced below turbo frequency (%d < %d)\n",
|
||||
cpu, chips[i].id, pmsr_pmax,
|
||||
powernv_pstate_info.max);
|
||||
} else if (chips[i].throttled) {
|
||||
chips[i].throttled = false;
|
||||
pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu,
|
||||
|
|
|
@ -175,9 +175,7 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
|
|||
.exit = tegra_cpu_exit,
|
||||
.name = "tegra",
|
||||
.attr = cpufreq_generic_attr,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cpufreq_generic_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init tegra_cpufreq_init(void)
|
||||
|
|
|
@ -99,44 +99,40 @@ static struct cpuidle_driver armada38x_idle_driver = {
|
|||
|
||||
static int mvebu_v7_cpuidle_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *id = pdev->id_entry;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
mvebu_v7_cpu_suspend = pdev->dev.platform_data;
|
||||
|
||||
if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-xp"))
|
||||
return cpuidle_register(&armadaxp_idle_driver, NULL);
|
||||
else if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-370"))
|
||||
return cpuidle_register(&armada370_idle_driver, NULL);
|
||||
else if (!strcmp(pdev->dev.driver->name, "cpuidle-armada-38x"))
|
||||
return cpuidle_register(&armada38x_idle_driver, NULL);
|
||||
else
|
||||
return -EINVAL;
|
||||
return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL);
|
||||
}
|
||||
|
||||
static struct platform_driver armadaxp_cpuidle_plat_driver = {
|
||||
.driver = {
|
||||
static const struct platform_device_id mvebu_cpuidle_ids[] = {
|
||||
{
|
||||
.name = "cpuidle-armada-xp",
|
||||
},
|
||||
.probe = mvebu_v7_cpuidle_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(armadaxp_cpuidle_plat_driver);
|
||||
|
||||
static struct platform_driver armada370_cpuidle_plat_driver = {
|
||||
.driver = {
|
||||
.driver_data = (unsigned long)&armadaxp_idle_driver,
|
||||
}, {
|
||||
.name = "cpuidle-armada-370",
|
||||
},
|
||||
.probe = mvebu_v7_cpuidle_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(armada370_cpuidle_plat_driver);
|
||||
|
||||
static struct platform_driver armada38x_cpuidle_plat_driver = {
|
||||
.driver = {
|
||||
.driver_data = (unsigned long)&armada370_idle_driver,
|
||||
}, {
|
||||
.name = "cpuidle-armada-38x",
|
||||
.driver_data = (unsigned long)&armada38x_idle_driver,
|
||||
},
|
||||
.probe = mvebu_v7_cpuidle_probe,
|
||||
{}
|
||||
};
|
||||
|
||||
module_platform_driver(armada38x_cpuidle_plat_driver);
|
||||
static struct platform_driver mvebu_cpuidle_driver = {
|
||||
.probe = mvebu_v7_cpuidle_probe,
|
||||
.driver = {
|
||||
.name = "cpuidle-mbevu",
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.id_table = mvebu_cpuidle_ids,
|
||||
};
|
||||
|
||||
builtin_platform_driver(mvebu_cpuidle_driver);
|
||||
|
||||
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver");
|
||||
|
|
|
@ -65,7 +65,6 @@ struct cpufreq_policy {
|
|||
unsigned int shared_type; /* ACPI: ANY or ALL affected CPUs
|
||||
should set cpufreq */
|
||||
unsigned int cpu; /* cpu managing this policy, must be online */
|
||||
unsigned int kobj_cpu; /* cpu managing sysfs files, can be offline */
|
||||
|
||||
struct clk *clk;
|
||||
struct cpufreq_cpuinfo cpuinfo;/* see above */
|
||||
|
@ -149,10 +148,6 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy)
|
|||
|
||||
/* /sys/devices/system/cpu/cpufreq: entry point for global variables */
|
||||
extern struct kobject *cpufreq_global_kobject;
|
||||
int cpufreq_get_global_kobject(void);
|
||||
void cpufreq_put_global_kobject(void);
|
||||
int cpufreq_sysfs_create_file(const struct attribute *attr);
|
||||
void cpufreq_sysfs_remove_file(const struct attribute *attr);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
unsigned int cpufreq_get(unsigned int cpu);
|
||||
|
|
Loading…
Reference in New Issue