Commit 595571cc authored by Charles Keepax's avatar Charles Keepax Committed by Mark Brown

ASoC: dapm: Fix regression introducing multiple copies of DAI widgets

Refactoring was done to factor out the linking of DAI widgets into
a helper function, dapm_add_valid_dai_widget. However when this was
done, a regression was introduced for CODEC to CODEC links. It was
over looked that the playback and capture variables persisted across
all CODEC DAIs being processed, which ensured that the special DAI
widget that is added for CODEC to CODEC links was only created once.
This bug causes kernel panics during DAPM shutdown.

To stick with the spirit of the original refactoring whilst fixing the
issue, variables to hold the DAI widgets are added to snd_soc_dai_link.
Furthermore the dapm_add_valid_dai_widget function is renamed to
dapm_connect_dai_pair, the function only adds DAI widgets in the CODEC
to CODEC case and its primary job is to add routes connecting two DAI
widgets, making the original name quite misleading.

Fixes: 6c4b13b5 ("ASoC: Add dapm_add_valid_dai_widget helper")
Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20200409181209.30130-1-ckeepax@opensource.cirrus.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent ec21bdc6
...@@ -790,6 +790,9 @@ struct snd_soc_dai_link { ...@@ -790,6 +790,9 @@ struct snd_soc_dai_link {
const struct snd_soc_pcm_stream *params; const struct snd_soc_pcm_stream *params;
unsigned int num_params; unsigned int num_params;
struct snd_soc_dapm_widget *playback_widget;
struct snd_soc_dapm_widget *capture_widget;
unsigned int dai_fmt; /* format to set on init */ unsigned int dai_fmt; /* format to set on init */
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */ enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
......
...@@ -4283,52 +4283,63 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) ...@@ -4283,52 +4283,63 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
return 0; return 0;
} }
static void dapm_add_valid_dai_widget(struct snd_soc_card *card, static void dapm_connect_dai_routes(struct snd_soc_dapm_context *dapm,
struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *src_dai,
struct snd_soc_dai *codec_dai, struct snd_soc_dapm_widget *src,
struct snd_soc_dai *cpu_dai) struct snd_soc_dapm_widget *dai,
struct snd_soc_dai *sink_dai,
struct snd_soc_dapm_widget *sink)
{ {
struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; dev_dbg(dapm->dev, "connected DAI link %s:%s -> %s:%s\n",
struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; src_dai->component->name, src->name,
sink_dai->component->name, sink->name);
if (dai) {
snd_soc_dapm_add_path(dapm, src, dai, NULL, NULL);
src = dai;
}
snd_soc_dapm_add_path(dapm, src, sink, NULL, NULL);
}
static void dapm_connect_dai_pair(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *codec_dai,
struct snd_soc_dai *cpu_dai)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dapm_widget *dai, *codec, *playback_cpu, *capture_cpu;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
struct snd_pcm_str *streams = rtd->pcm->streams; struct snd_pcm_str *streams = rtd->pcm->streams;
if (rtd->dai_link->params) { if (dai_link->params) {
playback_cpu = cpu_dai->capture_widget; playback_cpu = cpu_dai->capture_widget;
capture_cpu = cpu_dai->playback_widget; capture_cpu = cpu_dai->playback_widget;
} else { } else {
playback = cpu_dai->playback_widget; playback_cpu = cpu_dai->playback_widget;
capture = cpu_dai->capture_widget; capture_cpu = cpu_dai->capture_widget;
playback_cpu = playback;
capture_cpu = capture;
} }
/* connect BE DAI playback if widgets are valid */ /* connect BE DAI playback if widgets are valid */
codec = codec_dai->playback_widget; codec = codec_dai->playback_widget;
if (playback_cpu && codec) { if (playback_cpu && codec) {
if (!playback) { if (dai_link->params && !dai_link->playback_widget) {
substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
playback = snd_soc_dapm_new_dai(card, substream, dai = snd_soc_dapm_new_dai(card, substream, "playback");
"playback"); if (IS_ERR(dai)) {
if (IS_ERR(playback)) {
dev_err(rtd->dev, dev_err(rtd->dev,
"ASoC: Failed to create DAI %s: %ld\n", "ASoC: Failed to create DAI %s: %ld\n",
codec_dai->name, codec_dai->name,
PTR_ERR(playback)); PTR_ERR(dai));
goto capture; goto capture;
} }
dai_link->playback_widget = dai;
snd_soc_dapm_add_path(&card->dapm, playback_cpu,
playback, NULL, NULL);
} }
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu,
cpu_dai->component->name, playback_cpu->name, dai_link->playback_widget,
codec_dai->component->name, codec->name); codec_dai, codec);
snd_soc_dapm_add_path(&card->dapm, playback, codec,
NULL, NULL);
} }
capture: capture:
...@@ -4336,28 +4347,22 @@ static void dapm_add_valid_dai_widget(struct snd_soc_card *card, ...@@ -4336,28 +4347,22 @@ static void dapm_add_valid_dai_widget(struct snd_soc_card *card,
codec = codec_dai->capture_widget; codec = codec_dai->capture_widget;
if (codec && capture_cpu) { if (codec && capture_cpu) {
if (!capture) { if (dai_link->params && !dai_link->capture_widget) {
substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream;
capture = snd_soc_dapm_new_dai(card, substream, dai = snd_soc_dapm_new_dai(card, substream, "capture");
"capture"); if (IS_ERR(dai)) {
if (IS_ERR(capture)) {
dev_err(rtd->dev, dev_err(rtd->dev,
"ASoC: Failed to create DAI %s: %ld\n", "ASoC: Failed to create DAI %s: %ld\n",
codec_dai->name, codec_dai->name,
PTR_ERR(capture)); PTR_ERR(dai));
return; return;
} }
dai_link->capture_widget = dai;
snd_soc_dapm_add_path(&card->dapm, capture,
capture_cpu, NULL, NULL);
} }
dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", dapm_connect_dai_routes(&card->dapm, codec_dai, codec,
codec_dai->component->name, codec->name, dai_link->capture_widget,
cpu_dai->component->name, capture_cpu->name); cpu_dai, capture_cpu);
snd_soc_dapm_add_path(&card->dapm, codec, capture,
NULL, NULL);
} }
} }
...@@ -4369,12 +4374,12 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, ...@@ -4369,12 +4374,12 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
if (rtd->num_cpus == 1) { if (rtd->num_cpus == 1) {
for_each_rtd_codec_dais(rtd, i, codec_dai) for_each_rtd_codec_dais(rtd, i, codec_dai)
dapm_add_valid_dai_widget(card, rtd, codec_dai, dapm_connect_dai_pair(card, rtd, codec_dai,
rtd->cpu_dais[0]); rtd->cpu_dais[0]);
} else if (rtd->num_codecs == rtd->num_cpus) { } else if (rtd->num_codecs == rtd->num_cpus) {
for_each_rtd_codec_dais(rtd, i, codec_dai) for_each_rtd_codec_dais(rtd, i, codec_dai)
dapm_add_valid_dai_widget(card, rtd, codec_dai, dapm_connect_dai_pair(card, rtd, codec_dai,
rtd->cpu_dais[i]); rtd->cpu_dais[i]);
} else { } else {
dev_err(card->dev, dev_err(card->dev,
"N cpus to M codecs link is not supported yet\n"); "N cpus to M codecs link is not supported yet\n");
......
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