Merge branch 'pm-cpufreq'

* pm-cpufreq:
  cpufreq: move policy kobj to update_policy_cpu()
  cpufreq: propagate error returned by kobject_move()
  cpufreq: don't restore policy->cpus on failure to move kobj
  powernow-k6: support 350MHz CPU
  cpufreq: ondemand: Eliminate the deadband effect
  cpufreq: Introduce new relation for freq selection
  cpufreq: imx6: remove pu regulator dependency for SOCs with no PU regulator
  cpufreq: intel_pstate: Remove core_pct rounding
  cpufreq: intel_pstate: Simplify P state adjustment logic.
  cpufreq: intel_pstate: Keep values in aperf/mperf in full precision
  cpufreq: intel_pstate: Disable interrupts during MSRs reading
  cpufreq: intel_pstate: Align multiple lines to open parenthesis
  cpufreq: intel_pstate: Remove unnecessary intermediate variable sample_time
  cpufreq: intel_pstate: Cleanup parentheses
  cpufreq: intel_pstate: Fit code in a single line where possible
  cpufreq: intel_pstate: Add missing blank lines after declarations
  cpufreq: intel_pstate: Remove unnecessary type casting in div_s64() call
  cpufreq: intel_pstate: Make intel_pstate_kobject and debugfs_parent locals
This commit is contained in:
Rafael J. Wysocki 2014-08-05 22:49:22 +02:00
commit b14c348e8d
7 changed files with 127 additions and 138 deletions

View File

@ -1076,10 +1076,20 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
kfree(policy); kfree(policy);
} }
static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
struct device *cpu_dev)
{ {
int ret;
if (WARN_ON(cpu == policy->cpu)) if (WARN_ON(cpu == policy->cpu))
return; return 0;
/* Move kobject to the new policy->cpu */
ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
if (ret) {
pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
return ret;
}
down_write(&policy->rwsem); down_write(&policy->rwsem);
@ -1090,6 +1100,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
blocking_notifier_call_chain(&cpufreq_policy_notifier_list, blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_UPDATE_POLICY_CPU, policy); CPUFREQ_UPDATE_POLICY_CPU, policy);
return 0;
} }
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
@ -1153,12 +1165,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
* the creation of a brand new one. So we need to perform this update * the creation of a brand new one. So we need to perform this update
* by invoking update_policy_cpu(). * by invoking update_policy_cpu().
*/ */
if (recover_policy && cpu != policy->cpu) { if (recover_policy && cpu != policy->cpu)
update_policy_cpu(policy, cpu); WARN_ON(update_policy_cpu(policy, cpu, dev));
WARN_ON(kobject_move(&policy->kobj, &dev->kobj)); else
} else {
policy->cpu = cpu; policy->cpu = cpu;
}
cpumask_copy(policy->cpus, cpumask_of(cpu)); cpumask_copy(policy->cpus, cpumask_of(cpu));
@ -1309,38 +1319,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
return __cpufreq_add_dev(dev, sif); return __cpufreq_add_dev(dev, sif);
} }
static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
unsigned int old_cpu)
{
struct device *cpu_dev;
int ret;
/* first sibling now owns the new sysfs dir */
cpu_dev = get_cpu_device(cpumask_any_but(policy->cpus, old_cpu));
sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
if (ret) {
pr_err("%s: Failed to move kobj: %d\n", __func__, ret);
down_write(&policy->rwsem);
cpumask_set_cpu(old_cpu, policy->cpus);
up_write(&policy->rwsem);
ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
"cpufreq");
return -EINVAL;
}
return cpu_dev->id;
}
static int __cpufreq_remove_dev_prepare(struct device *dev, static int __cpufreq_remove_dev_prepare(struct device *dev,
struct subsys_interface *sif) struct subsys_interface *sif)
{ {
unsigned int cpu = dev->id, cpus; unsigned int cpu = dev->id, cpus;
int new_cpu, ret; int ret;
unsigned long flags; unsigned long flags;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
@ -1380,14 +1363,23 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
if (cpu != policy->cpu) { if (cpu != policy->cpu) {
sysfs_remove_link(&dev->kobj, "cpufreq"); sysfs_remove_link(&dev->kobj, "cpufreq");
} else if (cpus > 1) { } else if (cpus > 1) {
new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu); /* Nominate new CPU */
if (new_cpu >= 0) { int new_cpu = cpumask_any_but(policy->cpus, cpu);
update_policy_cpu(policy, new_cpu); struct device *cpu_dev = get_cpu_device(new_cpu);
if (!cpufreq_suspended) sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n", ret = update_policy_cpu(policy, new_cpu, cpu_dev);
__func__, new_cpu, cpu); if (ret) {
if (sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
"cpufreq"))
pr_err("%s: Failed to restore kobj link to cpu:%d\n",
__func__, cpu_dev->id);
return ret;
} }
if (!cpufreq_suspended)
pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
__func__, new_cpu, cpu);
} else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) { } else if (cpufreq_driver->stop_cpu && cpufreq_driver->setpolicy) {
cpufreq_driver->stop_cpu(policy); cpufreq_driver->stop_cpu(policy);
} }

