* [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap
@ 2026-10-16 14:11 Shawn Guo
2026-10-16 14:11 ` [PATCH 1/3] ASoC: qcom: q6apm: Fix unmap regions response handling Shawn Guo
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Shawn Guo @ 2026-10-16 14:11 UTC (permalink / raw)
To: Srinivas Kandagatla, Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Krzysztof Kozlowski, Ajay Kumar Nandam, linux-sound,
linux-arm-msm, linux-kernel, Shawn Guo
Since the early buffer mapping, q6apm maps a front-end's DSP buffers
once in pcm_new() and unmaps them in pcm_free(). The unmap side has a
few problems, which show up when the sound card is unbound and bound
again, e.g. by unbinding and binding any codec on the card:
- The card core removes the components before it frees the PCMs, so
the topology and its graph info are gone by the time pcm_free()
tries to unmap. The unmap is silently skipped, the DSP keeps the old
mapping, and the next bind fails to create the PCM:
qcom-apm gprsvc:service:2:1: Error (1) Processing 0x0100100c cmd
snd-sc8280xp sound: ASoC: can't create pcm MultiMedia1 Playback :-22
- Once unmap is actually sent, every command stalls for five seconds,
because the response handler matches on the wrong opcode:
qcom-apm gprsvc:service:2:1: CMD timeout for [100100d] opcode
- Unmapping the position buffer clears the circular buffer's handle
instead of its own.
Patch 1 fixes the unmap response handling, patch 2 makes the position
buffer unmap clear its own handle, and patch 3 moves the unmap to the
APM component's remove callback, before the topology is unloaded.
Patches 1 and 2 go first so that patch 3 does not introduce the five
second stalls.
Tested on Qualcomm Ride board by unbinding and binding the PCM1681
codec.
echo 0-004c > /sys/bus/i2c/drivers/pcm1681/unbind
echo 0-004c > /sys/bus/i2c/drivers/pcm1681/bind
Shawn Guo (3):
ASoC: qcom: q6apm: Fix unmap regions response handling
ASoC: qcom: q6apm: Clear the right handle on pos buffer unmap
ASoC: qcom: q6apm: Unmap DSP buffers before removing the topology
sound/soc/qcom/qdsp6/q6apm.c | 49 ++++++++++++++++++++++++++----------
1 file changed, 36 insertions(+), 13 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] ASoC: qcom: q6apm: Fix unmap regions response handling
2026-10-16 14:11 [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Shawn Guo
@ 2026-10-16 14:11 ` Shawn Guo
2026-10-16 14:11 ` [PATCH 2/3] ASoC: qcom: q6apm: Clear the right handle on pos buffer unmap Shawn Guo
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Shawn Guo @ 2026-10-16 14:11 UTC (permalink / raw)
To: Srinivas Kandagatla, Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Krzysztof Kozlowski, Ajay Kumar Nandam, linux-sound,
linux-arm-msm, linux-kernel, Shawn Guo
The DSP acknowledges APM_CMD_SHARED_MEM_UNMAP_REGIONS with a
GPR_BASIC_RSP_RESULT packet whose payload carries the acknowledged
opcode and the status. apm_callback() stores hdr->opcode, i.e.
GPR_BASIC_RSP_RESULT itself, as the result opcode, so
audioreach_send_cmd_sync(), which waits for 0x0100100d, never sees a
match and gives up after five seconds even though the DSP has already
processed the command:
qcom-apm gprsvc:service:2:1: CMD timeout for [100100d] opcode
Each mapped graph costs a five second stall on unmap, and the forced
status of 0 also hides real DSP failures from the caller.
Record the opcode and status from the response payload, like the other
basic-result commands do, and only drop the cached mapping handle when
the DSP reports success.
Fixes: 8ea6e25c8536 ("ASoC: qcom: q6apm: Add support for early buffer mapping on DSP")
Assisted-by: LLM
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
---
sound/soc/qcom/qdsp6/q6apm.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index ea6680925f21..702df80d2fb8 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -959,17 +959,16 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
wake_up(&apm->wait);
break;
case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
- apm->result.opcode = hdr->opcode;
- apm->result.status = 0;
- rsp = data->payload;
-
- info = idr_find(&apm->graph_info_idr, hdr->token);
- if (info)
- info->mem_map_handle = 0;
- else
+ apm->result.opcode = result->opcode;
+ apm->result.status = result->status;
+ if (result->status)
dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
result->opcode);
+ info = idr_find(&apm->graph_info_idr, hdr->token);
+ if (info && !result->status)
+ info->mem_map_handle = 0;
+
wake_up(&apm->wait);
break;
default:
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/3] ASoC: qcom: q6apm: Clear the right handle on pos buffer unmap
2026-10-16 14:11 [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Shawn Guo
2026-10-16 14:11 ` [PATCH 1/3] ASoC: qcom: q6apm: Fix unmap regions response handling Shawn Guo
@ 2026-10-16 14:11 ` Shawn Guo
2026-10-16 14:11 ` [PATCH 3/3] ASoC: qcom: q6apm: Unmap DSP buffers before removing the topology Shawn Guo
2026-10-20 6:26 ` [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Srinivas Kandagatla
3 siblings, 0 replies; 5+ messages in thread
From: Shawn Guo @ 2026-10-16 14:11 UTC (permalink / raw)
To: Srinivas Kandagatla, Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Krzysztof Kozlowski, Ajay Kumar Nandam, linux-sound,
linux-arm-msm, linux-kernel, Shawn Guo
Push/pull graphs map two shared-memory regions per graph, the circular
buffer and the position buffer, and keep a separate DSP handle for
each. The map path tags its token with APM_MMAP_TOKEN_MAP_TYPE_POS_BUF
so the response lands in the right handle, but the unmap path sends a
bare graph ID and the response handler always clears mem_map_handle.
Unmapping the position buffer therefore wipes the circular buffer's
handle and leaves pos_buf_mem_map_handle set. A subsequent unmap of the
circular buffer is skipped, leaking that DSP mapping, and a remap of
the position buffer is skipped because the stale handle looks valid.
Tag the unmap token the same way as the map token and decode it in the
response handler to clear the matching handle.
Fixes: 7c1ac23b178a ("ASoC: qcom: audioreach: Add support for shared memory push/pull modules")
Assisted-by: LLM
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
---
sound/soc/qcom/qdsp6/q6apm.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 702df80d2fb8..72ccaea1feb3 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -328,8 +328,9 @@ static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int gr
struct q6apm *apm = dev_get_drvdata(dev->parent);
struct audioreach_graph_info *info;
uint32_t mem_map_handle;
+ uint32_t pos_mask = is_pos_buf ? APM_MMAP_TOKEN_MAP_TYPE_POS_BUF : 0;
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd),
- APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id);
+ APM_CMD_SHARED_MEM_UNMAP_REGIONS, (graph_id | pos_mask));
if (IS_ERR(pkt))
return PTR_ERR(pkt);
@@ -965,9 +966,16 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
result->opcode);
- info = idr_find(&apm->graph_info_idr, hdr->token);
- if (info && !result->status)
- info->mem_map_handle = 0;
+ graph_id = hdr->token & APM_MMAP_TOKEN_GID_MASK;
+ is_pos_buf = hdr->token & APM_MMAP_TOKEN_MAP_TYPE_POS_BUF;
+
+ info = idr_find(&apm->graph_info_idr, graph_id);
+ if (info && !result->status) {
+ if (is_pos_buf)
+ info->pos_buf_mem_map_handle = 0;
+ else
+ info->mem_map_handle = 0;
+ }
wake_up(&apm->wait);
break;
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/3] ASoC: qcom: q6apm: Unmap DSP buffers before removing the topology
2026-10-16 14:11 [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Shawn Guo
2026-10-16 14:11 ` [PATCH 1/3] ASoC: qcom: q6apm: Fix unmap regions response handling Shawn Guo
2026-10-16 14:11 ` [PATCH 2/3] ASoC: qcom: q6apm: Clear the right handle on pos buffer unmap Shawn Guo
@ 2026-10-16 14:11 ` Shawn Guo
2026-10-20 6:26 ` [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Srinivas Kandagatla
3 siblings, 0 replies; 5+ messages in thread
From: Shawn Guo @ 2026-10-16 14:11 UTC (permalink / raw)
To: Srinivas Kandagatla, Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Krzysztof Kozlowski, Ajay Kumar Nandam, linux-sound,
linux-arm-msm, linux-kernel, Shawn Guo
Since buffers are mapped once in pcm_new() and unmapped in pcm_free(),
the unmap relies on the graph info still being registered. During card
teardown, however, soc_cleanup_card_resources() removes the components
before it frees the PCM runtimes. q6apm-audio's remove callback unloads
the topology, which frees every audioreach_graph_info, so by the time
q6apm_dai_pcm_free() runs the idr lookup fails and the unmap silently
returns -ENODEV. The DSP keeps the old mapping.
When the card is bound again, for example after unbinding and binding
any codec on it, pcm_new() maps the same buffer once more, the DSP
rejects it and the front-end PCM is not created:
qcom-apm gprsvc:service:2:1: Error (1) Processing 0x0100100c cmd
qcom-apm gprsvc:service:2:1: DSP returned error[100100c] 1
q6apm-dai ...: Audio Start: Buffer Allocation failed rc = -22
snd-sc8280xp sound: ASoC: can't create pcm MultiMedia1 Playback :-22
Release the circular and position buffer mappings of all graphs in
q6apm_audio_remove() while the graph info still exists. The unmap
helper now takes the q6apm instance directly, since it is called from
the APM component rather than from a q6apm-dai child device.
Fixes: 8ea6e25c8536 ("ASoC: qcom: q6apm: Add support for early buffer mapping on DSP")
Assisted-by: LLM
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
---
sound/soc/qcom/qdsp6/q6apm.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 72ccaea1feb3..bfbcf259002e 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -321,11 +321,10 @@ int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr
}
EXPORT_SYMBOL_GPL(q6apm_alloc_fragments);
-static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id,
+static int __q6apm_unmap_memory_fixed_region(struct q6apm *apm, unsigned int graph_id,
bool is_pos_buf)
{
struct apm_cmd_shared_mem_unmap_regions *cmd;
- struct q6apm *apm = dev_get_drvdata(dev->parent);
struct audioreach_graph_info *info;
uint32_t mem_map_handle;
uint32_t pos_mask = is_pos_buf ? APM_MMAP_TOKEN_MAP_TYPE_POS_BUF : 0;
@@ -357,13 +356,15 @@ static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int gr
int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id)
{
- return __q6apm_unmap_memory_fixed_region(dev, graph_id, false);
+ return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent),
+ graph_id, false);
}
EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region);
int q6apm_unmap_pos_buffer(struct device *dev, unsigned int graph_id)
{
- return __q6apm_unmap_memory_fixed_region(dev, graph_id, true);
+ return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent),
+ graph_id, true);
}
EXPORT_SYMBOL_GPL(q6apm_unmap_pos_buffer);
@@ -850,6 +851,21 @@ static int q6apm_audio_probe(struct snd_soc_component *component)
static void q6apm_audio_remove(struct snd_soc_component *component)
{
+ struct q6apm *apm = dev_get_drvdata(component->dev);
+ struct audioreach_graph_info *info;
+ int id;
+
+ /*
+ * The card core removes components before freeing the PCMs, so
+ * q6apm-dai's pcm_free() runs after the topology (and graph_info)
+ * is gone and can no longer unmap. Release the DSP mappings here,
+ * otherwise the next pcm_new() fails to map the same buffer again.
+ */
+ idr_for_each_entry(&apm->graph_info_idr, info, id) {
+ __q6apm_unmap_memory_fixed_region(apm, id, false);
+ __q6apm_unmap_memory_fixed_region(apm, id, true);
+ }
+
/* remove topology */
snd_soc_tplg_component_remove(component);
}
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap
2026-10-16 14:11 [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Shawn Guo
` (2 preceding siblings ...)
2026-10-16 14:11 ` [PATCH 3/3] ASoC: qcom: q6apm: Unmap DSP buffers before removing the topology Shawn Guo
@ 2026-10-20 6:26 ` Srinivas Kandagatla
3 siblings, 0 replies; 5+ messages in thread
From: Srinivas Kandagatla @ 2026-10-20 6:26 UTC (permalink / raw)
To: Shawn Guo, Srinivas Kandagatla, Mark Brown
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Krzysztof Kozlowski, Ajay Kumar Nandam, linux-sound,
linux-arm-msm, linux-kernel
On 10/16/26 3:11 PM, Shawn Guo wrote:
> Since the early buffer mapping, q6apm maps a front-end's DSP buffers
> once in pcm_new() and unmaps them in pcm_free(). The unmap side has a
> few problems, which show up when the sound card is unbound and bound
> again, e.g. by unbinding and binding any codec on the card:
>
> - The card core removes the components before it frees the PCMs, so
> the topology and its graph info are gone by the time pcm_free()
> tries to unmap. The unmap is silently skipped, the DSP keeps the old
> mapping, and the next bind fails to create the PCM:
>
> qcom-apm gprsvc:service:2:1: Error (1) Processing 0x0100100c cmd
> snd-sc8280xp sound: ASoC: can't create pcm MultiMedia1 Playback :-22
>
> - Once unmap is actually sent, every command stalls for five seconds,
> because the response handler matches on the wrong opcode:
>
> qcom-apm gprsvc:service:2:1: CMD timeout for [100100d] opcode
>
> - Unmapping the position buffer clears the circular buffer's handle
> instead of its own.
>
> Patch 1 fixes the unmap response handling, patch 2 makes the position
> buffer unmap clear its own handle, and patch 3 moves the unmap to the
> APM component's remove callback, before the topology is unloaded.
> Patches 1 and 2 go first so that patch 3 does not introduce the five
> second stalls.
>
> Tested on Qualcomm Ride board by unbinding and binding the PCM1681
> codec.
>
> echo 0-004c > /sys/bus/i2c/drivers/pcm1681/unbind
> echo 0-004c > /sys/bus/i2c/drivers/pcm1681/bind
Thanks for trying this case and fixing some of the issues.
Can you pl add Stable tag for these.
Other than than they look good to me.
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
--srini
>
> Shawn Guo (3):
> ASoC: qcom: q6apm: Fix unmap regions response handling
> ASoC: qcom: q6apm: Clear the right handle on pos buffer unmap
> ASoC: qcom: q6apm: Unmap DSP buffers before removing the topology
>
> sound/soc/qcom/qdsp6/q6apm.c | 49 ++++++++++++++++++++++++++----------
> 1 file changed, 36 insertions(+), 13 deletions(-)
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-20 6:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-16 14:11 [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Shawn Guo
2026-10-16 14:11 ` [PATCH 1/3] ASoC: qcom: q6apm: Fix unmap regions response handling Shawn Guo
2026-10-16 14:11 ` [PATCH 2/3] ASoC: qcom: q6apm: Clear the right handle on pos buffer unmap Shawn Guo
2026-10-16 14:11 ` [PATCH 3/3] ASoC: qcom: q6apm: Unmap DSP buffers before removing the topology Shawn Guo
2026-10-20 6:26 ` [PATCH 0/3] ASoC: qcom: q6apm: Fix shared memory unmap Srinivas Kandagatla
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®