Commit f786dfa3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power management fixes from Rafael Wysocki:
 "These fix the device links support in runtime PM, correct mistakes in
  the cpuidle documentation, fix the handling of policy limits changes
  in the schedutil cpufreq governor, fix assorted issues in the OPP
  (operating performance points) framework and make one janitorial
  change.

  Specifics:

   - Unify the handling of managed and stateless device links in the
     runtime PM framework and prevent runtime PM references to devices
     from being leaked after device link removal (Rafael Wysocki).

   - Fix two mistakes in the cpuidle documentation (Julia Lawall).

   - Prevent the schedutil cpufreq governor from missing policy limits
     updates in some cases (Viresh Kumar).

   - Prevent static OPPs from being dropped by mistake (Viresh Kumar).

   - Prevent helper function in the OPP framework from returning
     prematurely (Viresh Kumar).

   - Prevent opp_table_lock from being held too long during removal of
     OPP tables with no more active references (Viresh Kumar).

   - Drop redundant semicolon from the Intel RAPL power capping driver
     (Tom Rix)"

* tag 'pm-5.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  PM: runtime: Resume the device earlier in __device_release_driver()
  PM: runtime: Drop pm_runtime_clean_up_links()
  PM: runtime: Drop runtime PM references to supplier on link removal
  powercap/intel_rapl: remove unneeded semicolon
  Documentation: PM: cpuidle: correct path name
  Documentation: PM: cpuidle: correct typo
  cpufreq: schedutil: Don't skip freq update if need_freq_update is set
  opp: Reduce the size of critical section in _opp_table_kref_release()
  opp: Fix early exit from dev_pm_opp_register_set_opp_helper()
  opp: Don't always remove static OPPs in _of_add_opp_table_v1()
parents 1a092479 8c14577d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ order to ask the hardware to enter that state. Also, for each
statistics of the given idle state.  That information is exposed by the kernel
via ``sysfs``.

For each CPU in the system, there is a :file:`/sys/devices/system/cpu<N>/cpuidle/`
For each CPU in the system, there is a :file:`/sys/devices/system/cpu/cpu<N>/cpuidle/`
directory in ``sysfs``, where the number ``<N>`` is assigned to the given
CPU at the initialization time.  That directory contains a set of subdirectories
called :file:`state0`, :file:`state1` and so on, up to the number of idle state
@@ -494,7 +494,7 @@ object corresponding to it, as follows:
	residency.

``below``
	Total number of times this idle state had been asked for, but cerainly
	Total number of times this idle state had been asked for, but certainly
	a deeper idle state would have been a better match for the observed idle
	duration.

+2 −4
Original line number Diff line number Diff line
@@ -773,8 +773,7 @@ static void __device_link_del(struct kref *kref)
	dev_dbg(link->consumer, "Dropping the link to %s\n",
		dev_name(link->supplier));

	if (link->flags & DL_FLAG_PM_RUNTIME)
		pm_runtime_drop_link(link->consumer);
	pm_runtime_drop_link(link);

	list_del_rcu(&link->s_node);
	list_del_rcu(&link->c_node);
@@ -788,8 +787,7 @@ static void __device_link_del(struct kref *kref)
	dev_info(link->consumer, "Dropping the link to %s\n",
		 dev_name(link->supplier));

	if (link->flags & DL_FLAG_PM_RUNTIME)
		pm_runtime_drop_link(link->consumer);
	pm_runtime_drop_link(link);

	list_del(&link->s_node);
	list_del(&link->c_node);
+5 −4
Original line number Diff line number Diff line
@@ -1117,6 +1117,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)

	drv = dev->driver;
	if (drv) {
		pm_runtime_get_sync(dev);

		while (device_links_busy(dev)) {
			__device_driver_unlock(dev, parent);

@@ -1128,12 +1130,11 @@ static void __device_release_driver(struct device *dev, struct device *parent)
			 * have released the driver successfully while this one
			 * was waiting, so check for that.
			 */
			if (dev->driver != drv)
			if (dev->driver != drv) {
				pm_runtime_put(dev);
				return;
			}

		pm_runtime_get_sync(dev);
		pm_runtime_clean_up_links(dev);
		}

		driver_sysfs_remove(dev);

+20 −37
Original line number Diff line number Diff line
@@ -1642,42 +1642,6 @@ void pm_runtime_remove(struct device *dev)
	pm_runtime_reinit(dev);
}