View File

@ -170,21 +170,24 @@ static void od_check_cpu(int cpu, unsigned int load)
dbs_freq_increase(policy, policy->max); dbs_freq_increase(policy, policy->max);
} else { } else {
/* Calculate the next frequency proportional to load */ /* Calculate the next frequency proportional to load */
unsigned int freq_next; unsigned int freq_next, min_f, max_f;
freq_next = load * policy->cpuinfo.max_freq / 100;
min_f = policy->cpuinfo.min_freq;
max_f = policy->cpuinfo.max_freq;
freq_next = min_f + load * (max_f - min_f) / 100;
/* No longer fully busy, reset rate_mult */ /* No longer fully busy, reset rate_mult */
dbs_info->rate_mult = 1; dbs_info->rate_mult = 1;
if (!od_tuners->powersave_bias) { if (!od_tuners->powersave_bias) {
__cpufreq_driver_target(policy, freq_next, __cpufreq_driver_target(policy, freq_next,
CPUFREQ_RELATION_L); CPUFREQ_RELATION_C);
return; return;
} }
freq_next = od_ops.powersave_bias_target(policy, freq_next, freq_next = od_ops.powersave_bias_target(policy, freq_next,
CPUFREQ_RELATION_L); CPUFREQ_RELATION_L);
__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_C);
} }
} }

View File

