Commit be1fae62 authored by Srinivas Kandagatla's avatar Srinivas Kandagatla Committed by Mark Brown

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: 30ad723b ("ASoC: qdsp6: audioreach: add q6apm lpass dai support")
Signed-off-by: default avatarSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: default avatarDmitry 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.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 8af49868
...@@ -141,14 +141,17 @@ static void q6apm_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct ...@@ -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); struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc; int rc;
if (!dai_data->is_port_started[dai->id]) if (dai_data->is_port_started[dai->id]) {
return; rc = q6apm_graph_stop(dai_data->graph[dai->id]);
rc = q6apm_graph_stop(dai_data->graph[dai->id]); dai_data->is_port_started[dai->id] = false;
if (rc < 0) if (rc < 0)
dev_err(dai->dev, "fail to close APM port (%d)\n", rc); dev_err(dai->dev, "fail to close APM port (%d)\n", rc);
}
q6apm_graph_close(dai_data->graph[dai->id]); if (dai_data->graph[dai->id]) {
dai_data->is_port_started[dai->id] = false; 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) 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 ...@@ -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]); q6apm_graph_stop(dai_data->graph[dai->id]);
dai_data->is_port_started[dai->id] = false; 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]); 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 ...@@ -183,26 +188,29 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
cfg->direction = substream->stream; cfg->direction = substream->stream;
rc = q6apm_graph_media_format_pcm(dai_data->graph[dai->id], cfg); rc = q6apm_graph_media_format_pcm(dai_data->graph[dai->id], cfg);
if (rc) { if (rc) {
dev_err(dai->dev, "Failed to set media format %d\n", 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]); rc = q6apm_graph_prepare(dai_data->graph[dai->id]);
if (rc) { if (rc) {
dev_err(dai->dev, "Failed to prepare Graph %d\n", 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]); rc = q6apm_graph_start(dai_data->graph[dai->id]);
if (rc < 0) { if (rc < 0) {
dev_err(dai->dev, "fail to start APM port %x\n", dai->id); 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; dai_data->is_port_started[dai->id] = true;
return 0; 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) static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment