ASoC: q6apm-lpass-dai: close graph on prepare errors

There is an issue around with error handling and graph management with
the exising code, none of the error paths close the graph, which result in
leaving the loaded graph in dsp, however the driver thinks otherwise.

This can have a nasty side effect specially when we try to load the same
graph to dsp, dsp returns error which leaves the board with no sound and
requires restart.

Fix this by properly closing the graph when we hit errors between
open and close.

Fixes: 30ad723b93 ("ASoC: qdsp6: audioreach: add q6apm lpass dai support")
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> # X13s
Link: https://lore.kernel.org/r/20240613-q6apm-fixes-v1-1-d88953675ab3@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Srinivas Kandagatla 2024-06-13 13:13:05 +01:00 committed by Mark Brown
parent 8af49868e5
commit be1fae62cf
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -141,14 +141,17 @@ static void q6apm_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc;
if (!dai_data->is_port_started[dai->id])
return;
rc = q6apm_graph_stop(dai_data->graph[dai->id]);
if (rc < 0)
dev_err(dai->dev, "fail to close APM port (%d)\n", rc);
if (dai_data->is_port_started[dai->id]) {
rc = q6apm_graph_stop(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false;
if (rc < 0)
dev_err(dai->dev, "fail to close APM port (%d)\n", rc);
}
q6apm_graph_close(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false;
if (dai_data->graph[dai->id]) {
q6apm_graph_close(dai_data->graph[dai->id]);
dai_data->graph[dai->id] = NULL;
}
}
static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
@ -163,8 +166,10 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
q6apm_graph_stop(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
q6apm_graph_close(dai_data->graph[dai->id]);
dai_data->graph[dai->id] = NULL;
}
}
/**
@ -183,26 +188,29 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
cfg->direction = substream->stream;
rc = q6apm_graph_media_format_pcm(dai_data->graph[dai->id], cfg);
if (rc) {
dev_err(dai->dev, "Failed to set media format %d\n", rc);
return rc;
goto err;
}
rc = q6apm_graph_prepare(dai_data->graph[dai->id]);
if (rc) {
dev_err(dai->dev, "Failed to prepare Graph %d\n", rc);
return rc;
goto err;
}
rc = q6apm_graph_start(dai_data->graph[dai->id]);
if (rc < 0) {
dev_err(dai->dev, "fail to start APM port %x\n", dai->id);
return rc;
goto err;
}
dai_data->is_port_started[dai->id] = true;
return 0;
err:
q6apm_graph_close(dai_data->graph[dai->id]);
dai_data->graph[dai->id] = NULL;
return rc;
}
static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)