Skip to content

Commit 4080ab0

Browse files
rafaeljwgregkh
authored andcommitted
PM-runtime: Take suppliers into account in __pm_runtime_set_status()
If the target device has any suppliers, as reflected by device links to them, __pm_runtime_set_status() does not take them into account, which is not consistent with the other parts of the PM-runtime framework and may lead to programming mistakes. Modify __pm_runtime_set_status() to take suppliers into account by activating them upfront if the new status is RPM_ACTIVE and deactivating them on exit if the new status is RPM_SUSPENDED. If the activation of one of the suppliers fails, the new status will be RPM_SUSPENDED and the (remaining) suppliers will be deactivated on exit (the child count of the device's parent will be dropped too then). Of course, adding device links locking to __pm_runtime_set_status() means that it cannot be run fron interrupt context, so make it use spin_lock_irq() and spin_unlock_irq() instead of spin_lock_irqsave() and spin_unlock_irqrestore(), respectively. Signed-off-by: Rafael J. Wysocki <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 79a4e91 commit 4080ab0

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

drivers/base/power/runtime.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,20 +1089,43 @@ EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
10891089
* and the device parent's counter of unsuspended children is modified to
10901090
* reflect the new status. If the new status is RPM_SUSPENDED, an idle
10911091
* notification request for the parent is submitted.
1092+
*
1093+
* If @dev has any suppliers (as reflected by device links to them), and @status
1094+
* is RPM_ACTIVE, they will be activated upfront and if the activation of one
1095+
* of them fails, the status of @dev will be changed to RPM_SUSPENDED (instead
1096+
* of the @status value) and the suppliers will be deacticated on exit. The
1097+
* error returned by the failing supplier activation will be returned in that
1098+
* case.
10921099
*/
10931100
int __pm_runtime_set_status(struct device *dev, unsigned int status)
10941101
{
10951102
struct device *parent = dev->parent;
1096-
unsigned long flags;
10971103
bool notify_parent = false;
10981104
int error = 0;
10991105

11001106
if (status != RPM_ACTIVE && status != RPM_SUSPENDED)
11011107
return -EINVAL;
11021108

1103-
spin_lock_irqsave(&dev->power.lock, flags);
1109+
/*
1110+
* If the new status is RPM_ACTIVE, the suppliers can be activated
1111+
* upfront regardless of the current status, because next time
1112+
* rpm_put_suppliers() runs, the rpm_active refcounts of the links
1113+
* involved will be dropped down to one anyway.
1114+
*/
1115+
if (status == RPM_ACTIVE) {
1116+
int idx = device_links_read_lock();
1117+
1118+
error = rpm_get_suppliers(dev);
1119+
if (error)
1120+
status = RPM_SUSPENDED;
1121+
1122+
device_links_read_unlock(idx);
1123+
}
1124+
1125+
spin_lock_irq(&dev->power.lock);
11041126

11051127
if (!dev->power.runtime_error && !dev->power.disable_depth) {
1128+
status = dev->power.runtime_status;
11061129
error = -EAGAIN;
11071130
goto out;
11081131
}
@@ -1134,19 +1157,31 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
11341157

11351158
spin_unlock(&parent->power.lock);
11361159

1137-
if (error)
1160+
if (error) {
1161+
status = RPM_SUSPENDED;
11381162
goto out;
1163+
}
11391164
}
11401165

11411166
out_set:
11421167
__update_runtime_status(dev, status);
1143-
dev->power.runtime_error = 0;
1168+
if (!error)
1169+
dev->power.runtime_error = 0;
1170+
11441171
out:
1145-
spin_unlock_irqrestore(&dev->power.lock, flags);
1172+
spin_unlock_irq(&dev->power.lock);
11461173

11471174
if (notify_parent)
11481175
pm_request_idle(parent);
11491176

1177+
if (status == RPM_SUSPENDED) {
1178+
int idx = device_links_read_lock();
1179+
1180+
rpm_put_suppliers(dev);
1181+
1182+
device_links_read_unlock(idx);
1183+
}
1184+
11501185
return error;
11511186
}
11521187
EXPORT_SYMBOL_GPL(__pm_runtime_set_status);

0 commit comments

Comments
 (0)