@ -117,7 +117,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
.frequency = 0, .frequency = 0,
}; };
struct cpufreq_frequency_table *pos; struct cpufreq_frequency_table *pos;
unsigned int freq, i = 0; unsigned int freq, diff, i = 0;
pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
target_freq, relation, policy->cpu); target_freq, relation, policy->cpu);
@ -127,6 +127,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
suboptimal.frequency = ~0; suboptimal.frequency = ~0;
break; break;
case CPUFREQ_RELATION_L: case CPUFREQ_RELATION_L:
case CPUFREQ_RELATION_C:
optimal.frequency = ~0; optimal.frequency = ~0;
break; break;
} }
@ -168,6 +169,15 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
} }
} }
break; break;
case CPUFREQ_RELATION_C:
diff = abs(freq - target_freq);
if (diff < optimal.frequency ||
(diff == optimal.frequency &&
freq > table[optimal.driver_data].frequency)) {
optimal.frequency = diff;
optimal.driver_data = i;
}
break;
} }
} }
if (optimal.driver_data > i) { if (optimal.driver_data > i) {

View File

@ -66,10 +66,12 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
/* scaling up? scale voltage before frequency */ /* scaling up? scale voltage before frequency */
if (new_freq > old_freq) { if (new_freq > old_freq) {
ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (!IS_ERR(pu_reg)) {
if (ret) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); if (ret) {
return ret; dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);
return ret;
}
} }
ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
if (ret) { if (ret) {
@ -121,10 +123,12 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret); dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret);
ret = 0; ret = 0;
} }
ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); if (!IS_ERR(pu_reg)) {
if (ret) { ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret); if (ret) {
ret = 0; dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret);
ret = 0;
}
} }
} }
@ -182,9 +186,9 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
} }
arm_reg = regulator_get(cpu_dev, "arm"); arm_reg = regulator_get(cpu_dev, "arm");
pu_reg = regulator_get(cpu_dev, "pu"); pu_reg = regulator_get_optional(cpu_dev, "pu");
soc_reg = regulator_get(cpu_dev, "soc"); soc_reg = regulator_get(cpu_dev, "soc");
if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) { if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) {
dev_err(cpu_dev, "failed to get regulators\n"); dev_err(cpu_dev, "failed to get regulators\n");
ret = -ENOENT; ret = -ENOENT;
goto put_reg; goto put_reg;
@ -268,9 +272,11 @@ soc_opp_out:
ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); ret = regulator_set_voltage_time(soc_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);
if (ret > 0) if (ret > 0)
transition_latency += ret * 1000; transition_latency += ret * 1000;
ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); if (!IS_ERR(pu_reg)) {
if (ret > 0) ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]);
transition_latency += ret * 1000; if (ret > 0)
transition_latency += ret * 1000;
}
/* /*
* OPP is maintained in order of increasing frequency, and * OPP is maintained in order of increasing frequency, and
@ -327,7 +333,8 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
cpufreq_unregister_driver(&imx6q_cpufreq_driver); cpufreq_unregister_driver(&imx6q_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
regulator_put(arm_reg); regulator_put(arm_reg);
regulator_put(pu_reg); if (!IS_ERR(pu_reg))
regulator_put(pu_reg);
regulator_put(soc_reg); regulator_put(soc_reg);
clk_put(arm_clk); clk_put(arm_clk);
clk_put(pll1_sys_clk); clk_put(pll1_sys_clk);

View File

@ -37,7 +37,6 @@
#define BYT_TURBO_RATIOS 0x66c #define BYT_TURBO_RATIOS 0x66c
#define BYT_TURBO_VIDS 0x66d #define BYT_TURBO_VIDS 0x66d
#define FRAC_BITS 8 #define FRAC_BITS 8
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
#define fp_toint(X) ((X) >> FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS)
@ -50,7 +49,7 @@ static inline int32_t mul_fp(int32_t x, int32_t y)
static inline int32_t div_fp(int32_t x, int32_t y) static inline int32_t div_fp(int32_t x, int32_t y)
{ {
return div_s64((int64_t)x << FRAC_BITS, (int64_t)y); return div_s64((int64_t)x << FRAC_BITS, y);
} }
struct sample { struct sample {
@ -148,7 +147,7 @@ static struct perf_limits limits = {
}; };
static inline void pid_reset(struct _pid *pid, int setpoint, int busy, static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
int deadband, int integral) { int deadband, int integral) {
pid->setpoint = setpoint; pid->setpoint = setpoint;
pid->deadband = deadband; pid->deadband = deadband;
pid->integral = int_tofp(integral); pid->integral = int_tofp(integral);
@ -167,7 +166,6 @@ static inline void pid_i_gain_set(struct _pid *pid, int percent)
static inline void pid_d_gain_set(struct _pid *pid, int percent) static inline void pid_d_gain_set(struct _pid *pid, int percent)
{ {
pid->d_gain = div_fp(int_tofp(percent), int_tofp(100)); pid->d_gain = div_fp(int_tofp(percent), int_tofp(100));
} }
@ -207,16 +205,13 @@ static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu)
pid_d_gain_set(&cpu->pid, pid_params.d_gain_pct); pid_d_gain_set(&cpu->pid, pid_params.d_gain_pct);
pid_i_gain_set(&cpu->pid, pid_params.i_gain_pct); pid_i_gain_set(&cpu->pid, pid_params.i_gain_pct);
pid_reset(&cpu->pid, pid_reset(&cpu->pid, pid_params.setpoint, 100, pid_params.deadband, 0);
pid_params.setpoint,
100,
pid_params.deadband,
0);
} }
static inline void intel_pstate_reset_all_pid(void) static inline void intel_pstate_reset_all_pid(void)
{ {
unsigned int cpu; unsigned int cpu;
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
if (all_cpu_data[cpu]) if (all_cpu_data[cpu])
intel_pstate_busy_pid_reset(all_cpu_data[cpu]); intel_pstate_busy_pid_reset(all_cpu_data[cpu]);
@ -230,13 +225,13 @@ static int pid_param_set(void *data, u64 val)
intel_pstate_reset_all_pid(); intel_pstate_reset_all_pid();
return 0; return 0;
} }
static int pid_param_get(void *data, u64 *val) static int pid_param_get(void *data, u64 *val)
{ {
*val = *(u32 *)data; *val = *(u32 *)data;
return 0; return 0;
} }
DEFINE_SIMPLE_ATTRIBUTE(fops_pid_param, pid_param_get, DEFINE_SIMPLE_ATTRIBUTE(fops_pid_param, pid_param_get, pid_param_set, "%llu\n");
pid_param_set, "%llu\n");
struct pid_param { struct pid_param {
char *name; char *name;
@ -253,9 +248,9 @@ static struct pid_param pid_files[] = {
{NULL, NULL} {NULL, NULL}
}; };
static struct dentry *debugfs_parent; static void __init intel_pstate_debug_expose_params(void)
static void intel_pstate_debug_expose_params(void)
{ {
struct dentry *debugfs_parent;
int i = 0; int i = 0;
debugfs_parent = debugfs_create_dir("pstate_snb", NULL); debugfs_parent = debugfs_create_dir("pstate_snb", NULL);
@ -263,8 +258,8 @@ static void intel_pstate_debug_expose_params(void)
return; return;
while (pid_files[i].name) { while (pid_files[i].name) {
debugfs_create_file(pid_files[i].name, 0660, debugfs_create_file(pid_files[i].name, 0660,
debugfs_parent, pid_files[i].value, debugfs_parent, pid_files[i].value,
&fops_pid_param); &fops_pid_param);
i++; i++;
} }
} }
@ -280,10 +275,11 @@ static void intel_pstate_debug_expose_params(void)
} }
static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
const char *buf, size_t count) const char *buf, size_t count)
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
@ -296,10 +292,11 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
} }
static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
const char *buf, size_t count) const char *buf, size_t count)
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
@ -307,14 +304,16 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
limits.max_sysfs_pct = clamp_t(int, input, 0 , 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 = min(limits.max_policy_pct, limits.max_sysfs_pct);
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
return count; return count;
} }
static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
const char *buf, size_t count) const char *buf, size_t count)
{ {
unsigned int input; unsigned int input;
int ret; int ret;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
@ -342,17 +341,16 @@ static struct attribute *intel_pstate_attributes[] = {
static struct attribute_group intel_pstate_attr_group = { static struct attribute_group intel_pstate_attr_group = {
.attrs = intel_pstate_attributes, .attrs = intel_pstate_attributes,
}; };
static struct kobject *intel_pstate_kobject;
static void intel_pstate_sysfs_expose_params(void) static void __init intel_pstate_sysfs_expose_params(void)
{ {
struct kobject *intel_pstate_kobject;
int rc; int rc;
intel_pstate_kobject = kobject_create_and_add("intel_pstate", intel_pstate_kobject = kobject_create_and_add("intel_pstate",
&cpu_subsys.dev_root->kobj); &cpu_subsys.dev_root->kobj);
BUG_ON(!intel_pstate_kobject); BUG_ON(!intel_pstate_kobject);
rc = sysfs_create_group(intel_pstate_kobject, rc = sysfs_create_group(intel_pstate_kobject, &intel_pstate_attr_group);
&intel_pstate_attr_group);
BUG_ON(rc); BUG_ON(rc);
} }
@ -360,6 +358,7 @@ static void intel_pstate_sysfs_expose_params(void)
static int byt_get_min_pstate(void) static int byt_get_min_pstate(void)
{ {
u64 value; u64 value;
rdmsrl(BYT_RATIOS, value); rdmsrl(BYT_RATIOS, value);
return (value >> 8) & 0x7F; return (value >> 8) & 0x7F;
} }
@ -367,6 +366,7 @@ static int byt_get_min_pstate(void)
static int byt_get_max_pstate(void) static int byt_get_max_pstate(void)
{ {
u64 value; u64 value;
rdmsrl(BYT_RATIOS, value); rdmsrl(BYT_RATIOS, value);
return (value >> 16) & 0x7F; return (value >> 16) & 0x7F;
} }
@ -374,6 +374,7 @@ static int byt_get_max_pstate(void)
static int byt_get_turbo_pstate(void) static int byt_get_turbo_pstate(void)
{ {
u64 value; u64 value;
rdmsrl(BYT_TURBO_RATIOS, value); rdmsrl(BYT_TURBO_RATIOS, value);
return value & 0x7F; return value & 0x7F;
} }
@ -407,7 +408,6 @@ static void byt_get_vid(struct cpudata *cpudata)
{ {
u64 value; u64 value;
rdmsrl(BYT_VIDS, value); rdmsrl(BYT_VIDS, value);
cpudata->vid.min = int_tofp((value >> 8) & 0x7f); cpudata->vid.min = int_tofp((value >> 8) & 0x7f);
cpudata->vid.max = int_tofp((value >> 16) & 0x7f); cpudata->vid.max = int_tofp((value >> 16) & 0x7f);
@ -420,10 +420,10 @@ static void byt_get_vid(struct cpudata *cpudata)
cpudata->vid.turbo = value & 0x7f; cpudata->vid.turbo = value & 0x7f;
} }
static int core_get_min_pstate(void) static int core_get_min_pstate(void)
{ {
u64 value; u64 value;
rdmsrl(MSR_PLATFORM_INFO, value); rdmsrl(MSR_PLATFORM_INFO, value);
return (value >> 40) & 0xFF; return (value >> 40) & 0xFF;
} }
@ -431,6 +431,7 @@ static int core_get_min_pstate(void)
static int core_get_max_pstate(void) static int core_get_max_pstate(void)
{ {
u64 value; u64 value;
rdmsrl(MSR_PLATFORM_INFO, value); rdmsrl(MSR_PLATFORM_INFO, value);
return (value >> 8) & 0xFF; return (value >> 8) & 0xFF;
} }
@ -439,9 +440,10 @@ static int core_get_turbo_pstate(void)
{ {
u64 value; u64 value;
int nont, ret; int nont, ret;
rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value); rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
nont = core_get_max_pstate(); nont = core_get_max_pstate();
ret = ((value) & 255); ret = (value) & 255;
if (ret <= nont) if (ret <= nont)
ret = nont; ret = nont;
return ret; return ret;
@ -493,12 +495,12 @@ static struct cpu_defaults byt_params = {
}, },
}; };
static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
{ {
int max_perf = cpu->pstate.turbo_pstate; int max_perf = cpu->pstate.turbo_pstate;
int max_perf_adj; int max_perf_adj;
int min_perf; int min_perf;
if (limits.no_turbo) if (limits.no_turbo)
max_perf = cpu->pstate.max_pstate; max_perf = cpu->pstate.max_pstate;
@ -507,8 +509,7 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
cpu->pstate.min_pstate, cpu->pstate.turbo_pstate); cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf)); min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits.min_perf));
*min = clamp_t(int, min_perf, *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
cpu->pstate.min_pstate, max_perf);
} }
static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
@ -529,21 +530,6 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
pstate_funcs.set(cpu, pstate); pstate_funcs.set(cpu, pstate);
} }
static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps)
{
int target;
target = cpu->pstate.current_pstate + steps;
intel_pstate_set_pstate(cpu, target);
}
static inline void intel_pstate_pstate_decrease(struct cpudata *cpu, int steps)
{
int target;
target = cpu->pstate.current_pstate - steps;
intel_pstate_set_pstate(cpu, target);
}
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{ {
cpu->pstate.min_pstate = pstate_funcs.get_min(); cpu->pstate.min_pstate = pstate_funcs.get_min();
@ -559,13 +545,9 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
{ {
struct sample *sample = &cpu->sample; struct sample *sample = &cpu->sample;
int64_t core_pct; int64_t core_pct;
int32_t rem;
core_pct = int_tofp(sample->aperf) * int_tofp(100); core_pct = int_tofp(sample->aperf) * int_tofp(100);
core_pct = div_u64_rem(core_pct, int_tofp(sample->mperf), &rem); core_pct = div64_u64(core_pct, int_tofp(sample->mperf));
if ((rem << 1) >= int_tofp(sample->mperf))
core_pct += 1;
sample->freq = fp_toint( sample->freq = fp_toint(
mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
@ -576,12 +558,12 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
static inline void intel_pstate_sample(struct cpudata *cpu) static inline void intel_pstate_sample(struct cpudata *cpu)
{ {
u64 aperf, mperf; u64 aperf, mperf;
unsigned long flags;
local_irq_save(flags);
rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf); rdmsrl(MSR_IA32_MPERF, mperf);
local_irq_restore(flags);
aperf = aperf >> FRAC_BITS;
mperf = mperf >> FRAC_BITS;
cpu->last_sample_time = cpu->sample.time; cpu->last_sample_time = cpu->sample.time;
cpu->sample.time = ktime_get(); cpu->sample.time = ktime_get();
@ -598,10 +580,9 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
static inline void intel_pstate_set_sample_time(struct cpudata *cpu) static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
{ {
int sample_time, delay; int delay;
sample_time = pid_params.sample_rate_ms; delay = msecs_to_jiffies(pid_params.sample_rate_ms);
delay = msecs_to_jiffies(sample_time);
mod_timer_pinned(&cpu->timer, jiffies + delay); mod_timer_pinned(&cpu->timer, jiffies + delay);
} }
@ -616,12 +597,12 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
current_pstate = int_tofp(cpu->pstate.current_pstate); current_pstate = int_tofp(cpu->pstate.current_pstate);
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
sample_time = (pid_params.sample_rate_ms * USEC_PER_MSEC); sample_time = pid_params.sample_rate_ms * USEC_PER_MSEC;
duration_us = (u32) ktime_us_delta(cpu->sample.time, duration_us = (u32) ktime_us_delta(cpu->sample.time,
cpu->last_sample_time); cpu->last_sample_time);
if (duration_us > sample_time * 3) { if (duration_us > sample_time * 3) {
sample_ratio = div_fp(int_tofp(sample_time), sample_ratio = div_fp(int_tofp(sample_time),
int_tofp(duration_us)); int_tofp(duration_us));
core_busy = mul_fp(core_busy, sample_ratio); core_busy = mul_fp(core_busy, sample_ratio);
} }
@ -632,20 +613,15 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
{ {
int32_t busy_scaled; int32_t busy_scaled;
struct _pid *pid; struct _pid *pid;
signed int ctl = 0; signed int ctl;
int steps;
pid = &cpu->pid; pid = &cpu->pid;
busy_scaled = intel_pstate_get_scaled_busy(cpu); busy_scaled = intel_pstate_get_scaled_busy(cpu);
ctl = pid_calc(pid, busy_scaled); ctl = pid_calc(pid, busy_scaled);
steps = abs(ctl); /* Negative values of ctl increase the pstate and vice versa */
intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl);
if (ctl < 0)
intel_pstate_pstate_increase(cpu, steps);
else
intel_pstate_pstate_decrease(cpu, steps);
} }
static void intel_pstate_timer_func(unsigned long __data) static void intel_pstate_timer_func(unsigned long __data)
@ -705,8 +681,7 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
init_timer_deferrable(&cpu->timer); init_timer_deferrable(&cpu->timer);
cpu->timer.function = intel_pstate_timer_func; cpu->timer.function = intel_pstate_timer_func;
cpu->timer.data = cpu->timer.data = (unsigned long)cpu;
(unsigned long)cpu;
cpu->timer.expires = jiffies + HZ/100; cpu->timer.expires = jiffies + HZ/100;
intel_pstate_busy_pid_reset(cpu); intel_pstate_busy_pid_reset(cpu);
intel_pstate_sample(cpu); intel_pstate_sample(cpu);
@ -751,7 +726,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100); limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
limits.max_policy_pct = policy->max * 100 / policy->cpuinfo.max_freq; limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100); limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100);
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
@ -763,8 +738,8 @@ static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
{ {
cpufreq_verify_within_cpu_limits(policy); cpufreq_verify_within_cpu_limits(policy);
if ((policy->policy != CPUFREQ_POLICY_POWERSAVE) && if (policy->policy != CPUFREQ_POLICY_POWERSAVE &&
(policy->policy != CPUFREQ_POLICY_PERFORMANCE)) policy->policy != CPUFREQ_POLICY_PERFORMANCE)
return -EINVAL; return -EINVAL;
return 0; return 0;
@ -797,7 +772,7 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
rdmsrl(MSR_IA32_MISC_ENABLE, misc_en); rdmsrl(MSR_IA32_MISC_ENABLE, misc_en);
if (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE || if (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE ||
cpu->pstate.max_pstate == cpu->pstate.turbo_pstate) { cpu->pstate.max_pstate == cpu->pstate.turbo_pstate) {
limits.turbo_disabled = 1; limits.turbo_disabled = 1;
limits.no_turbo = 1; limits.no_turbo = 1;
} }
@ -839,8 +814,8 @@ static int intel_pstate_msrs_not_valid(void)
rdmsrl(MSR_IA32_MPERF, mperf); rdmsrl(MSR_IA32_MPERF, mperf);
if (!pstate_funcs.get_max() || if (!pstate_funcs.get_max() ||
!pstate_funcs.get_min() || !pstate_funcs.get_min() ||
!pstate_funcs.get_turbo()) !pstate_funcs.get_turbo())
return -ENODEV; return -ENODEV;
rdmsrl(MSR_IA32_APERF, tmp); rdmsrl(MSR_IA32_APERF, tmp);
@ -922,14 +897,14 @@ static bool intel_pstate_platform_pwr_mgmt_exists(void)
struct acpi_table_header hdr; struct acpi_table_header hdr;
struct hw_vendor_info *v_info; struct hw_vendor_info *v_info;
if (acpi_disabled if (acpi_disabled ||
|| ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr))) ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr)))
return false; return false;
for (v_info = vendor_info; v_info->valid; v_info++) { for (v_info = vendor_info; v_info->valid; v_info++) {
if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE) if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE) &&
&& !strncmp(hdr.oem_table_id, v_info->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) !strncmp(hdr.oem_table_id, v_info->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
&& intel_pstate_no_acpi_pss()) intel_pstate_no_acpi_pss())
return true; return true;
} }

View File

@ -55,6 +55,7 @@ static const struct {
unsigned freq; unsigned freq;
unsigned mult; unsigned mult;
} usual_frequency_table[] = { } usual_frequency_table[] = {
{ 350000, 35 }, // 100 * 3.5
{ 400000, 40 }, // 100 * 4 { 400000, 40 }, // 100 * 4
{ 450000, 45 }, // 100 * 4.5 { 450000, 45 }, // 100 * 4.5
{ 475000, 50 }, // 95 * 5 { 475000, 50 }, // 95 * 5

View File

@ -176,6 +176,7 @@ static inline void disable_cpufreq(void) { }
#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ #define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ #define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */
#define CPUFREQ_RELATION_C 2 /* closest frequency to target */
struct freq_attr { struct freq_attr {
struct attribute attr; struct attribute attr;