Commit 5fa2845f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power management fixes from Rafael Wysocki:
 "These fix problems related to frequency limits management in cpufreq
  that were introduced during the 5.3 cycle (when PM QoS had started to
  be used for that), fix a few issues in the OPP (operating performance
  points) library code and fix up the recently added haltpoll cpuidle
  driver.

  The cpufreq changes are somewhat bigger that I would like them to be
  at this stage of the cycle, but the problems fixed by them include
  crashes on boot and shutdown in some cases (among other things) and in
  my view it is better to address the root of the issue right away.

  Specifics:

   - Using device PM QoS of CPU devices for managing frequency limits in
     cpufreq does not work, so introduce frequency QoS (based on the
     original low-level PM QoS) for this purpose, switch cpufreq and
     related code over to using it and fix a race involving deferred
     updates of frequency limits on top of that (Rafael Wysocki, Sudeep
     Holla).

   - Avoid calling regulator_enable()/disable() from the OPP framework
     to avoid side-effects on boot-enabled regulators that may change
     their initial voltage due to performing initial voltage balancing
     without all restrictions from the consumers (Marek Szyprowski).

   - Avoid a kref management issue in the OPP library code and drop an
     incorrectly added lockdep_assert_held() from it (Viresh Kumar).

   - Make the recently added haltpoll cpuidle driver take the 'idle='
     override into account as appropriate (Zhenzhong Duan)"

* tag 'pm-5.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  opp: Reinitialize the list_kref before adding the static OPPs again
  cpufreq: Cancel policy update work scheduled before freeing
  cpuidle: haltpoll: Take 'idle=' override into account
  opp: core: Revert "add regulators enable and disable"
  PM: QoS: Drop frequency QoS types from device PM QoS
  cpufreq: Use per-policy frequency QoS
  PM: QoS: Introduce frequency QoS
  opp: of: drop incorrect lockdep_assert_held()
parents 65b15b7f 767d2d71
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -290,14 +290,13 @@ static int acpi_processor_notifier(struct notifier_block *nb,
				   unsigned long event, void *data)
{
	struct cpufreq_policy *policy = data;
	int cpu = policy->cpu;

	if (event == CPUFREQ_CREATE_POLICY) {
		acpi_thermal_cpufreq_init(cpu);
		acpi_processor_ppc_init(cpu);
		acpi_thermal_cpufreq_init(policy);
		acpi_processor_ppc_init(policy);
	} else if (event == CPUFREQ_REMOVE_POLICY) {
		acpi_processor_ppc_exit(cpu);
		acpi_thermal_cpufreq_exit(cpu);
		acpi_processor_ppc_exit(policy);
		acpi_thermal_cpufreq_exit(policy);
	}

	return 0;
+9 −9
Original line number Diff line number Diff line
@@ -81,10 +81,10 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
	pr->performance_platform_limit = (int)ppc;

	if (ppc >= pr->performance->state_count ||
	    unlikely(!dev_pm_qos_request_active(&pr->perflib_req)))
	    unlikely(!freq_qos_request_active(&pr->perflib_req)))
		return 0;

	ret = dev_pm_qos_update_request(&pr->perflib_req,
	ret = freq_qos_update_request(&pr->perflib_req,
			pr->performance->states[ppc].core_frequency * 1000);
	if (ret < 0) {
		pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n",
@@ -157,28 +157,28 @@ void acpi_processor_ignore_ppc_init(void)
		ignore_ppc = 0;
}

void acpi_processor_ppc_init(int cpu)
void acpi_processor_ppc_init(struct cpufreq_policy *policy)
{
	int cpu = policy->cpu;
	struct acpi_processor *pr = per_cpu(processors, cpu);
	int ret;

	if (!pr)
		return;

	ret = dev_pm_qos_add_request(get_cpu_device(cpu),
				     &pr->perflib_req, DEV_PM_QOS_MAX_FREQUENCY,
				     INT_MAX);
	ret = freq_qos_add_request(&policy->constraints, &pr->perflib_req,
				   FREQ_QOS_MAX, INT_MAX);
	if (ret < 0)
		pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu,
		       ret);
}

