Merge branch 'pm-runtime'

Merge changes related to the runtime power management of devices for
6.9-rc1:

 - Simplify pm_runtime_get_if_active() usage and add a replacement for
   pm_runtime_put_autosuspend() (Sakari Ailus).

 - Add a tracepoint for runtime_status changes tracking (Vilas Bhat).

 - Fix section title markdown in the runtime PM documentation (Yiwei
   Lin).

* pm-runtime:
  Documentation: PM: Fix runtime_pm.rst markdown syntax
  PM: runtime: add tracepoint for runtime_status changes
  PM: runtime: Add pm_runtime_put_autosuspend() replacement
  PM: runtime: Simplify pm_runtime_get_if_active() usage
This commit is contained in:
Rafael J. Wysocki 2024-03-11 15:21:00 +01:00
commit 7874b581c7
13 changed files with 117 additions and 35 deletions

View File

@ -154,7 +154,7 @@ suspending the device are satisfied) and to queue up a suspend request for the
device in that case. If there is no idle callback, or if the callback returns
0, then the PM core will attempt to carry out a runtime suspend of the device,
also respecting devices configured for autosuspend. In essence this means a
call to pm_runtime_autosuspend() (do note that drivers needs to update the
call to __pm_runtime_autosuspend() (do note that drivers needs to update the
device last busy mark, pm_runtime_mark_last_busy(), to control the delay under
this circumstance). To prevent this (for example, if the callback routine has
started a delayed suspend), the routine must return a non-zero value. Negative
@ -396,10 +396,9 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
nonzero, increment the counter and return 1; otherwise return 0 without
changing the counter
`int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count);`
`int pm_runtime_get_if_active(struct device *dev);`
- return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
runtime PM status is RPM_ACTIVE, and either ign_usage_count is true
or the device's usage_count is non-zero, increment the counter and
runtime PM status is RPM_ACTIVE, increment the counter and
return 1; otherwise return 0 without changing the counter
`void pm_runtime_put_noidle(struct device *dev);`
@ -410,6 +409,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
pm_request_idle(dev) and return its result
`int pm_runtime_put_autosuspend(struct device *dev);`
- does the same as __pm_runtime_put_autosuspend() for now, but in the
future, will also call pm_runtime_mark_last_busy() as well, DO NOT USE!
`int __pm_runtime_put_autosuspend(struct device *dev);`
- decrement the device's usage counter; if the result is 0 then run
pm_request_autosuspend(dev) and return its result
@ -540,6 +543,7 @@ It is safe to execute the following helper functions from interrupt context:
- pm_runtime_put_noidle()
- pm_runtime_put()
- pm_runtime_put_autosuspend()
- __pm_runtime_put_autosuspend()
- pm_runtime_enable()
- pm_suspend_ignore_children()
- pm_runtime_set_active()
@ -730,6 +734,7 @@ out the following operations:
for it, respectively.
7. Generic subsystem callbacks
==============================
Subsystems may wish to conserve code space by using the set of generic power
management callbacks provided by the PM core, defined in
@ -865,9 +870,9 @@ automatically be delayed until the desired period of inactivity has elapsed.
Inactivity is determined based on the power.last_busy field. Drivers should
call pm_runtime_mark_last_busy() to update this field after carrying out I/O,
typically just before calling pm_runtime_put_autosuspend(). The desired length
of the inactivity period is a matter of policy. Subsystems can set this length
initially by calling pm_runtime_set_autosuspend_delay(), but after device
typically just before calling __pm_runtime_put_autosuspend(). The desired
length of the inactivity period is a matter of policy. Subsystems can set this
length initially by calling pm_runtime_set_autosuspend_delay(), but after device
registration the length should be controlled by user space, using the
/sys/devices/.../power/autosuspend_delay_ms attribute.
@ -878,7 +883,7 @@ instead of the non-autosuspend counterparts::
Instead of: pm_runtime_suspend use: pm_runtime_autosuspend;
Instead of: pm_schedule_suspend use: pm_request_autosuspend;
Instead of: pm_runtime_put use: pm_runtime_put_autosuspend;
Instead of: pm_runtime_put use: __pm_runtime_put_autosuspend;
Instead of: pm_runtime_put_sync use: pm_runtime_put_sync_autosuspend.
Drivers may also continue to use the non-autosuspend helper functions; they
@ -917,7 +922,7 @@ Here is a schematic pseudo-code example::
lock(&foo->private_lock);
if (--foo->num_pending_requests == 0) {
pm_runtime_mark_last_busy(&foo->dev);
pm_runtime_put_autosuspend(&foo->dev);
__pm_runtime_put_autosuspend(&foo->dev);
} else {
foo_process_next_request(foo);
}

View File

@ -309,7 +309,7 @@ int ivpu_rpm_get_if_active(struct ivpu_device *vdev)
{
int ret;
ret = pm_runtime_get_if_active(vdev->drm.dev, false);
ret = pm_runtime_get_if_in_use(vdev->drm.dev);
drm_WARN_ON(&vdev->drm, ret < 0);
return ret;

View File

@ -94,6 +94,7 @@ static void update_pm_runtime_accounting(struct device *dev)
static void __update_runtime_status(struct device *dev, enum rpm_status status)
{
update_pm_runtime_accounting(dev);
trace_rpm_status(dev, status);
dev->power.runtime_status = status;
}
@ -1176,7 +1177,7 @@ int __pm_runtime_resume(struct device *dev, int rpmflags)
EXPORT_SYMBOL_GPL(__pm_runtime_resume);
/**
* pm_runtime_get_if_active - Conditionally bump up device usage counter.
* pm_runtime_get_conditional - Conditionally bump up device usage counter.
* @dev: Device to handle.
* @ign_usage_count: Whether or not to look at the current usage counter value.
*
@ -1197,7 +1198,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_resume);
* The caller is responsible for decrementing the runtime PM usage counter of
* @dev after this function has returned a positive value for it.
*/
int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count)
static int pm_runtime_get_conditional(struct device *dev, bool ign_usage_count)
{
unsigned long flags;
int retval;
@ -1218,8 +1219,39 @@ int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count)
return retval;
}
/**
* pm_runtime_get_if_active - Bump up runtime PM usage counter if the device is
* in active state
* @dev: Target device.
*
* Increment the runtime PM usage counter of @dev if its runtime PM status is
* %RPM_ACTIVE, in which case it returns 1. If the device is in a different
* state, 0 is returned. -EINVAL is returned if runtime PM is disabled for the
* device, in which case also the usage_count will remain unmodified.
*/
int pm_runtime_get_if_active(struct device *dev)
{
return pm_runtime_get_conditional(dev, true);
}
EXPORT_SYMBOL_GPL(pm_runtime_get_if_active);
/**
* pm_runtime_get_if_in_use - Conditionally bump up runtime PM usage counter.
* @dev: Target device.
*
* Increment the runtime PM usage counter of @dev if its runtime PM status is
* %RPM_ACTIVE and its runtime PM usage counter is greater than 0, in which case
* it returns 1. If the device is in a different state or its usage_count is 0,
* 0 is returned. -EINVAL is returned if runtime PM is disabled for the device,
* in which case also the usage_count will remain unmodified.
*/
int pm_runtime_get_if_in_use(struct device *dev)
{
return pm_runtime_get_conditional(dev, false);
}
EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
/**
* __pm_runtime_set_status - Set runtime PM status of a device.
* @dev: Device to handle.

View File

@ -246,7 +246,10 @@ static intel_wakeref_t __intel_runtime_pm_get_if_active(struct intel_runtime_pm
* function, since the power state is undefined. This applies
* atm to the late/early system suspend/resume handlers.
*/
if (pm_runtime_get_if_active(rpm->kdev, ignore_usecount) <= 0)
if ((ignore_usecount &&
pm_runtime_get_if_active(rpm->kdev) <= 0) ||
(!ignore_usecount &&
pm_runtime_get_if_in_use(rpm->kdev) <= 0))
return 0;
}

