summaryrefslogtreecommitdiff
path: root/drivers/base/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2b0a1054535c..93c2fc58013e 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -180,11 +180,20 @@ struct device_link *device_link_add(struct device *consumer,
struct device *supplier, u32 flags)
{
struct device_link *link;
+ bool rpm_put_supplier = false;
if (!consumer || !supplier ||
((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE)))
return NULL;
+ if (flags & DL_FLAG_PM_RUNTIME && flags & DL_FLAG_RPM_ACTIVE) {
+ if (pm_runtime_get_sync(supplier) < 0) {
+ pm_runtime_put_noidle(supplier);
+ return NULL;
+ }
+ rpm_put_supplier = true;
+ }
+
device_links_write_lock();
device_pm_lock();
@@ -209,13 +218,8 @@ struct device_link *device_link_add(struct device *consumer,
if (flags & DL_FLAG_PM_RUNTIME) {
if (flags & DL_FLAG_RPM_ACTIVE) {
- if (pm_runtime_get_sync(supplier) < 0) {
- pm_runtime_put_noidle(supplier);
- kfree(link);
- link = NULL;
- goto out;
- }
link->rpm_active = true;
+ rpm_put_supplier = false;
}
pm_runtime_new_link(consumer);
/*
@@ -286,6 +290,10 @@ struct device_link *device_link_add(struct device *consumer,
out:
device_pm_unlock();
device_links_write_unlock();
+
+ if (rpm_put_supplier)
+ pm_runtime_put(supplier);
+
return link;
}
EXPORT_SYMBOL_GPL(device_link_add);