void acpi_processor_ppc_exit(int cpu)
void acpi_processor_ppc_exit(struct cpufreq_policy *policy)
{
	struct acpi_processor *pr = per_cpu(processors, cpu);
	struct acpi_processor *pr = per_cpu(processors, policy->cpu);

	if (pr)
		dev_pm_qos_remove_request(&pr->perflib_req);
		freq_qos_remove_request(&pr->perflib_req);
}

static int acpi_processor_get_performance_control(struct acpi_processor *pr)
+9 −9
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)

		pr = per_cpu(processors, i);

		if (unlikely(!dev_pm_qos_request_active(&pr->thermal_req)))
		if (unlikely(!freq_qos_request_active(&pr->thermal_req)))
			continue;

		policy = cpufreq_cpu_get(i);
@@ -116,7 +116,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)

		cpufreq_cpu_put(policy);

		ret = dev_pm_qos_update_request(&pr->thermal_req, max_freq);
		ret = freq_qos_update_request(&pr->thermal_req, max_freq);
		if (ret < 0) {
			pr_warn("Failed to update thermal freq constraint: CPU%d (%d)\n",
				pr->id, ret);
@@ -125,28 +125,28 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
	return 0;
}

void acpi_thermal_cpufreq_init(int cpu)
void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy)
{
	int cpu = policy->cpu;
	struct acpi_processor *pr = per_cpu(processors, cpu);
	int ret;

	if (!pr)
		return;

	ret = dev_pm_qos_add_request(get_cpu_device(cpu),
				     &pr->thermal_req, DEV_PM_QOS_MAX_FREQUENCY,
				     INT_MAX);
	ret = freq_qos_add_request(&policy->constraints, &pr->thermal_req,
				   FREQ_QOS_MAX, INT_MAX);
	if (ret < 0)
		pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu,
		       ret);
}

void acpi_thermal_cpufreq_exit(int cpu)
void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy)
{
	struct acpi_processor *pr = per_cpu(processors, cpu);
	struct acpi_processor *pr = per_cpu(processors, policy->cpu);

	if (pr)
		dev_pm_qos_remove_request(&pr->thermal_req);
		freq_qos_remove_request(&pr->thermal_req);
}
#else				/* ! CONFIG_CPU_FREQ */
static int cpufreq_get_max_state(unsigned int cpu)
+2 −68
Original line number Diff line number Diff line
@@ -115,20 +115,10 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)

	spin_lock_irqsave(&dev->power.lock, flags);

	switch (type) {
	case DEV_PM_QOS_RESUME_LATENCY:
	if (type == DEV_PM_QOS_RESUME_LATENCY) {
		ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
			: pm_qos_read_value(&qos->resume_latency);
		break;
	case DEV_PM_QOS_MIN_FREQUENCY:
		ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
			: pm_qos_read_value(&qos->min_frequency);
		break;
	case DEV_PM_QOS_MAX_FREQUENCY:
		ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
			: pm_qos_read_value(&qos->max_frequency);
		break;
	default:
	} else {
		WARN_ON(1);
		ret = 0;
	}
@@ -169,14 +159,6 @@ static int apply_constraint(struct dev_pm_qos_request *req,
			req->dev->power.set_latency_tolerance(req->dev, value);
		}
		break;
	case DEV_PM_QOS_MIN_FREQUENCY:
		ret = pm_qos_update_target(&qos->min_frequency,
					   &req->data.pnode, action, value);
		break;
	case DEV_PM_QOS_MAX_FREQUENCY:
		ret = pm_qos_update_target(&qos->max_frequency,
					   &req->data.pnode, action, value);
		break;
	case DEV_PM_QOS_FLAGS:
		ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
					  action, value);
@@ -227,24 +209,6 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
	c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
	c->type = PM_QOS_MIN;

	c = &qos->min_frequency;
	plist_head_init(&c->list);
	c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
	c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
	c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
	c->type = PM_QOS_MAX;
	c->notifiers = ++n;
	BLOCKING_INIT_NOTIFIER_HEAD(n);

	c = &qos->max_frequency;
	plist_head_init(&c->list);
	c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
	c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
	c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
	c->type = PM_QOS_MIN;
	c->notifiers = ++n;
	BLOCKING_INIT_NOTIFIER_HEAD(n);

	INIT_LIST_HEAD(&qos->flags.list);

	spin_lock_irq(&dev->power.lock);
