Commit e4719b52 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge back PM core changes for v5.17.

parents 544e737d 2cdbd92c
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -265,6 +265,10 @@ defined in include/linux/pm.h:
      RPM_SUSPENDED, which means that each device is initially regarded by the
      PM core as 'suspended', regardless of its real hardware status

  `enum rpm_status last_status;`
    - the last runtime PM status of the device captured before disabling runtime
      PM for it (invalid initially and when disable_depth is 0)

  `unsigned int runtime_auto;`
    - if set, indicates that the user space has allowed the device driver to
      power manage the device at run time via the /sys/devices/.../power/control
@@ -333,10 +337,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:

  `int pm_runtime_resume(struct device *dev);`
    - execute the subsystem-level resume callback for the device; returns 0 on
      success, 1 if the device's runtime PM status was already 'active' or
      error code on failure, where -EAGAIN means it may be safe to attempt to
      resume the device again in future, but 'power.runtime_error' should be
      checked additionally, and -EACCES means that 'power.disable_depth' is
      success, 1 if the device's runtime PM status is already 'active' (also if
      'power.disable_depth' is nonzero, but the status was 'active' when it was
      changing from 0 to 1) or error code on failure, where -EAGAIN means it may
      be safe to attempt to resume the device again in future, but
      'power.runtime_error' should be checked additionally, and -EACCES means
      that the callback could not be run, because 'power.disable_depth' was
      different from 0

  `int pm_runtime_resume_and_get(struct device *dev);`
+1 −2
Original line number Diff line number Diff line
@@ -485,8 +485,7 @@ static void device_link_release_fn(struct work_struct *work)
	/* Ensure that all references to the link object have been dropped. */
	device_link_synchronize_removal();

	while (refcount_dec_not_one(&link->rpm_active))
		pm_runtime_put(link->supplier);
	pm_runtime_release_supplier(link, true);

	put_device(link->consumer);
	put_device(link->supplier);
+55 −31
Original line number Diff line number Diff line
@@ -305,19 +305,40 @@ static int rpm_get_suppliers(struct device *dev)
	return 0;
}

/**
 * pm_runtime_release_supplier - Drop references to device link's supplier.
 * @link: Target device link.
 * @check_idle: Whether or not to check if the supplier device is idle.
 *
 * Drop all runtime PM references associated with @link to its supplier device
 * and if @check_idle is set, check if that device is idle (and so it can be
 * suspended).
 */
void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
{
	struct device *supplier = link->supplier;

	/*
	 * The additional power.usage_count check is a safety net in case
	 * the rpm_active refcount becomes saturated, in which case
	 * refcount_dec_not_one() would return true forever, but it is not
	 * strictly necessary.
	 */
	while (refcount_dec_not_one(&link->rpm_active) &&
	       atomic_read(&supplier->power.usage_count) > 0)
		pm_runtime_put_noidle(supplier);

	if (check_idle)
		pm_request_idle(supplier);
}

static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
{
	struct device_link *link;

	list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
				device_links_read_lock_held()) {

		while (refcount_dec_not_one(&link->rpm_active))
			pm_runtime_put_noidle(link->supplier);

		if (try_to_suspend)
			pm_request_idle(link->supplier);
	}
				device_links_read_lock_held())
		pm_runtime_release_supplier(link, try_to_suspend);
}

static void rpm_put_suppliers(struct device *dev)
@@ -742,13 +763,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
	trace_rpm_resume_rcuidle(dev, rpmflags);

 repeat:
	if (dev->power.runtime_error)
	if (dev->power.runtime_error) {
		retval = -EINVAL;
	else if (dev->power.disable_depth == 1 && dev->power.is_suspended
	    && dev->power.runtime_status == RPM_ACTIVE)
	} else if (dev->power.disable_depth > 0) {
		if (dev->power.runtime_status == RPM_ACTIVE &&
		    dev->power.last_status == RPM_ACTIVE)
			retval = 1;
	else if (dev->power.disable_depth > 0)
		else
			retval = -EACCES;
	}
	if (retval)
		goto out;

