Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 057868ea authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 6be28d33 9d066a25
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -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 */
		opp_table->shared_opp = true;
		opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
	}
unlock:
	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.
 *
 * 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.
 * 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;
	}

	if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
		ret = -EINVAL;
		goto unlock;
	}

	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)
			cpumask_set_cpu(opp_dev->dev->id, cpumask);
	} else {
+8 −2
Original line number Diff line number Diff line
@@ -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
			 * 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->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);

+7 −1
Original line number Diff line number Diff line
@@ -119,6 +119,12 @@ struct opp_device {
#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
 * @node:	table node - contains the devices with OPPs that
@@ -166,7 +172,7 @@ struct opp_table {
	/* For backward compatibility with v1 bindings */
	unsigned int voltage_tolerance_v1;

	bool shared_opp;
	enum opp_table_access shared_opp;
	struct dev_pm_opp *suspend_opp;

	unsigned int *supported_hw;
+2 −20
Original line number Diff line number Diff line
@@ -372,26 +372,9 @@ static bool intel_pstate_get_ppc_enable_status(void)
	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)
{
	struct cpudata *cpu;
	int turbo_pss_ctl;
	int ret;
	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
	 * this driver uses real max turbo frequency as the max
	 * 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.
	 */
	turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
	if (turbo_pss_ctl > cpu->pstate.max_pstate)
	if (!limits->turbo_disabled)
		cpu->acpi_perf_data.states[0].core_frequency =
					policy->cpuinfo.max_freq / 1000;
	cpu->valid_pss_table = true;