@@ -1308,6 +1308,8 @@ static void dpm_superior_set_must_resume(struct device *dev)
13081308 device_links_read_unlock (idx );
13091309}
13101310
1311+ static void async_suspend_noirq (void * data , async_cookie_t cookie );
1312+
13111313/**
13121314 * device_suspend_noirq - Execute a "noirq suspend" callback for given device.
13131315 * @dev: Device to handle.
@@ -1386,7 +1388,13 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
13861388Complete :
13871389 complete_all (& dev -> power .completion );
13881390 TRACE_SUSPEND (error );
1389- return error ;
1391+
1392+ if (error || async_error )
1393+ return error ;
1394+
1395+ dpm_async_suspend_parent (dev , async_suspend_noirq );
1396+
1397+ return 0 ;
13901398}
13911399
13921400static void async_suspend_noirq (void * data , async_cookie_t cookie )
@@ -1400,6 +1408,7 @@ static void async_suspend_noirq(void *data, async_cookie_t cookie)
14001408static int dpm_noirq_suspend_devices (pm_message_t state )
14011409{
14021410 ktime_t starttime = ktime_get ();
1411+ struct device * dev ;
14031412 int error = 0 ;
14041413
14051414 trace_suspend_resume (TPS ("dpm_suspend_noirq" ), state .event , true);
@@ -1409,12 +1418,21 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
14091418
14101419 mutex_lock (& dpm_list_mtx );
14111420
1421+ /*
1422+ * Start processing "async" leaf devices upfront so they don't need to
1423+ * wait for the "sync" devices they don't depend on.
1424+ */
1425+ list_for_each_entry_reverse (dev , & dpm_late_early_list , power .entry ) {
1426+ dpm_clear_async_state (dev );
1427+ if (dpm_leaf_device (dev ))
1428+ dpm_async_with_cleanup (dev , async_suspend_noirq );
1429+ }
1430+
14121431 while (!list_empty (& dpm_late_early_list )) {
1413- struct device * dev = to_device (dpm_late_early_list .prev );
1432+ dev = to_device (dpm_late_early_list .prev );
14141433
14151434 list_move (& dev -> power .entry , & dpm_noirq_list );
14161435
1417- dpm_clear_async_state (dev );
14181436 if (dpm_async_fn (dev , async_suspend_noirq ))
14191437 continue ;
14201438
@@ -1428,8 +1446,14 @@ static int dpm_noirq_suspend_devices(pm_message_t state)
14281446
14291447 mutex_lock (& dpm_list_mtx );
14301448
1431- if (error || async_error )
1449+ if (error || async_error ) {
1450+ /*
1451+ * Move all devices to the target list to resume them
1452+ * properly.
1453+ */
1454+ list_splice (& dpm_late_early_list , & dpm_noirq_list );
14321455 break ;
1456+ }
14331457 }
14341458
14351459 mutex_unlock (& dpm_list_mtx );
@@ -1482,6 +1506,8 @@ static void dpm_propagate_wakeup_to_parent(struct device *dev)
14821506 spin_unlock_irq (& parent -> power .lock );
14831507}
14841508
1509+ static void async_suspend_late (void * data , async_cookie_t cookie );
1510+
14851511/**
14861512 * device_suspend_late - Execute a "late suspend" callback for given device.
14871513 * @dev: Device to handle.
@@ -1558,7 +1584,13 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
15581584Complete :
15591585 TRACE_SUSPEND (error );
15601586 complete_all (& dev -> power .completion );
1561- return error ;
1587+
1588+ if (error || async_error )
1589+ return error ;
1590+
1591+ dpm_async_suspend_parent (dev , async_suspend_late );
1592+
1593+ return 0 ;
15621594}
15631595
15641596static void async_suspend_late (void * data , async_cookie_t cookie )
@@ -1576,6 +1608,7 @@ static void async_suspend_late(void *data, async_cookie_t cookie)
15761608int dpm_suspend_late (pm_message_t state )
15771609{
15781610 ktime_t starttime = ktime_get ();
1611+ struct device * dev ;
15791612 int error = 0 ;
15801613
15811614 trace_suspend_resume (TPS ("dpm_suspend_late" ), state .event , true);
@@ -1587,12 +1620,21 @@ int dpm_suspend_late(pm_message_t state)
15871620
15881621 mutex_lock (& dpm_list_mtx );
15891622
1623+ /*
1624+ * Start processing "async" leaf devices upfront so they don't need to
1625+ * wait for the "sync" devices they don't depend on.
1626+ */
1627+ list_for_each_entry_reverse (dev , & dpm_suspended_list , power .entry ) {
1628+ dpm_clear_async_state (dev );
1629+ if (dpm_leaf_device (dev ))
1630+ dpm_async_with_cleanup (dev , async_suspend_late );
1631+ }
1632+
15901633 while (!list_empty (& dpm_suspended_list )) {
1591- struct device * dev = to_device (dpm_suspended_list .prev );
1634+ dev = to_device (dpm_suspended_list .prev );
15921635
15931636 list_move (& dev -> power .entry , & dpm_late_early_list );
15941637
1595- dpm_clear_async_state (dev );
15961638 if (dpm_async_fn (dev , async_suspend_late ))
15971639 continue ;
15981640
@@ -1606,8 +1648,14 @@ int dpm_suspend_late(pm_message_t state)
16061648
16071649 mutex_lock (& dpm_list_mtx );
16081650
1609- if (error || async_error )
1651+ if (error || async_error ) {
1652+ /*
1653+ * Move all devices to the target list to resume them
1654+ * properly.
1655+ */
1656+ list_splice (& dpm_suspended_list , & dpm_late_early_list );
16101657 break ;
1658+ }
16111659 }
16121660
16131661 mutex_unlock (& dpm_list_mtx );
0 commit comments