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:
Linus Torvalds 2016-06-17 20:08:00 -10:00
commit 057868ea15
4 changed files with 26 additions and 26 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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;

View File

@ -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;