Power management fixes for v4.7-rc4
- Fix a recent regression in the intel_pstate driver that may lead to degraded performance on some systems due to missing turbo state entry in the table returned by the ACPI _PSS object (Srinivas Pandruvada). - Fix a recent regression in the OPP (operating performance points) framework that may lead to degraded performance on some systems where the OPP table is created too early (Viresh Kumar). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJXZJSaAAoJEILEb/54YlRxsSIP/3La4sQznXd2U5S4E/kjy7eh 7bidzRH1R0RlkCnE6WmRMSVwAG5dF3n3vQMYFIQxT1Mq1Fbbfmb+fPgWVJ+2xbjJ +2yobuq385bwE4Y1RJViLcYsEEA1t/92r6gE3eI6x2jYg0FUJ4YHYAg22aYUGyDE p5PmazJX1v4wuEarwe1qKloNLRW++mqyERdobH21JLTaRECuwC669ydZt6OMDNk6 lx0thNyOtNumr6w4Z3RSgIo3+pHjSYLIjL9yxRTWgQAmAFr7WdWyfP/nh48p8fEj sP8yuaRcIBOzxC8IXP2jlLENmkLZI+dttFz7CQ8xEwdhzMSZ1Z9dJb82dSO5gTc8 F8xY48xk+W5jH+qLc4ZayS4sCxWgAphFTpAq6o9N16zbRo5BPOmyYujOIlMl6lvz 4n95r+1OkvX0k4b07rkBJcrKb8mDKhmnv2K0UDyNElz6Ihx2YgMlv2YGWOYhT88K 8X49o2HaftRJDK2rtOhvCivQUU/cj3ldTu7Ys0hTBe+OxIeGA2+OJz1gr60gYMcz jN75c2llTQfJeMa4X2ysFEHUma5QNv8IqV2IsqsmGtcmZx3ARkKfH1yfqWQlzLU0 HY1cht5S1vc1e4AsezwfejwFaNdo02U/yXa2SHYYlw0tL+0J039XGTKQswh3RRT2 y3lQnQOl2ogeKHsTxELr =BG8V -----END PGP SIGNATURE----- Merge tag 'pm-4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management fixes from Rafael Wysocki: "Fixes for two recent regressions that may lead to degraded performance (operating performance points framework, intel_pstate). Specifics: - Fix a recent regression in the intel_pstate driver that may lead to degraded performance on some systems due to missing turbo state entry in the table returned by the ACPI _PSS object (Srinivas Pandruvada). - Fix a recent regression in the OPP (operating performance points) framework that may lead to degraded performance on some systems where the OPP table is created too early (Viresh Kumar)" * tag 'pm-4.7-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: PM / OPP: Add 'UNKNOWN' status for shared_opp in struct opp_table cpufreq: intel_pstate: Adjust _PSS[0] freqeuency if needed
This commit is contained in:
commit
057868ea15
|
@ -211,7 +211,7 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark opp-table as multiple CPUs are sharing it now */
|
/* Mark opp-table as multiple CPUs are sharing it now */
|
||||||
opp_table->shared_opp = true;
|
opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
|
||||||
}
|
}
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&opp_table_lock);
|
mutex_unlock(&opp_table_lock);
|
||||||
|
@ -227,7 +227,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
|
||||||
*
|
*
|
||||||
* This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
|
* This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
|
||||||
*
|
*
|
||||||
* Returns -ENODEV if OPP table isn't already present.
|
* Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP
|
||||||
|
* table's status is access-unknown.
|
||||||
*
|
*
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
* Locking: The internal opp_table and opp structures are RCU protected.
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
* Hence this function internally uses RCU updater strategy with mutex locks
|
||||||
|
@ -249,9 +250,14 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
cpumask_clear(cpumask);
|
cpumask_clear(cpumask);
|
||||||
|
|
||||||
if (opp_table->shared_opp) {
|
if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
|
||||||
list_for_each_entry(opp_dev, &opp_table->dev_list, node)
|
list_for_each_entry(opp_dev, &opp_table->dev_list, node)
|
||||||
cpumask_set_cpu(opp_dev->dev->id, cpumask);
|
cpumask_set_cpu(opp_dev->dev->id, cpumask);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -34,7 +34,10 @@ static struct opp_table *_managed_opp(const struct device_node *np)
|
||||||
* But the OPPs will be considered as shared only if the
|
* But the OPPs will be considered as shared only if the
|
||||||
* OPP table contains a "opp-shared" property.
|
* OPP table contains a "opp-shared" property.
|
||||||
*/
|
*/
|
||||||
return opp_table->shared_opp ? opp_table : NULL;
|
if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED)
|
||||||
|
return opp_table;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +356,10 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
|
||||||
}
|
}
|
||||||
|
|
||||||
opp_table->np = opp_np;
|
opp_table->np = opp_np;
|
||||||
opp_table->shared_opp = of_property_read_bool(opp_np, "opp-shared");
|
if (of_property_read_bool(opp_np, "opp-shared"))
|
||||||
|
opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
|
||||||
|
else
|
||||||
|
opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
|
||||||
|
|
||||||
mutex_unlock(&opp_table_lock);
|
mutex_unlock(&opp_table_lock);
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,12 @@ struct opp_device {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum opp_table_access {
|
||||||
|
OPP_TABLE_ACCESS_UNKNOWN = 0,
|
||||||
|
OPP_TABLE_ACCESS_EXCLUSIVE = 1,
|
||||||
|
OPP_TABLE_ACCESS_SHARED = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct opp_table - Device opp structure
|
* struct opp_table - Device opp structure
|
||||||
* @node: table node - contains the devices with OPPs that
|
* @node: table node - contains the devices with OPPs that
|
||||||
|
@ -166,7 +172,7 @@ struct opp_table {
|
||||||
/* For backward compatibility with v1 bindings */
|
/* For backward compatibility with v1 bindings */
|
||||||
unsigned int voltage_tolerance_v1;
|
unsigned int voltage_tolerance_v1;
|
||||||
|
|
||||||
bool shared_opp;
|
enum opp_table_access shared_opp;
|
||||||
struct dev_pm_opp *suspend_opp;
|
struct dev_pm_opp *suspend_opp;
|
||||||
|
|
||||||
unsigned int *supported_hw;
|
unsigned int *supported_hw;
|
||||||
|
|
|
@ -372,26 +372,9 @@ static bool intel_pstate_get_ppc_enable_status(void)
|
||||||
return acpi_ppc;
|
return acpi_ppc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
|
static void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
struct cpudata *cpu;
|
struct cpudata *cpu;
|
||||||
int turbo_pss_ctl;
|
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -441,11 +424,10 @@ static void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
|
||||||
* max frequency, which will cause a reduced performance as
|
* max frequency, which will cause a reduced performance as
|
||||||
* this driver uses real max turbo frequency as the max
|
* this driver uses real max turbo frequency as the max
|
||||||
* frequency. So correct this frequency in _PSS table to
|
* frequency. So correct this frequency in _PSS table to
|
||||||
* correct max turbo frequency based on the turbo ratio.
|
* correct max turbo frequency based on the turbo state.
|
||||||
* Also need to convert to MHz as _PSS freq is in MHz.
|
* Also need to convert to MHz as _PSS freq is in MHz.
|
||||||
*/
|
*/
|
||||||
turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
|
if (!limits->turbo_disabled)
|
||||||
if (turbo_pss_ctl > cpu->pstate.max_pstate)
|
|
||||||
cpu->acpi_perf_data.states[0].core_frequency =
|
cpu->acpi_perf_data.states[0].core_frequency =
|
||||||
policy->cpuinfo.max_freq / 1000;
|
policy->cpuinfo.max_freq / 1000;
|
||||||
cpu->valid_pss_table = true;
|
cpu->valid_pss_table = true;
|
||||||
|
|
Loading…
Reference in New Issue