View File

@ -330,7 +330,7 @@ int xe_pm_runtime_put(struct xe_device *xe)
int xe_pm_runtime_get_if_active(struct xe_device *xe)
{
return pm_runtime_get_if_active(xe->drm.dev, true);
return pm_runtime_get_if_active(xe->drm.dev);
}
void xe_pm_assert_unbounded_bridge(struct xe_device *xe)

View File

@ -674,7 +674,7 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl)
break;
}
pm_status = pm_runtime_get_if_active(&client->dev, true);
pm_status = pm_runtime_get_if_active(&client->dev);
if (!pm_status)
return 0;

View File

@ -3287,7 +3287,7 @@ static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl)
exp_max, 1, exp_val);
}
pm_status = pm_runtime_get_if_active(ov64a40->dev, true);
pm_status = pm_runtime_get_if_active(ov64a40->dev);
if (!pm_status)
return 0;

View File

@ -1052,7 +1052,7 @@ static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl)
if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
return -EINVAL;
if (!pm_runtime_get_if_active(thp7312->dev, true))
if (!pm_runtime_get_if_active(thp7312->dev))
return 0;
switch (ctrl->id) {

View File

@ -92,7 +92,7 @@ static void ipa_smp2p_notify(struct ipa_smp2p *smp2p)
return;
dev = &smp2p->ipa->pdev->dev;
smp2p->power_on = pm_runtime_get_if_active(dev, true) > 0;
smp2p->power_on = pm_runtime_get_if_active(dev) > 0;
/* Signal whether the IPA power is enabled */
mask = BIT(smp2p->enabled_bit);

View File

@ -2532,7 +2532,7 @@ static void pci_pme_list_scan(struct work_struct *work)
* course of the call.
*/
if (bdev) {
bref = pm_runtime_get_if_active(bdev, true);
bref = pm_runtime_get_if_active(bdev);
if (!bref)
continue;

View File

@ -72,7 +72,8 @@ extern int pm_runtime_force_resume(struct device *dev);
extern int __pm_runtime_idle(struct device *dev, int rpmflags);
extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
extern int __pm_runtime_resume(struct device *dev, int rpmflags);
extern int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count);
extern int pm_runtime_get_if_active(struct device *dev);
extern int pm_runtime_get_if_in_use(struct device *dev);
extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
extern int pm_runtime_barrier(struct device *dev);
@ -94,18 +95,6 @@ extern void pm_runtime_release_supplier(struct device_link *link);
extern int devm_pm_runtime_enable(struct device *dev);
/**
* pm_runtime_get_if_in_use - Conditionally bump up runtime PM usage counter.
* @dev: Target device.
*
* Increment the runtime PM usage counter of @dev if its runtime PM status is
* %RPM_ACTIVE and its runtime PM usage counter is greater than 0.
*/
static inline int pm_runtime_get_if_in_use(struct device *dev)
{
return pm_runtime_get_if_active(dev, false);
}
/**
* pm_suspend_ignore_children - Set runtime PM behavior regarding children.
* @dev: Target device.
@ -275,8 +264,7 @@ static inline int pm_runtime_get_if_in_use(struct device *dev)
{
return -EINVAL;
}
static inline int pm_runtime_get_if_active(struct device *dev,
bool ign_usage_count)
static inline int pm_runtime_get_if_active(struct device *dev)
{
return -EINVAL;
}
@ -460,6 +448,18 @@ static inline int pm_runtime_put(struct device *dev)
return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_ASYNC);
}
/**
* __pm_runtime_put_autosuspend - Drop device usage counter and queue autosuspend if 0.
* @dev: Target device.
*
* Decrement the runtime PM usage counter of @dev and if it turns out to be
* equal to 0, queue up a work item for @dev like in pm_request_autosuspend().
*/
static inline int __pm_runtime_put_autosuspend(struct device *dev)
{
return __pm_runtime_suspend(dev, RPM_GET_PUT | RPM_ASYNC | RPM_AUTO);
}
/**
* pm_runtime_put_autosuspend - Drop device usage counter and queue autosuspend if 0.
* @dev: Target device.

View File

@ -101,6 +101,48 @@ TRACE_EVENT(rpm_return_int,
__entry->ret)
);
#define RPM_STATUS_STRINGS \
EM(RPM_INVALID, "RPM_INVALID") \
EM(RPM_ACTIVE, "RPM_ACTIVE") \
EM(RPM_RESUMING, "RPM_RESUMING") \
EM(RPM_SUSPENDED, "RPM_SUSPENDED") \
EMe(RPM_SUSPENDING, "RPM_SUSPENDING")
/* Enums require being exported to userspace, for user tool parsing. */
#undef EM
#undef EMe
#define EM(a, b) TRACE_DEFINE_ENUM(a);
#define EMe(a, b) TRACE_DEFINE_ENUM(a);
RPM_STATUS_STRINGS
/*
* Now redefine the EM() and EMe() macros to map the enums to the strings that
* will be printed in the output.
*/
#undef EM
#undef EMe
#define EM(a, b) { a, b },
#define EMe(a, b) { a, b }
TRACE_EVENT(rpm_status,
TP_PROTO(struct device *dev, enum rpm_status status),
TP_ARGS(dev, status),
TP_STRUCT__entry(
__string(name, dev_name(dev))
__field(int, status)
),
TP_fast_assign(
__assign_str(name, dev_name(dev));
__entry->status = status;
),
TP_printk("%s status=%s", __get_str(name),
__print_symbolic(__entry->status, RPM_STATUS_STRINGS))
);
#endif /* _TRACE_RUNTIME_POWER_H */
/* This part must be outside protection */

View File

@ -612,7 +612,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
int snd_hdac_keep_power_up(struct hdac_device *codec)
{
if (!atomic_inc_not_zero(&codec->in_pm)) {
int ret = pm_runtime_get_if_active(&codec->dev, true);
int ret = pm_runtime_get_if_active(&codec->dev);
if (!ret)
return -1;
if (ret < 0)