[PATCH] ASoC: qcom: q6apm: keep the graph start count in sync with the DSP
From: Jorijn van der Graaf
Date: Sun Jul 26 2026 - 17:13:27 EST
q6apm_graph_start() increments start_count even when APM_CMD_GRAPH_START
fails, leaving the graph counted as running while the DSP never started
it. A later start - a retried prepare, or a resume after a failed start -
then finds a non-zero count, skips the command and returns success with
no data flowing.
Count the graph only once the DSP has accepted the start. The count then
stays at zero for a graph that never started, so also stop decrementing
below zero in q6apm_graph_stop(): the compressed free path stops
unconditionally, and a negative count would make the next start skip the
command in the same way.
Fixes: 5477518b8a0e ("ASoC: qdsp6: audioreach: add q6apm support")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@xxxxxxxxxxxxx>
---
Found by inspection while working on MI2S clocking on the Fairphone
(Gen. 6); I have not hit either path on hardware, so no stable Cc - say
the word if you want one.
One patch, because the start hunk alone would leave q6apm_dai_compr_free()
able to take the count negative - a bisect hole. That call became
unbalanced with 88b60bf047fd ("ASoC: q6dsp: q6apm-dai: Add open/free
compress DAI callbacks"), but the counting logic is from the Fixes commit.
A never-started graph is still torn down by APM_CMD_GRAPH_CLOSE.
The guard is in the helper to keep the count in one place; the equivalent
check in the compressed free path, as q6apm_dai_close() has it, works too.
sound/soc/qcom/qdsp6/q6apm.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 641d6d243229..f167b9dae3fa 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -802,14 +802,17 @@ EXPORT_SYMBOL_GPL(q6apm_graph_prepare);
int q6apm_graph_start(struct q6apm_graph *graph)
{
struct audioreach_graph *ar_graph = graph->ar_graph;
- int ret = 0;
+ int ret;
- if (ar_graph->start_count == 0)
+ if (ar_graph->start_count == 0) {
ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START);
+ if (ret)
+ return ret;
+ }
ar_graph->start_count++;
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(q6apm_graph_start);
@@ -817,6 +820,9 @@ int q6apm_graph_stop(struct q6apm_graph *graph)
{
struct audioreach_graph *ar_graph = graph->ar_graph;
+ if (ar_graph->start_count == 0)
+ return 0;
+
if (--ar_graph->start_count > 0)
return 0;
base-commit: 4c4a11fdf61ca56a08ea05635a1479b9bee666f4
--
2.55.0