@@ -305,18 +269,6 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
		memset(req, 0, sizeof(*req));
	}

	c = &qos->min_frequency;
	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
		memset(req, 0, sizeof(*req));
	}

	c = &qos->max_frequency;
	plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
		memset(req, 0, sizeof(*req));
	}

	f = &qos->flags;
	list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
		apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -428,8 +380,6 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
	switch(req->type) {
	case DEV_PM_QOS_RESUME_LATENCY:
	case DEV_PM_QOS_LATENCY_TOLERANCE:
	case DEV_PM_QOS_MIN_FREQUENCY:
	case DEV_PM_QOS_MAX_FREQUENCY:
		curr_value = req->data.pnode.prio;
		break;
	case DEV_PM_QOS_FLAGS:
@@ -557,14 +507,6 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
		ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
						       notifier);
		break;
	case DEV_PM_QOS_MIN_FREQUENCY:
		ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers,
						       notifier);
		break;
	case DEV_PM_QOS_MAX_FREQUENCY:
		ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers,
						       notifier);
		break;
	default:
		WARN_ON(1);
		ret = -EINVAL;
@@ -604,14 +546,6 @@ int dev_pm_qos_remove_notifier(struct device *dev,
		ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
							 notifier);
		break;
	case DEV_PM_QOS_MIN_FREQUENCY:
		ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers,
							 notifier);
		break;
	case DEV_PM_QOS_MAX_FREQUENCY:
		ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers,
							 notifier);
		break;
	default:
		WARN_ON(1);
		ret = -EINVAL;
