[PATCH v5 24/25] soundwire: amd: fix shared-register RMW race in amd_sdw_set_device_state()

From: Vijendar Mukunda

Date: Sat Nov 07 2026 - 11:04:48 EST


AMD_SDW_DEVICE_STATE packs the D0/D3 state for SDW0 (bits [1:0]) and
SDW1 (bits [3:2]) in a single ACP-level register.
amd_sdw_set_device_state() performed a read-modify-write sequence on
this shared register without holding acp_sdw_lock, leaving it open to
a lost-update race when SDW0 and SDW1 execute concurrent PM transitions.

Acquire acp_sdw_lock around the read-modify-write sequence. Unlock
before returning -EINVAL from the default branch so the mutex is always
released on every exit path.

Fixes: 829c3e1cb4a3 ("soundwire: amd: set device power state during suspend/resume sequence")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@xxxxxxx>
---
drivers/soundwire/amd_manager.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 4e151f7350c9..495f0607bb0b 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -279,6 +279,7 @@ static int amd_sdw_set_device_state(struct amd_sdw_manager *amd_manager, u32 tar
{
u32 sdw_dev_state;

+ mutex_lock(amd_manager->acp_sdw_lock);
sdw_dev_state = readl(amd_manager->acp_mmio + AMD_SDW_DEVICE_STATE);
switch (amd_manager->instance) {
case ACP_SDW0:
@@ -290,10 +291,12 @@ static int amd_sdw_set_device_state(struct amd_sdw_manager *amd_manager, u32 tar
AMD_SDW1_DEVICE_STATE_MASK);
break;
default:
+ mutex_unlock(amd_manager->acp_sdw_lock);
return -EINVAL;
}
writel(sdw_dev_state, amd_manager->acp_mmio + AMD_SDW_DEVICE_STATE);
sdw_dev_state = readl(amd_manager->acp_mmio + AMD_SDW_DEVICE_STATE);
+ mutex_unlock(amd_manager->acp_sdw_lock);
dev_dbg(amd_manager->dev, "AMD_SDW_DEVICE_STATE:0x%x\n", sdw_dev_state);
return 0;
}
--
2.53.0