* [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes
@ 2026-10-13 8:49 Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 01/10] soundwire: amd: fix SDW command timeout return value handling Vijendar Mukunda
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
This series collects bug fixes for the AMD SoundWire manager
driver (ACP6.3/7.0/7.1/7.2). The patches address correctness issues
in command response handling, slave status caching, work-queue teardown
ordering, resource cleanup on probe failure, power-management
suspend/resume sequences, and IRQ thread status handling.
Changes since v2:
- Add patch 10/10 to fix the IRQ thread dropping STATUS_0TO7 when a
device-state change and a wake event arrive simultaneously, which
caused slave ATTACHED events to be lost during concurrent manager
wake/re-attach.
Changes since v1:
- Update comment for ping_slave_stat variable description in patch 2/9.
- split the remove path work drain and pm ops guard patch into separate
patches (patches 3/9 and 4/9) to improve clarity and maintainability.
Vijendar Mukunda (10):
soundwire: amd: fix SDW command timeout return value handling
soundwire: amd: cache ping slave status to avoid spurious disconnect
on timeout
soundwire: amd: fix work drain ordering in remove path
soundwire: amd: pm_runtime guard in remove path
soundwire: amd: fix ctx leak when sdw_amd_startup() fails
soundwire: amd: propagate amd_init_sdw_manager() error on resume
soundwire: amd: drop amd_deinit_sdw_manager() in POWER_OFF suspend
soundwire: amd: replace >= ACP70 with explicit switch/case in PM paths
soundwire: amd: fix interrupt gate and work drain ordering in PM ops
soundwire: amd: fix IRQ thread dropping STATUS_0TO7 on simultaneous
wake
drivers/soundwire/amd_init.c | 9 +-
drivers/soundwire/amd_manager.c | 212 ++++++++++++++++++++----------
include/linux/soundwire/sdw_amd.h | 4 +
3 files changed, 154 insertions(+), 71 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 01/10] soundwire: amd: fix SDW command timeout return value handling
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 02/10] soundwire: amd: cache ping slave status to avoid spurious disconnect on timeout Vijendar Mukunda
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
amd_sdw_send_cmd_get_resp() returned u64 but was returning -ETIMEDOUT
(a negative int) on readl_poll_timeout() failures, which silently
widens to a large u64 value.
Change the return type to int and pass the raw u64 response through an
out-parameter. Timeout is detected directly from readl_poll_timeout()
return value.
Update all callers: amd_program_scp_addr(), _amd_sdw_xfer_msg(),
amd_sdw_read_and_process_ping_status(), and amd_sdw_read_ping_status()
to check the return value and handle timeout explicitly. In
amd_sdw_read_and_process_ping_status(), the mutex unlock is also moved
to after amd_sdw_process_ping_status() so the lock is held across the
full status processing step.
Fixes: d8f48fbdfd9a ("soundwire: amd: Add support for AMD Manager driver")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 56 +++++++++++++++++++--------------
1 file changed, 33 insertions(+), 23 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index a3316efdf8ac..fa3f4e797edd 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -250,10 +250,9 @@ static void amd_sdw_ctl_word_prep(u32 *lower_word, u32 *upper_word, struct sdw_m
*lower_word = lower_data;
}
-static u64 amd_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lower_data,
- u32 upper_data)
+static int amd_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lower_data,
+ u32 upper_data, u64 *response)
{
- u64 resp;
u32 lower_resp, upper_resp;
u32 sts;
int ret;
@@ -291,9 +290,8 @@ static u64 amd_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lo
amd_manager->instance);
return ret;
}
- resp = upper_resp;
- resp = (resp << 32) | lower_resp;
- return resp;
+ *response = ((u64)upper_resp << 32) | lower_resp;
+ return 0;
}
static enum sdw_command_response
@@ -309,19 +307,22 @@ amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
scp_msg.buf = &msg->addr_page1;
scp_msg.flags = SDW_MSG_FLAG_WRITE;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
- response_buf[0] = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data);
+ if (amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response_buf[0])) {
+ dev_err_ratelimited(amd_manager->dev,
+ "SCP_addrpage command timeout for Slave %d\n", msg->dev_num);
+ return SDW_CMD_TIMEOUT;
+ }
scp_msg.addr = SDW_SCP_ADDRPAGE2;
scp_msg.buf = &msg->addr_page2;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
- response_buf[1] = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data);
+ if (amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response_buf[1])) {
+ dev_err_ratelimited(amd_manager->dev,
+ "SCP_addrpage command timeout for Slave %d\n", msg->dev_num);
+ return SDW_CMD_TIMEOUT;
+ }
for (index = 0; index < 2; index++) {
- if (response_buf[index] == -ETIMEDOUT) {
- dev_err_ratelimited(amd_manager->dev,
- "SCP_addrpage command timeout for Slave %d\n",
- msg->dev_num);
- return SDW_CMD_TIMEOUT;
- } else if (!(response_buf[index] & AMD_SDW_MCP_RESP_ACK)) {
+ if (!(response_buf[index] & AMD_SDW_MCP_RESP_ACK)) {
if (response_buf[index] & AMD_SDW_MCP_RESP_NACK) {
dev_err_ratelimited(amd_manager->dev,
"SCP_addrpage NACKed for Slave %d\n",
@@ -366,11 +367,7 @@ static enum sdw_command_response amd_sdw_fill_msg_resp(struct amd_sdw_manager *a
if (msg->flags == SDW_MSG_FLAG_READ)
msg->buf[offset] = FIELD_GET(AMD_SDW_MCP_RESP_RDATA, response);
} else {
- if (response == -ETIMEDOUT) {
- dev_err_ratelimited(amd_manager->dev, "command timeout for Slave %d\n",
- msg->dev_num);
- return SDW_CMD_TIMEOUT;
- } else if (response & AMD_SDW_MCP_RESP_NACK) {
+ if (response & AMD_SDW_MCP_RESP_NACK) {
dev_err_ratelimited(amd_manager->dev,
"command response NACK received for Slave %d\n",
msg->dev_num);
@@ -390,7 +387,11 @@ static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struc
u32 upper_data = 0, lower_data = 0;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, msg, cmd_offset);
- response = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data);
+ if (amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response)) {
+ dev_err_ratelimited(amd_manager->dev, "command timeout for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_TIMEOUT;
+ }
return amd_sdw_fill_msg_resp(amd_manager, msg, response, cmd_offset);
}
@@ -446,9 +447,14 @@ static void amd_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_man
u64 response;
mutex_lock(&amd_manager->bus.msg_lock);
- response = amd_sdw_send_cmd_get_resp(amd_manager, 0, 0);
- mutex_unlock(&amd_manager->bus.msg_lock);
+ if (amd_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
+ mutex_unlock(&amd_manager->bus.msg_lock);
+ dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
+ amd_manager->instance);
+ return;
+ }
amd_sdw_process_ping_status(response, amd_manager);
+ mutex_unlock(&amd_manager->bus.msg_lock);
}
static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
@@ -457,7 +463,11 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
u64 response;
u32 slave_stat;
- response = amd_sdw_send_cmd_get_resp(amd_manager, 0, 0);
+ if (amd_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
+ dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
+ amd_manager->instance);
+ return 0;
+ }
/* slave status from ping response */
slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response);
slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8;
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 02/10] soundwire: amd: cache ping slave status to avoid spurious disconnect on timeout
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 01/10] soundwire: amd: fix SDW command timeout return value handling Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 03/10] soundwire: amd: fix work drain ordering in remove path Vijendar Mukunda
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Add ping_slave_stat to struct amd_sdw_manager to cache the slave_stat
from the last successful ping response. On timeout,
amd_sdw_read_ping_status() returns the cached value (or 0 if no
successful response yet) to avoid the spurious "no peripherals
attached" warning from sdw_show_ping_status().
ping_slave_stat is initialised to U32_MAX in probe and reset to
U32_MAX under msg_lock on entry to the POWER_OFF_MODE resume path,
before any hardware step that can fail and return early, so that a
partially-failed resume cannot leave a stale pre-suspend value behind
for a subsequent ping timeout to report.
Add lockdep_assert_held() in amd_sdw_read_ping_status() to document
that the caller must hold msg_lock.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 21 ++++++++++++++++++++-
include/linux/soundwire/sdw_amd.h | 4 ++++
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index fa3f4e797edd..a57b59609bfe 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -453,6 +453,9 @@ static void amd_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_man
amd_manager->instance);
return;
}
+ amd_manager->ping_slave_stat =
+ FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response) |
+ (FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8);
amd_sdw_process_ping_status(response, amd_manager);
mutex_unlock(&amd_manager->bus.msg_lock);
}
@@ -463,15 +466,19 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
u64 response;
u32 slave_stat;
+ /* Called by sdw_show_ping_status() which holds msg_lock. */
+ lockdep_assert_held(&bus->msg_lock);
+
if (amd_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
amd_manager->instance);
- return 0;
+ return amd_manager->ping_slave_stat == U32_MAX ? 0 : amd_manager->ping_slave_stat;
}
/* slave status from ping response */
slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response);
slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8;
dev_dbg(amd_manager->dev, "slave_stat:0x%x\n", slave_stat);
+ amd_manager->ping_slave_stat = slave_stat;
return slave_stat;
}
@@ -1087,6 +1094,7 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
dev_err(dev, "mmio not found\n");
return -ENOMEM;
}
+ amd_manager->ping_slave_stat = U32_MAX;
amd_manager->instance = pdata->instance;
amd_manager->mmio = amd_manager->acp_mmio +
(amd_manager->instance * SDW_MANAGER_REG_OFFSET);
@@ -1414,6 +1422,17 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
}
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
writel(0x00, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
+ /*
+ * POWER_OFF_MODE tears the bus down completely; invalidate the
+ * cached ping status on entry, before any step that can fail and
+ * return early, so that a partially-failed resume leaves the first
+ * post-resume ping timeout returning 0 rather than stale
+ * pre-suspend data. CLK_STOP_MODE leaves peripherals attached, so
+ * the cache remains valid there.
+ */
+ mutex_lock(&amd_manager->bus.msg_lock);
+ amd_manager->ping_slave_stat = U32_MAX;
+ mutex_unlock(&amd_manager->bus.msg_lock);
if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
ret = amd_sdw_host_wake_enable(amd_manager, false);
if (ret)
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
index 470360a2723c..d0e97007e3ff 100644
--- a/include/linux/soundwire/sdw_amd.h
+++ b/include/linux/soundwire/sdw_amd.h
@@ -76,6 +76,9 @@ struct sdw_amd_dai_runtime {
* @acp_rev: acp pci device revision id
* @clk_stopped: flag set to true when clock is stopped
* @power_mode_mask: flag interprets amd SoundWire manager power mode
+ * @ping_slave_stat: cached slave status from the last ping
+ * transaction that returned a response;
+ * initialised to U32_MAX ("no valid reading yet")
* @dai_runtime_array: dai runtime array
*/
struct amd_sdw_manager {
@@ -105,6 +108,7 @@ struct amd_sdw_manager {
u32 wake_en_mask;
u32 power_mode_mask;
u32 acp_rev;
+ u32 ping_slave_stat;
bool clk_stopped;
struct sdw_amd_dai_runtime **dai_runtime_array;
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 03/10] soundwire: amd: fix work drain ordering in remove path
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 01/10] soundwire: amd: fix SDW command timeout return value handling Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 02/10] soundwire: amd: cache ping slave status to avoid spurious disconnect on timeout Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 04/10] soundwire: amd: pm_runtime guard " Vijendar Mukunda
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
amd_sdw_manager_remove() cancelled amd_sdw_work but not
amd_sdw_irq_thread. Since amd_sdw_irq_thread() calls
schedule_work(&amd_sdw_work), an in-flight irq_thread item can
re-queue amd_sdw_work after its cancel returns, defeating the
cancellation.
Fix by calling amd_disable_sdw_interrupts() first to quiesce the
hardware IRQ source, then cancel_work_sync() for amd_sdw_irq_thread,
then cancel_work_sync() for amd_sdw_work. The existing
cancel_work_sync(amd_sdw_work) is also moved to after
amd_disable_sdw_interrupts() so that any work item queued between the
old cancel position and the interrupt disable cannot escape draining.
synchronize_irq() is deliberately not used before the
cancel_work_sync() calls. Once SoundWire interrupts are masked, no new
IRQ deliveries can occur. An IRQ handler already in flight may still
queue amd_sdw_irq_thread, so cancel_work_sync() is used to drain both
amd_sdw_irq_thread and any amd_sdw_work items it may have scheduled.
This fully quiesces the driver workqueues, making synchronize_irq()
unnecessary.
Fixes: f93b697ed98e ("soundwire: amd: cancel pending slave status handling workqueue during remove sequence")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index a57b59609bfe..dfbe9a181983 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1173,8 +1173,9 @@ static void amd_sdw_manager_remove(struct platform_device *pdev)
int ret;
pm_runtime_disable(&pdev->dev);
- cancel_work_sync(&amd_manager->amd_sdw_work);
amd_disable_sdw_interrupts(amd_manager);
+ cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
+ cancel_work_sync(&amd_manager->amd_sdw_work);
sdw_bus_master_delete(&amd_manager->bus);
ret = amd_disable_sdw_manager(amd_manager);
if (ret)
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 04/10] soundwire: amd: pm_runtime guard in remove path
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (2 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 03/10] soundwire: amd: fix work drain ordering in remove path Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 05/10] soundwire: amd: fix ctx leak when sdw_amd_startup() fails Vijendar Mukunda
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Guard pm_runtime_disable() so it is only called when runtime PM
was actually enabled. amd_sdw_manager_start() calls pm_runtime_enable()
only at the very end, after several fallible hardware init steps. If
sdw_amd_startup() fails mid-loop (one manager started, the next fails
before pm_runtime_enable()), sdw_amd_exit() triggers
platform_device_unregister() for all managers. Calling
pm_runtime_disable() on the partially-started manager finds
disable_depth already at its initial value of 1, silently increments it
to 2 and returns without a warning, so a later pm_runtime_enable() would
only bring it back to 1 and leave runtime PM disabled. Use
pm_runtime_enabled() to skip the call when it was never paired with an
enable.
Fixes: f93b697ed98e ("soundwire: amd: cancel pending slave status handling workqueue during remove sequence")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index dfbe9a181983..bbe1e73ed255 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1172,7 +1172,8 @@ static void amd_sdw_manager_remove(struct platform_device *pdev)
struct amd_sdw_manager *amd_manager = dev_get_drvdata(&pdev->dev);
int ret;
- pm_runtime_disable(&pdev->dev);
+ if (pm_runtime_enabled(&pdev->dev))
+ pm_runtime_disable(&pdev->dev);
amd_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 05/10] soundwire: amd: fix ctx leak when sdw_amd_startup() fails
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (3 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 04/10] soundwire: amd: pm_runtime guard " Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 06/10] soundwire: amd: propagate amd_init_sdw_manager() error on resume Vijendar Mukunda
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
sdw_amd_probe() allocates a context and registers platform devices via
sdw_amd_probe_controller(), then calls sdw_amd_startup() to start each
manager. If sdw_amd_startup() fails, the error was returned directly,
leaving *sdw_ctx non-NULL with the allocated context and its registered
platform devices leaked.
Call sdw_amd_exit() on the failure path to unregister the platform
devices and free ctx, then clear *sdw_ctx so callers observe a
consistent NULL on error.
Fixes: ed5e8741b8db ("soundwire: amd: refactor amd soundwire manager device node creation")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_init.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c
index 8e419ddfa516..88004d59322e 100644
--- a/drivers/soundwire/amd_init.c
+++ b/drivers/soundwire/amd_init.c
@@ -166,11 +166,18 @@ static int sdw_amd_startup(struct sdw_amd_ctx *ctx)
int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx)
{
+ int ret;
+
*sdw_ctx = sdw_amd_probe_controller(res);
if (!*sdw_ctx)
return -ENODEV;
- return sdw_amd_startup(*sdw_ctx);
+ ret = sdw_amd_startup(*sdw_ctx);
+ if (ret) {
+ sdw_amd_exit(*sdw_ctx);
+ *sdw_ctx = NULL;
+ }
+ return ret;
}
EXPORT_SYMBOL_NS(sdw_amd_probe, "SOUNDWIRE_AMD_INIT");
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 06/10] soundwire: amd: propagate amd_init_sdw_manager() error on resume
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (4 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 05/10] soundwire: amd: fix ctx leak when sdw_amd_startup() fails Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 07/10] soundwire: amd: drop amd_deinit_sdw_manager() in POWER_OFF suspend Vijendar Mukunda
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
In amd_resume_runtime() POWER_OFF_MODE, amd_init_sdw_manager() was
called without capturing its return value. The function performs
hardware bus resets using readl_poll_timeout() and can return
-ETIMEDOUT if the hardware does not respond. When that happens,
execution fell through to amd_enable_sdw_interrupts() and
amd_enable_sdw_manager() on hardware that may still be in a broken
reset state.
Fix by capturing the return value and returning early on failure.
Fixes: 81ff58ff71ad ("soundwire: amd: add runtime pm ops for AMD SoundWire manager driver")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index bbe1e73ed255..2d2f628230ee 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1456,7 +1456,9 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
ret = amd_sdw_clk_init_ctrl(amd_manager);
if (ret)
return ret;
- amd_init_sdw_manager(amd_manager);
+ ret = amd_init_sdw_manager(amd_manager);
+ if (ret)
+ return ret;
amd_enable_sdw_interrupts(amd_manager);
ret = amd_enable_sdw_manager(amd_manager);
if (ret)
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 07/10] soundwire: amd: drop amd_deinit_sdw_manager() in POWER_OFF suspend
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (5 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 06/10] soundwire: amd: propagate amd_init_sdw_manager() error on resume Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 08/10] soundwire: amd: replace >= ACP70 with explicit switch/case in PM paths Vijendar Mukunda
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
amd_deinit_sdw_manager() was a small helper that bundled
amd_disable_sdw_interrupts() and amd_disable_sdw_manager() together.
Expand the two POWER_OFF_MODE call sites in amd_suspend() and
amd_suspend_runtime() to call those two functions directly, then remove
the helper. No functional change.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 2d2f628230ee..6af224ca54a3 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -146,12 +146,6 @@ static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
writel(0x00, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
}
-static int amd_deinit_sdw_manager(struct amd_sdw_manager *amd_manager)
-{
- amd_disable_sdw_interrupts(amd_manager);
- return amd_disable_sdw_manager(amd_manager);
-}
-
static void amd_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
{
u32 frame_size;
@@ -1336,7 +1330,8 @@ static int __maybe_unused amd_suspend(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- ret = amd_deinit_sdw_manager(amd_manager);
+ amd_disable_sdw_interrupts(amd_manager);
+ ret = amd_disable_sdw_manager(amd_manager);
if (ret)
return ret;
}
@@ -1380,7 +1375,8 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- ret = amd_deinit_sdw_manager(amd_manager);
+ amd_disable_sdw_interrupts(amd_manager);
+ ret = amd_disable_sdw_manager(amd_manager);
if (ret)
return ret;
}
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 08/10] soundwire: amd: replace >= ACP70 with explicit switch/case in PM paths
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (6 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 07/10] soundwire: amd: drop amd_deinit_sdw_manager() in POWER_OFF suspend Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 09/10] soundwire: amd: fix interrupt gate and work drain ordering in PM ops Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 10/10] soundwire: amd: fix IRQ thread dropping STATUS_0TO7 on simultaneous wake Vijendar Mukunda
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Replace open-ended acp_rev >= ACP70_PCI_REV_ID comparisons in
amd_suspend(), amd_suspend_runtime(), and amd_resume_runtime() with
explicit per-revision handling enumerating ACP63, ACP70, ACP71, and
ACP72, so that every supported revision is handled explicitly.
The host wake enable step is guarded by acp_rev at six PM call sites.
Factor that repeated block into amd_sdw_host_wake_enable_by_rev() to
avoid duplicating the switch/case at every site. The remaining device
state transitions keep an inline switch/case as one of them carries
additional PME handling.
An unrecognised revision cannot reach these PM callbacks because
amd_sdw_manager_probe() already validates acp_rev with the same switch
and fails registration for anything unknown. The switch default therefore
emits dev_err() and returns -EINVAL to make the unexpected case visible
while keeping the error path consistent across all PM operations.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 97 ++++++++++++++++++++++-----------
1 file changed, 64 insertions(+), 33 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 6af224ca54a3..0cb5f4694e9a 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1292,6 +1292,22 @@ static int __maybe_unused amd_pm_prepare(struct device *dev)
return 0;
}
+static int amd_sdw_host_wake_enable_by_rev(struct amd_sdw_manager *amd_manager, bool enable)
+{
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ break;
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
+ return amd_sdw_host_wake_enable(amd_manager, enable);
+ default:
+ dev_err(amd_manager->dev, "unexpected acp_rev 0x%x\n", amd_manager->acp_rev);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int __maybe_unused amd_suspend(struct device *dev)
{
struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
@@ -1307,22 +1323,18 @@ static int __maybe_unused amd_suspend(struct device *dev)
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
cancel_work_sync(&amd_manager->amd_sdw_work);
amd_sdw_wake_enable(amd_manager, false);
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
- ret = amd_sdw_host_wake_enable(amd_manager, false);
- if (ret)
- return ret;
- }
+ ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
+ if (ret)
+ return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
cancel_work_sync(&amd_manager->amd_sdw_work);
amd_sdw_wake_enable(amd_manager, false);
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
- ret = amd_sdw_host_wake_enable(amd_manager, false);
- if (ret)
- return ret;
- }
+ ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
+ if (ret)
+ return ret;
/*
* As per hardware programming sequence on AMD platforms,
* clock stop should be invoked first before powering-off
@@ -1335,10 +1347,19 @@ static int __maybe_unused amd_suspend(struct device *dev)
if (ret)
return ret;
}
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ break;
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
ret = amd_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
if (ret)
return ret;
+ break;
+ default:
+ dev_err(amd_manager->dev, "unexpected acp_rev 0x%x\n", amd_manager->acp_rev);
+ return -EINVAL;
}
return 0;
}
@@ -1357,21 +1378,17 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
amd_sdw_wake_enable(amd_manager, true);
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
- ret = amd_sdw_host_wake_enable(amd_manager, true);
- if (ret)
- return ret;
- }
+ ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
+ if (ret)
+ return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
amd_sdw_wake_enable(amd_manager, true);
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
- ret = amd_sdw_host_wake_enable(amd_manager, true);
- if (ret)
- return ret;
- }
+ ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
+ if (ret)
+ return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
@@ -1380,7 +1397,12 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
if (ret)
return ret;
}
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ break;
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
ret = amd_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
if (ret)
return ret;
@@ -1392,6 +1414,10 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
dev_dbg(amd_manager->dev, "ACP_PME_EN:0x%x\n", val);
}
}
+ break;
+ default:
+ dev_err(amd_manager->dev, "unexpected acp_rev 0x%x\n", amd_manager->acp_rev);
+ return -EINVAL;
}
return 0;
}
@@ -1413,11 +1439,9 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
ret = amd_sdw_clock_stop_exit(amd_manager);
if (ret)
return ret;
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
- ret = amd_sdw_host_wake_enable(amd_manager, false);
- if (ret)
- return ret;
- }
+ ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
+ if (ret)
+ return ret;
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
writel(0x00, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
/*
@@ -1431,11 +1455,9 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
mutex_lock(&amd_manager->bus.msg_lock);
amd_manager->ping_slave_stat = U32_MAX;
mutex_unlock(&amd_manager->bus.msg_lock);
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
- ret = amd_sdw_host_wake_enable(amd_manager, false);
- if (ret)
- return ret;
- }
+ ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
+ if (ret)
+ return ret;
val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
if (val) {
val |= AMD_SDW_CLK_RESUME_REQ;
@@ -1461,10 +1483,19 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
return ret;
amd_sdw_set_frameshape(amd_manager);
}
- if (amd_manager->acp_rev >= ACP70_PCI_REV_ID) {
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ break;
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
ret = amd_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D0);
if (ret)
return ret;
+ break;
+ default:
+ dev_err(amd_manager->dev, "unexpected acp_rev 0x%x\n", amd_manager->acp_rev);
+ return -EINVAL;
}
return 0;
}
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 09/10] soundwire: amd: fix interrupt gate and work drain ordering in PM ops
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (7 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 08/10] soundwire: amd: replace >= ACP70 with explicit switch/case in PM paths Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 10/10] soundwire: amd: fix IRQ thread dropping STATUS_0TO7 on simultaneous wake Vijendar Mukunda
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
The CLK_STOP_MODE branches in amd_suspend_runtime() and amd_suspend()
did not close the ACP_EXTERNAL_INTR_CNTL delivery gate before draining
amd_sdw_irq_thread and amd_sdw_work. The ACP PCI parent driver interrupt
handler dispatches SoundWire interrupts to the AMD SoundWire stack by
scheduling amd_sdw_irq_thread. Because the gate was open, an ISR already
running when the drains completed could re-queue work after
cancel_work_sync() returned, racing amd_sdw_clock_stop().
Fix both suspend paths by calling amd_disable_sdw_interrupts() first to
close the ACP-level gate before work drains.
In amd_suspend() CLK_STOP_MODE:
- Add amd_disable_sdw_interrupts() and cancel_work_sync(irq_thread)
before the existing cancel_work_sync(work).
- Call amd_enable_sdw_interrupts() after clock stop to reopen the gate.
ACP remains powered in CLK_STOP_MODE (only the SoundWire bus clock is
gated), so the interrupt path must be live to allow wake events to
reach the CPU during system sleep.
In amd_suspend() POWER_OFF_MODE:
- Add amd_disable_sdw_interrupts() and cancel_work_sync(irq_thread)
before the existing cancel_work_sync(work).
- Remove the redundant post-clock-stop amd_disable_sdw_interrupts() call;
the gate is already closed at the top of the branch.
In amd_suspend_runtime() CLK_STOP_MODE:
- Add amd_disable_sdw_interrupts() and cancel_work_sync(irq_thread)
before the existing cancel_work_sync(work).
- Call amd_enable_sdw_interrupts() to reopen the gate. ACP remains
powered in CLK_STOP_MODE (only the SoundWire bus clock is gated), so
the interrupt path must be live to allow wake events to reach the CPU.
In amd_suspend_runtime() POWER_OFF_MODE:
- Add amd_disable_sdw_interrupts() and cancel_work_sync(irq_thread)
before the existing cancel_work_sync(work).
- Remove the redundant post-clock-stop amd_disable_sdw_interrupts() call;
the gate is already closed at the top of the branch.
Fixes: 86a4371b7697 ("soundwire: amd: fix for handling slave alerts after link is down")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 0cb5f4694e9a..1a252a81269a 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1321,6 +1321,8 @@ static int __maybe_unused amd_suspend(struct device *dev)
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
+ amd_disable_sdw_interrupts(amd_manager);
+ cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
amd_sdw_wake_enable(amd_manager, false);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
@@ -1329,7 +1331,10 @@ static int __maybe_unused amd_suspend(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
+ amd_enable_sdw_interrupts(amd_manager);
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
+ amd_disable_sdw_interrupts(amd_manager);
+ cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
amd_sdw_wake_enable(amd_manager, false);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
@@ -1342,7 +1347,6 @@ static int __maybe_unused amd_suspend(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- amd_disable_sdw_interrupts(amd_manager);
ret = amd_disable_sdw_manager(amd_manager);
if (ret)
return ret;
@@ -1377,6 +1381,9 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
return 0;
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
+ amd_disable_sdw_interrupts(amd_manager);
+ cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
+ cancel_work_sync(&amd_manager->amd_sdw_work);
amd_sdw_wake_enable(amd_manager, true);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
if (ret)
@@ -1384,7 +1391,11 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
+ amd_enable_sdw_interrupts(amd_manager);
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
+ amd_disable_sdw_interrupts(amd_manager);
+ cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
+ cancel_work_sync(&amd_manager->amd_sdw_work);
amd_sdw_wake_enable(amd_manager, true);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
if (ret)
@@ -1392,7 +1403,6 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- amd_disable_sdw_interrupts(amd_manager);
ret = amd_disable_sdw_manager(amd_manager);
if (ret)
return ret;
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3 10/10] soundwire: amd: fix IRQ thread dropping STATUS_0TO7 on simultaneous wake
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
` (8 preceding siblings ...)
2026-10-13 8:49 ` [PATCH V3 09/10] soundwire: amd: fix interrupt gate and work drain ordering in PM ops Vijendar Mukunda
@ 2026-10-13 8:49 ` Vijendar Mukunda
9 siblings, 0 replies; 11+ messages in thread
From: Vijendar Mukunda @ 2026-10-13 8:49 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
When the wake bit and a device-state change arrive at the same time,
the IRQ thread returned early after handling wake, silently discarding
STATUS_0TO7. If the manager is already at D0, pm_request_resume() is
a no-op so the dropped ATTACHED event is never recovered and jack
detection stops working.
Remove the early return on wake: call amd_sdw_process_wake_event(),
strip the wake bit from the local STATUS_8TO11 copy, and continue to
the normal slave-status processing path. Remove the STATUS_8TO11 clear
from amd_sdw_process_wake_event() so the single tail clear in
amd_sdw_irq_thread() is the only write to the register per invocation,
eliminating the double-clear race where a new event arriving between
two successive clears would be wiped before being read.
Fixes: 66c878838f37 ("soundwire: amd: handle SoundWire wake enable interrupt")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 1a252a81269a..beb982b17fa9 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1006,7 +1006,6 @@ static void amd_sdw_process_wake_event(struct amd_sdw_manager *amd_manager)
dev_dbg(amd_manager->dev, "SoundWire Wake event reported\n");
pm_request_resume(amd_manager->dev);
writel(0x00, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
- writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11);
}
static void amd_sdw_irq_thread(struct work_struct *work)
@@ -1023,8 +1022,11 @@ static void amd_sdw_irq_thread(struct work_struct *work)
dev_dbg(amd_manager->dev, "[SDW%d] SDW INT: 0to7=0x%x, 8to11=0x%x\n",
amd_manager->instance, status_change_0to7, status_change_8to11);
- if (status_change_8to11 & AMD_SDW_WAKE_STAT_MASK)
- return amd_sdw_process_wake_event(amd_manager);
+
+ if (status_change_8to11 & AMD_SDW_WAKE_STAT_MASK) {
+ amd_sdw_process_wake_event(amd_manager);
+ status_change_8to11 &= ~AMD_SDW_WAKE_STAT_MASK;
+ }
if (status_change_8to11 & AMD_SDW_PREQ_INTR_STAT) {
amd_sdw_read_and_process_ping_status(amd_manager);
--
2.48.1
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-10-13 8:53 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-13 8:49 [PATCH V3 00/10] soundwire: amd: SoundWire manager driver bug fixes Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 01/10] soundwire: amd: fix SDW command timeout return value handling Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 02/10] soundwire: amd: cache ping slave status to avoid spurious disconnect on timeout Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 03/10] soundwire: amd: fix work drain ordering in remove path Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 04/10] soundwire: amd: pm_runtime guard " Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 05/10] soundwire: amd: fix ctx leak when sdw_amd_startup() fails Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 06/10] soundwire: amd: propagate amd_init_sdw_manager() error on resume Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 07/10] soundwire: amd: drop amd_deinit_sdw_manager() in POWER_OFF suspend Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 08/10] soundwire: amd: replace >= ACP70 with explicit switch/case in PM paths Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 09/10] soundwire: amd: fix interrupt gate and work drain ordering in PM ops Vijendar Mukunda
2026-10-13 8:49 ` [PATCH V3 10/10] soundwire: amd: fix IRQ thread dropping STATUS_0TO7 on simultaneous wake Vijendar Mukunda
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®