Commit eb23a119 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power management fixes from Rafael Wysocki:
 "These fix three issues in the power capping code including one recent
  regression and a runtime PM framework regression introduced during the
  6.17 development cycle:

   - Fix CPU hotplug locking deadlock reported by lockdep after a recent
     update of the Intel RAPL power capping driver (Srinivas Pandruvada)

   - Fix sscanf() error return value handling in the power capping core
     and a race condition in register_control_type() (Sumeet Pawnikar)

   - Fix a concurrent bit field update issue in the runtime PM core code
     by only updating the bit field in question when runtime PM is
     disabled (Rafael Wysocki)"

* tag 'pm-6.19-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  powercap: intel_rapl: Fix possible recursive lock warning
  PM: runtime: Do not clear needs_force_resume with enabled runtime PM
  powercap: fix sscanf() error return value handling
  powercap: fix race condition in register_control_type()
parents 14e0e8d0 277141a8
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -1868,9 +1868,12 @@ void pm_runtime_init(struct device *dev)
 */
void pm_runtime_reinit(struct device *dev)
{
	if (!pm_runtime_enabled(dev)) {
	if (pm_runtime_enabled(dev))
		return;

	if (dev->power.runtime_status == RPM_ACTIVE)
		pm_runtime_set_suspended(dev);

	if (dev->power.irq_safe) {
		spin_lock_irq(&dev->power.lock);
		dev->power.irq_safe = 0;
@@ -1878,7 +1881,6 @@ void pm_runtime_reinit(struct device *dev)
		if (dev->parent)
			pm_runtime_put(dev->parent);
	}
	}
	/*
	 * Clear power.needs_force_resume in case it has been set by
	 * pm_runtime_force_suspend() invoked from a driver remove callback.
+18 −6
Original line number Diff line number Diff line
@@ -2032,7 +2032,7 @@ static int rapl_pmu_update(struct rapl_package *rp)
	return ret;
}

int rapl_package_add_pmu(struct rapl_package *rp)
int rapl_package_add_pmu_locked(struct rapl_package *rp)
{
	struct rapl_package_pmu_data *data = &rp->pmu_data;
	int idx;
@@ -2040,8 +2040,6 @@ int rapl_package_add_pmu(struct rapl_package *rp)
	if (rp->has_pmu)
		return -EEXIST;

	guard(cpus_read_lock)();

	for (idx = 0; idx < rp->nr_domains; idx++) {
		struct rapl_domain *rd = &rp->domains[idx];
		int domain = rd->id;
@@ -2091,17 +2089,23 @@ int rapl_package_add_pmu(struct rapl_package *rp)

	return rapl_pmu_update(rp);
}
EXPORT_SYMBOL_GPL(rapl_package_add_pmu_locked);

int rapl_package_add_pmu(struct rapl_package *rp)
{
	guard(cpus_read_lock)();

	return rapl_package_add_pmu_locked(rp);
}
EXPORT_SYMBOL_GPL(rapl_package_add_pmu);

void rapl_package_remove_pmu(struct rapl_package *rp)
void rapl_package_remove_pmu_locked(struct rapl_package *rp)
{
	struct rapl_package *pos;

	if (!rp->has_pmu)
		return;

	guard(cpus_read_lock)();

	list_for_each_entry(pos, &rapl_packages, plist) {
		/* PMU is still needed */
		if (pos->has_pmu && pos != rp)
@@ -2111,6 +2115,14 @@ void rapl_package_remove_pmu(struct rapl_package *rp)
	perf_pmu_unregister(&rapl_pmu.pmu);
	memset(&rapl_pmu, 0, sizeof(struct rapl_pmu));
}
EXPORT_SYMBOL_GPL(rapl_package_remove_pmu_locked);

void rapl_package_remove_pmu(struct rapl_package *rp)
{
	guard(cpus_read_lock)();

	rapl_package_remove_pmu_locked(rp);
}
EXPORT_SYMBOL_GPL(rapl_package_remove_pmu);
#endif