+29 −33
Original line number Diff line number Diff line
@@ -720,7 +720,7 @@ static ssize_t store_##file_name \
	if (ret != 1)							\
		return -EINVAL;						\
									\
	ret = dev_pm_qos_update_request(policy->object##_freq_req, val);\
	ret = freq_qos_update_request(policy->object##_freq_req, val);\
	return ret >= 0 ? count : ret;					\
}

@@ -1202,19 +1202,21 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
		goto err_free_real_cpus;
	}

	freq_constraints_init(&policy->constraints);

	policy->nb_min.notifier_call = cpufreq_notifier_min;
	policy->nb_max.notifier_call = cpufreq_notifier_max;

	ret = dev_pm_qos_add_notifier(dev, &policy->nb_min,
				      DEV_PM_QOS_MIN_FREQUENCY);
	ret = freq_qos_add_notifier(&policy->constraints, FREQ_QOS_MIN,
				    &policy->nb_min);
	if (ret) {
		dev_err(dev, "Failed to register MIN QoS notifier: %d (%*pbl)\n",
			ret, cpumask_pr_args(policy->cpus));
		goto err_kobj_remove;
	}

	ret = dev_pm_qos_add_notifier(dev, &policy->nb_max,
				      DEV_PM_QOS_MAX_FREQUENCY);
	ret = freq_qos_add_notifier(&policy->constraints, FREQ_QOS_MAX,
				    &policy->nb_max);
	if (ret) {
		dev_err(dev, "Failed to register MAX QoS notifier: %d (%*pbl)\n",
			ret, cpumask_pr_args(policy->cpus));
@@ -1232,8 +1234,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
	return policy;

err_min_qos_notifier:
	dev_pm_qos_remove_notifier(dev, &policy->nb_min,
				   DEV_PM_QOS_MIN_FREQUENCY);
	freq_qos_remove_notifier(&policy->constraints, FREQ_QOS_MIN,
				 &policy->nb_min);
err_kobj_remove:
	cpufreq_policy_put_kobj(policy);
err_free_real_cpus:
@@ -1250,7 +1252,6 @@ err_free_policy:

static void cpufreq_policy_free(struct cpufreq_policy *policy)
{
	struct device *dev = get_cpu_device(policy->cpu);
	unsigned long flags;
	int cpu;

@@ -1262,10 +1263,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
		per_cpu(cpufreq_cpu_data, cpu) = NULL;
	write_unlock_irqrestore(&cpufreq_driver_lock, flags);

	dev_pm_qos_remove_notifier(dev, &policy->nb_max,
				   DEV_PM_QOS_MAX_FREQUENCY);
	dev_pm_qos_remove_notifier(dev, &policy->nb_min,
				   DEV_PM_QOS_MIN_FREQUENCY);
	freq_qos_remove_notifier(&policy->constraints, FREQ_QOS_MAX,
				 &policy->nb_max);
	freq_qos_remove_notifier(&policy->constraints, FREQ_QOS_MIN,
				 &policy->nb_min);

	/* Cancel any pending policy->update work before freeing the policy. */
	cancel_work_sync(&policy->update);

	if (policy->max_freq_req) {
		/*
@@ -1274,10 +1278,10 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
		 */
		blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
					     CPUFREQ_REMOVE_POLICY, policy);
		dev_pm_qos_remove_request(policy->max_freq_req);
		freq_qos_remove_request(policy->max_freq_req);
	}

	dev_pm_qos_remove_request(policy->min_freq_req);
	freq_qos_remove_request(policy->min_freq_req);
	kfree(policy->min_freq_req);

	cpufreq_policy_put_kobj(policy);
@@ -1357,8 +1361,6 @@ static int cpufreq_online(unsigned int cpu)
	cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);

	if (new_policy) {
		struct device *dev = get_cpu_device(cpu);

		for_each_cpu(j, policy->related_cpus) {
			per_cpu(cpufreq_cpu_data, j) = policy;
			add_cpu_dev_symlink(policy, j);
@@ -1369,36 +1371,31 @@ static int cpufreq_online(unsigned int cpu)
		if (!policy->min_freq_req)
			goto out_destroy_policy;

		ret = dev_pm_qos_add_request(dev, policy->min_freq_req,
					     DEV_PM_QOS_MIN_FREQUENCY,
		ret = freq_qos_add_request(&policy->constraints,
					   policy->min_freq_req, FREQ_QOS_MIN,
					   policy->min);
		if (ret < 0) {
			/*
			 * So we don't call dev_pm_qos_remove_request() for an
			 * So we don't call freq_qos_remove_request() for an
			 * uninitialized request.
			 */
			kfree(policy->min_freq_req);
			policy->min_freq_req = NULL;

			dev_err(dev, "Failed to add min-freq constraint (%d)\n",
				ret);
			goto out_destroy_policy;
		}

		/*
		 * This must be initialized right here to avoid calling
		 * dev_pm_qos_remove_request() on uninitialized request in case
		 * freq_qos_remove_request() on uninitialized request in case
		 * of errors.
		 */
		policy->max_freq_req = policy->min_freq_req + 1;

		ret = dev_pm_qos_add_request(dev, policy->max_freq_req,
					     DEV_PM_QOS_MAX_FREQUENCY,
		ret = freq_qos_add_request(&policy->constraints,
					   policy->max_freq_req, FREQ_QOS_MAX,
					   policy->max);
		if (ret < 0) {
			policy->max_freq_req = NULL;
			dev_err(dev, "Failed to add max-freq constraint (%d)\n",
				ret);
			goto out_destroy_policy;
		}

@@ -2374,7 +2371,6 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
		       struct cpufreq_policy *new_policy)
{
	struct cpufreq_governor *old_gov;
	struct device *cpu_dev = get_cpu_device(policy->cpu);
	int ret;

	pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
@@ -2386,8 +2382,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
	 * PM QoS framework collects all the requests from users and provide us
	 * the final aggregated value here.
	 */
	new_policy->min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
	new_policy->max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
	new_policy->min = freq_qos_read_value(&policy->constraints, FREQ_QOS_MIN);
	new_policy->max = freq_qos_read_value(&policy->constraints, FREQ_QOS_MAX);

	/* verify the cpu speed can be set within this limit */
	ret = cpufreq_driver->verify(new_policy);
@@ -2518,7 +2514,7 @@ static int cpufreq_boost_set_sw(int state)
			break;
		}

		ret = dev_pm_qos_update_request(policy->max_freq_req, policy->max);
		ret = freq_qos_update_request(policy->max_freq_req, policy->max);
		if (ret < 0)
			break;
	}
Loading