Skip to content

Commit edccfd1

Browse files
committed
PM: sleep: Make async suspend handle suppliers like parents
JIRA: https://issues.redhat.com/browse/RHEL-109251 commit 0679963 Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Date: Thu, 03 Jul 2025 16:53:33 +0000 Avoid starting "async" suspend processing upfront for devices that have consumers and start "async" suspend processing for a device's suppliers right after suspending the device itself. Suggested-by: Saravana Kannan <saravanak@google.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Sudeep Holla <sudeep.holla@arm.com> Link: https://patch.msgid.link/3384525.44csPzL39Z@rjwysocki.net Signed-off-by: Mark Langsdorf <mlangsdo@redhat.com>
1 parent 2c2ca02 commit edccfd1

File tree

1 file changed

+31
-6
lines changed

1 file changed

+31
-6
lines changed

drivers/base/power/main.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,10 +1289,15 @@ static bool dpm_leaf_device(struct device *dev)
12891289
return false;
12901290
}
12911291

1292-
return true;
1292+
/*
1293+
* Since this function is required to run under dpm_list_mtx, the
1294+
* list_empty() below will only return true if the device's list of
1295+
* consumers is actually empty before calling it.
1296+
*/
1297+
return list_empty(&dev->links.consumers);
12931298
}
12941299

1295-
static void dpm_async_suspend_parent(struct device *dev, async_func_t func)
1300+
static bool dpm_async_suspend_parent(struct device *dev, async_func_t func)
12961301
{
12971302
guard(mutex)(&dpm_list_mtx);
12981303

@@ -1304,11 +1309,31 @@ static void dpm_async_suspend_parent(struct device *dev, async_func_t func)
13041309
* deleted before it.
13051310
*/
13061311
if (!device_pm_initialized(dev))
1307-
return;
1312+
return false;
13081313

13091314
/* Start processing the device's parent if it is "async". */
13101315
if (dev->parent)
13111316
dpm_async_with_cleanup(dev->parent, func);
1317+
1318+
return true;
1319+
}
1320+
1321+
static void dpm_async_suspend_superior(struct device *dev, async_func_t func)
1322+
{
1323+
struct device_link *link;
1324+
int idx;
1325+
1326+
if (!dpm_async_suspend_parent(dev, func))
1327+
return;
1328+
1329+
idx = device_links_read_lock();
1330+
1331+
/* Start processing the device's "async" suppliers. */
1332+
list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
1333+
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
1334+
dpm_async_with_cleanup(link->supplier, func);
1335+
1336+
device_links_read_unlock(idx);
13121337
}
13131338

13141339
/**
@@ -1432,7 +1457,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
14321457
if (error || async_error)
14331458
return error;
14341459

1435-
dpm_async_suspend_parent(dev, async_suspend_noirq);
1460+
dpm_async_suspend_superior(dev, async_suspend_noirq);
14361461

14371462
return 0;
14381463
}
@@ -1628,7 +1653,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
16281653
if (error || async_error)
16291654
return error;
16301655

1631-
dpm_async_suspend_parent(dev, async_suspend_late);
1656+
dpm_async_suspend_superior(dev, async_suspend_late);
16321657

16331658
return 0;
16341659
}
@@ -1919,7 +1944,7 @@ static int device_suspend(struct device *dev, pm_message_t state, bool async)
19191944
if (error || async_error)
19201945
return error;
19211946

1922-
dpm_async_suspend_parent(dev, async_suspend);
1947+
dpm_async_suspend_superior(dev, async_suspend);
19231948

19241949
return 0;
19251950
}

0 commit comments

Comments
 (0)