+2 −2
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ static int rapl_cpu_online(unsigned int cpu)
		if (IS_ERR(rp))
			return PTR_ERR(rp);
		if (rapl_msr_pmu)
			rapl_package_add_pmu(rp);
			rapl_package_add_pmu_locked(rp);
	}
	cpumask_set_cpu(cpu, &rp->cpumask);
	return 0;
@@ -101,7 +101,7 @@ static int rapl_cpu_down_prep(unsigned int cpu)
	lead_cpu = cpumask_first(&rp->cpumask);
	if (lead_cpu >= nr_cpu_ids) {
		if (rapl_msr_pmu)
			rapl_package_remove_pmu(rp);
			rapl_package_remove_pmu_locked(rp);
		rapl_remove_package_cpuslocked(rp);
	} else if (rp->lead_cpu == cpu) {
		rp->lead_cpu = lead_cpu;
+14 −8
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ static ssize_t show_constraint_##_attr(struct device *dev, \
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
	if (sscanf(dev_attr->attr.name, "constraint_%d_", &id) != 1) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
@@ -93,7 +93,7 @@ static ssize_t store_constraint_##_attr(struct device *dev,\
	int id; \
	struct powercap_zone_constraint *pconst;\
	\
	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
	if (sscanf(dev_attr->attr.name, "constraint_%d_", &id) != 1) \
		return -EINVAL; \
	if (id >= power_zone->const_id_cnt)	\
		return -EINVAL; \
@@ -162,7 +162,7 @@ static ssize_t show_constraint_name(struct device *dev,
	ssize_t len = -ENODATA;
	struct powercap_zone_constraint *pconst;

	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id))
	if (sscanf(dev_attr->attr.name, "constraint_%d_", &id) != 1)
		return -EINVAL;
	if (id >= power_zone->const_id_cnt)
		return -EINVAL;
@@ -625,17 +625,23 @@ struct powercap_control_type *powercap_register_control_type(
	INIT_LIST_HEAD(&control_type->node);
	control_type->dev.class = &powercap_class;
	dev_set_name(&control_type->dev, "%s", name);
	result = device_register(&control_type->dev);
	if (result) {
		put_device(&control_type->dev);
		return ERR_PTR(result);
	}
	idr_init(&control_type->idr);

	mutex_lock(&powercap_cntrl_list_lock);
	list_add_tail(&control_type->node, &powercap_cntrl_list);
	mutex_unlock(&powercap_cntrl_list_lock);

	result = device_register(&control_type->dev);
	if (result) {
		mutex_lock(&powercap_cntrl_list_lock);
		list_del(&control_type->node);
		mutex_unlock(&powercap_cntrl_list_lock);

		idr_destroy(&control_type->idr);
		put_device(&control_type->dev);
		return ERR_PTR(result);
	}

	return control_type;
}
EXPORT_SYMBOL_GPL(powercap_register_control_type);
+4 −0
Original line number Diff line number Diff line
@@ -214,10 +214,14 @@ void rapl_remove_package(struct rapl_package *rp);

#ifdef CONFIG_PERF_EVENTS
int rapl_package_add_pmu(struct rapl_package *rp);
int rapl_package_add_pmu_locked(struct rapl_package *rp);
void rapl_package_remove_pmu(struct rapl_package *rp);
void rapl_package_remove_pmu_locked(struct rapl_package *rp);
#else
static inline int rapl_package_add_pmu(struct rapl_package *rp) { return 0; }
static inline int rapl_package_add_pmu_locked(struct rapl_package *rp) { return 0; }
static inline void rapl_package_remove_pmu(struct rapl_package *rp) { }
static inline void rapl_package_remove_pmu_locked(struct rapl_package *rp) { }
#endif

#endif /* __INTEL_RAPL_H__ */