@@ -1410,8 +1433,10 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
	/* Update time accounting before disabling PM-runtime. */
	update_pm_runtime_accounting(dev);

	if (!dev->power.disable_depth++)
	if (!dev->power.disable_depth++) {
		__pm_runtime_barrier(dev);
		dev->power.last_status = dev->power.runtime_status;
	}

 out:
	spin_unlock_irq(&dev->power.lock);
@@ -1428,23 +1453,23 @@ void pm_runtime_enable(struct device *dev)

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

	if (dev->power.disable_depth > 0) {
		dev->power.disable_depth--;

		/* About to enable runtime pm, set accounting_timestamp to now */
		if (!dev->power.disable_depth)
			dev->power.accounting_timestamp = ktime_get_mono_fast_ns();
	} else {
	if (!dev->power.disable_depth) {
		dev_warn(dev, "Unbalanced %s!\n", __func__);
		goto out;
	}

	WARN(!dev->power.disable_depth &&
	     dev->power.runtime_status == RPM_SUSPENDED &&
	if (--dev->power.disable_depth > 0)
		goto out;

	dev->power.last_status = RPM_INVALID;
	dev->power.accounting_timestamp = ktime_get_mono_fast_ns();

	if (dev->power.runtime_status == RPM_SUSPENDED &&
	    !dev->power.ignore_children &&
	     atomic_read(&dev->power.child_count) > 0,
	     "Enabling runtime PM for inactive device (%s) with active children\n",
	     dev_name(dev));
	    atomic_read(&dev->power.child_count) > 0)
		dev_warn(dev, "Enabling runtime PM for inactive device with active children\n");

out:
	spin_unlock_irqrestore(&dev->power.lock, flags);
}
EXPORT_SYMBOL_GPL(pm_runtime_enable);
@@ -1640,6 +1665,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
void pm_runtime_init(struct device *dev)
{
	dev->power.runtime_status = RPM_SUSPENDED;
	dev->power.last_status = RPM_INVALID;
	dev->power.idle_notification = false;

	dev->power.disable_depth = 1;
@@ -1772,9 +1798,7 @@ void pm_runtime_drop_link(struct device_link *link)
		return;

	pm_runtime_drop_link_count(link->consumer);

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

static bool pm_runtime_need_not_resume(struct device *dev)
+4 −4
Original line number Diff line number Diff line
@@ -1103,17 +1103,17 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
	return 0;
}

static int __maybe_unused jz4740_mmc_suspend(struct device *dev)
static int jz4740_mmc_suspend(struct device *dev)
{
	return pinctrl_pm_select_sleep_state(dev);
}

static int __maybe_unused jz4740_mmc_resume(struct device *dev)
static int jz4740_mmc_resume(struct device *dev)
{
	return pinctrl_select_default_state(dev);
}

static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
	jz4740_mmc_resume);

static struct platform_driver jz4740_mmc_driver = {
@@ -1123,7 +1123,7 @@ static struct platform_driver jz4740_mmc_driver = {
		.name = "jz4740-mmc",
		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
		.of_match_table = of_match_ptr(jz4740_mmc_of_match),
		.pm = pm_ptr(&jz4740_mmc_pm_ops),
		.pm = pm_sleep_ptr(&jz4740_mmc_pm_ops),
	},
};

+2 −4
Original line number Diff line number Diff line
@@ -1183,7 +1183,6 @@ static int mxcmci_remove(struct platform_device *pdev)
	return 0;
}

#ifdef CONFIG_PM_SLEEP
static int mxcmci_suspend(struct device *dev)
{
	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1210,9 +1209,8 @@ static int mxcmci_resume(struct device *dev)

	return ret;
}
#endif

static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);

static struct platform_driver mxcmci_driver = {
	.probe		= mxcmci_probe,
@@ -1220,7 +1218,7 @@ static struct platform_driver mxcmci_driver = {
	.driver		= {
		.name		= DRIVER_NAME,
		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
		.pm	= &mxcmci_pm_ops,
		.pm	= pm_sleep_ptr(&mxcmci_pm_ops),
		.of_match_table	= mxcmci_of_match,
	}
};
Loading