Commit 6d47254c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power management fixes from Rafael Wysocki:
 "These fix the usage of device links in the runtime PM core code and
  update the DTPM (Dynamic Thermal Power Management) feature added
  recently.

  Specifics:

   - Make the runtime PM core code avoid attempting to suspend supplier
     devices before updating the PM-runtime status of a consumer to
     'suspended' (Rafael Wysocki).

   - Fix DTPM (Dynamic Thermal Power Management) root node
     initialization and label that feature as EXPERIMENTAL in Kconfig
     (Daniel Lezcano)"

* tag 'pm-5.12-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  powercap/drivers/dtpm: Add the experimental label to the option description
  powercap/drivers/dtpm: Fix root node initialization
  PM: runtime: Update device status before letting suppliers suspend
parents ea6be461 7bff4c26
Loading
Loading
Loading
Loading
+37 −25
Original line number Diff line number Diff line
@@ -325,22 +325,22 @@ static void rpm_put_suppliers(struct device *dev)
static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
	__releases(&dev->power.lock) __acquires(&dev->power.lock)
{
	int retval, idx;
	bool use_links = dev->power.links_count > 0;
	bool get = false;
	int retval, idx;
	bool put;

	if (dev->power.irq_safe) {
		spin_unlock(&dev->power.lock);
	} else if (!use_links) {
		spin_unlock_irq(&dev->power.lock);
	} else {
		get = dev->power.runtime_status == RPM_RESUMING;

		spin_unlock_irq(&dev->power.lock);

		/*
		 * Resume suppliers if necessary.
		 *
		 * The device's runtime PM status cannot change until this
		 * routine returns, so it is safe to read the status outside of
		 * the lock.
		 */
		if (use_links && dev->power.runtime_status == RPM_RESUMING) {
		/* Resume suppliers if necessary. */
		if (get) {
			idx = device_links_read_lock();

			retval = rpm_get_suppliers(dev);
@@ -355,24 +355,36 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev)

	if (dev->power.irq_safe) {
		spin_lock(&dev->power.lock);
	} else {
		return retval;
	}

	spin_lock_irq(&dev->power.lock);

	if (!use_links)
		return retval;

	/*
		 * If the device is suspending and the callback has returned
		 * success, drop the usage counters of the suppliers that have
		 * been reference counted on its resume.
	 * If the device is suspending and the callback has returned success,
	 * drop the usage counters of the suppliers that have been reference
	 * counted on its resume.
	 *
		 * Do that if resume fails too.
	 * Do that if the resume fails too.
	 */
		if (use_links
		    && ((dev->power.runtime_status == RPM_SUSPENDING && !retval)
		    || (dev->power.runtime_status == RPM_RESUMING && retval))) {
	put = dev->power.runtime_status == RPM_SUSPENDING && !retval;
	if (put)
		__update_runtime_status(dev, RPM_SUSPENDED);
	else
		put = get && retval;

	if (put) {
		spin_unlock_irq(&dev->power.lock);

		idx = device_links_read_lock();

fail:
		rpm_put_suppliers(dev);

		device_links_read_unlock(idx);
		}

		spin_lock_irq(&dev->power.lock);
	}
+1 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ config IDLE_INJECT
	  on a per CPU basis.

config DTPM
	bool "Power capping for Dynamic Thermal Power Management"
	bool "Power capping for Dynamic Thermal Power Management (EXPERIMENTAL)"
	help
	  This enables support for the power capping for the dynamic
	  thermal power management userspace engine.
+3 −0
Original line number Diff line number Diff line
@@ -207,6 +207,9 @@ int dtpm_release_zone(struct powercap_zone *pcz)
	if (dtpm->ops)
		dtpm->ops->release(dtpm);

	if (root == dtpm)
		root = NULL;

	kfree(dtpm);

	return 0;