Skip to content

Commit cb88c22

Browse files
committed
PM: sleep: Update power.smart_suspend under PM spinlock
Put the update of the power.smart_suspend device flag under the PM spinlock of the device in case multiple bit fields in struct dev_pm_info occupy one memory location which needs to be updated via RMW every time any of these bit fields is updated. The lock in question is already held around the power.direct_complete flag update in device_prepare() for the same reason, so this change does not add locking-related overhead to the code. Signed-off-by: Rafael J. Wysocki <[email protected]> Reviewed-by: Ulf Hansson <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent eeb87d1 commit cb88c22

File tree

1 file changed

+19
-16
lines changed

1 file changed

+19
-16
lines changed

drivers/base/power/main.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,9 +1795,10 @@ int dpm_suspend(pm_message_t state)
17951795
return error;
17961796
}
17971797

1798-
static void device_prepare_smart_suspend(struct device *dev)
1798+
static bool device_prepare_smart_suspend(struct device *dev)
17991799
{
18001800
struct device_link *link;
1801+
bool ret = true;
18011802
int idx;
18021803

18031804
/*
@@ -1808,17 +1809,13 @@ static void device_prepare_smart_suspend(struct device *dev)
18081809
* or any of its suppliers that take runtime PM into account, it cannot
18091810
* be enabled for the device either.
18101811
*/
1811-
dev->power.smart_suspend = dev->power.no_pm_callbacks ||
1812-
dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND);
1813-
1814-
if (!dev_pm_smart_suspend(dev))
1815-
return;
1812+
if (!dev->power.no_pm_callbacks &&
1813+
!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
1814+
return false;
18161815

18171816
if (dev->parent && !dev_pm_smart_suspend(dev->parent) &&
1818-
!dev->parent->power.ignore_children && !pm_runtime_blocked(dev->parent)) {
1819-
dev->power.smart_suspend = false;
1820-
return;
1821-
}
1817+
!dev->parent->power.ignore_children && !pm_runtime_blocked(dev->parent))
1818+
return false;
18221819

18231820
idx = device_links_read_lock();
18241821

@@ -1828,12 +1825,14 @@ static void device_prepare_smart_suspend(struct device *dev)
18281825

18291826
if (!dev_pm_smart_suspend(link->supplier) &&
18301827
!pm_runtime_blocked(link->supplier)) {
1831-
dev->power.smart_suspend = false;
1828+
ret = false;
18321829
break;
18331830
}
18341831
}
18351832

18361833
device_links_read_unlock(idx);
1834+
1835+
return ret;
18371836
}
18381837

18391838
/**
@@ -1847,7 +1846,7 @@ static void device_prepare_smart_suspend(struct device *dev)
18471846
static int device_prepare(struct device *dev, pm_message_t state)
18481847
{
18491848
int (*callback)(struct device *) = NULL;
1850-
bool no_runtime_pm;
1849+
bool smart_suspend;
18511850
int ret = 0;
18521851

18531852
/*
@@ -1863,7 +1862,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
18631862
* suspend-resume cycle is complete, so prepare to trigger a warning on
18641863
* subsequent attempts to enable it.
18651864
*/
1866-
no_runtime_pm = pm_runtime_block_if_disabled(dev);
1865+
smart_suspend = !pm_runtime_block_if_disabled(dev);
18671866

18681867
if (dev->power.syscore)
18691868
return 0;
@@ -1899,21 +1898,25 @@ static int device_prepare(struct device *dev, pm_message_t state)
18991898
return ret;
19001899
}
19011900
/* Do not enable "smart suspend" for devices without runtime PM. */
1902-
if (!no_runtime_pm)
1903-
device_prepare_smart_suspend(dev);
1901+
if (smart_suspend)
1902+
smart_suspend = device_prepare_smart_suspend(dev);
1903+
1904+
spin_lock_irq(&dev->power.lock);
19041905

1906+
dev->power.smart_suspend = smart_suspend;
19051907
/*
19061908
* A positive return value from ->prepare() means "this device appears
19071909
* to be runtime-suspended and its state is fine, so if it really is
19081910
* runtime-suspended, you can leave it in that state provided that you
19091911
* will do the same thing with all of its descendants". This only
19101912
* applies to suspend transitions, however.
19111913
*/
1912-
spin_lock_irq(&dev->power.lock);
19131914
dev->power.direct_complete = state.event == PM_EVENT_SUSPEND &&
19141915
(ret > 0 || dev->power.no_pm_callbacks) &&
19151916
!dev_pm_test_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE);
1917+
19161918
spin_unlock_irq(&dev->power.lock);
1919+
19171920
return 0;
19181921
}
19191922

0 commit comments

Comments
 (0)