/**
 * pm_runtime_clean_up_links - Prepare links to consumers for driver removal.
 * @dev: Device whose driver is going to be removed.
 *
 * Check links from this device to any consumers and if any of them have active
 * runtime PM references to the device, drop the usage counter of the device
 * (as many times as needed).
 *
 * Links with the DL_FLAG_MANAGED flag unset are ignored.
 *
 * Since the device is guaranteed to be runtime-active at the point this is
 * called, nothing else needs to be done here.
 *
 * Moreover, this is called after device_links_busy() has returned 'false', so
 * the status of each link is guaranteed to be DL_STATE_SUPPLIER_UNBIND and
 * therefore rpm_active can't be manipulated concurrently.
 */
void pm_runtime_clean_up_links(struct device *dev)
{
	struct device_link *link;
	int idx;

	idx = device_links_read_lock();

	list_for_each_entry_rcu(link, &dev->links.consumers, s_node,
				device_links_read_lock_held()) {
		if (!(link->flags & DL_FLAG_MANAGED))
			continue;

		while (refcount_dec_not_one(&link->rpm_active))
			pm_runtime_put_noidle(dev);
	}

	device_links_read_unlock(idx);
}

/**
 * pm_runtime_get_suppliers - Resume and reference-count supplier devices.
 * @dev: Consumer device.
@@ -1729,7 +1693,7 @@ void pm_runtime_new_link(struct device *dev)
	spin_unlock_irq(&dev->power.lock);
}

void pm_runtime_drop_link(struct device *dev)
static void pm_runtime_drop_link_count(struct device *dev)
{
	spin_lock_irq(&dev->power.lock);
	WARN_ON(dev->power.links_count == 0);
@@ -1737,6 +1701,25 @@ void pm_runtime_drop_link(struct device *dev)
	spin_unlock_irq(&dev->power.lock);
}

/**
 * pm_runtime_drop_link - Prepare for device link removal.
 * @link: Device link going away.
 *
 * Drop the link count of the consumer end of @link and decrement the supplier
 * device's runtime PM usage counter as many times as needed to drop all of the
 * PM runtime reference to it from the consumer.
 */
void pm_runtime_drop_link(struct device_link *link)
{
	if (!(link->flags & DL_FLAG_PM_RUNTIME))
		return;

	pm_runtime_drop_link_count(link->consumer);

	while (refcount_dec_not_one(&link->rpm_active))
		pm_runtime_put(link->supplier);
}

static bool pm_runtime_need_not_resume(struct device *dev)
{
	return atomic_read(&dev->power.usage_count) <= 1 &&
+5 −4
Original line number Diff line number Diff line
@@ -1181,6 +1181,10 @@ static void _opp_table_kref_release(struct kref *kref)
	struct opp_device *opp_dev, *temp;
	int i;

	/* Drop the lock as soon as we can */
	list_del(&opp_table->node);
	mutex_unlock(&opp_table_lock);

	_of_clear_opp_table(opp_table);

	/* Release clk */
@@ -1208,10 +1212,7 @@ static void _opp_table_kref_release(struct kref *kref)

	mutex_destroy(&opp_table->genpd_virt_dev_lock);
	mutex_destroy(&opp_table->lock);
	list_del(&opp_table->node);
	kfree(opp_table);

	mutex_unlock(&opp_table_lock);
}

void dev_pm_opp_put_opp_table(struct opp_table *opp_table)
@@ -1930,7 +1931,7 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
		return ERR_PTR(-EINVAL);

	opp_table = dev_pm_opp_get_opp_table(dev);
	if (!IS_ERR(opp_table))
	if (IS_ERR(opp_table))
		return opp_table;

	/* This should be called before OPPs are initialized */
Loading