Skip to content

Commit 84e3cfd

Browse files
plbossartbroonie
authored andcommitted
ASoC: SOF: Intel: hda-dai: improve SSP DAI handling for dynamic pipelines
In order to keep the widget use_count balanced, make sure the DAI widgets are allocated once in hw_params and released in hw_free. A 'setup' status flag is used to deal with cases where the .hw_params callback is invoked multiple times, and likewise with cases where hw_free is invoked without hw_params being called first (which can happen if the FE hw_params fails). In addition, this patch frees the widgets in the suspend transition, and reallocates them in the .prepare callback. The 'setup' flag helps in this case differentiate between resume (setup needed) and xruns (setup not needed). This balanced operation was not needed previously but will be required when SOF dynamic pipelines are enabled. Co-developed-by: Ranjani Sridharan <[email protected]> Signed-off-by: Ranjani Sridharan <[email protected]> Signed-off-by: Pierre-Louis Bossart <[email protected]> Reviewed-by: Ranjani Sridharan <[email protected]> Reviewed-by: Bard Liao <[email protected]> Reviewed-by: Guennadi Liakhovetski <[email protected]> Reviewed-by: Péter Ujfalusi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 68776b2 commit 84e3cfd

File tree

1 file changed

+80
-2
lines changed

1 file changed

+80
-2
lines changed

sound/soc/sof/intel/hda-dai.c

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,11 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = {
440440

441441
#endif
442442

443+
/* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
444+
struct ssp_dai_dma_data {
445+
bool setup;
446+
};
447+
443448
static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
444449
bool setup)
445450
{
@@ -469,22 +474,95 @@ static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd
469474
return hda_ctrl_dai_widget_free(w);
470475
}
471476

477+
static int ssp_dai_startup(struct snd_pcm_substream *substream,
478+
struct snd_soc_dai *dai)
479+
{
480+
struct ssp_dai_dma_data *dma_data;
481+
482+
dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
483+
if (!dma_data)
484+
return -ENOMEM;
485+
486+
snd_soc_dai_set_dma_data(dai, substream, dma_data);
487+
488+
return 0;
489+
}
490+
491+
static int ssp_dai_setup(struct snd_pcm_substream *substream,
492+
struct snd_soc_dai *dai,
493+
bool setup)
494+
{
495+
struct ssp_dai_dma_data *dma_data;
496+
int ret = 0;
497+
498+
dma_data = snd_soc_dai_get_dma_data(dai, substream);
499+
if (!dma_data) {
500+
dev_err(dai->dev, "%s: failed to get dma_data\n", __func__);
501+
return -EIO;
502+
}
503+
504+
if (dma_data->setup != setup) {
505+
ret = ssp_dai_setup_or_free(substream, dai, setup);
506+
if (!ret)
507+
dma_data->setup = setup;
508+
}
509+
return ret;
510+
}
511+
472512
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
473513
struct snd_pcm_hw_params *params,
474514
struct snd_soc_dai *dai)
475515
{
476-
return ssp_dai_setup_or_free(substream, dai, true);
516+
/* params are ignored for now */
517+
return ssp_dai_setup(substream, dai, true);
518+
}
519+
520+
static int ssp_dai_prepare(struct snd_pcm_substream *substream,
521+
struct snd_soc_dai *dai)
522+
{
523+
/*
524+
* the SSP will only be reconfigured during resume operations and
525+
* not in case of xruns
526+
*/
527+
return ssp_dai_setup(substream, dai, true);
528+
}
529+
530+
static int ssp_dai_trigger(struct snd_pcm_substream *substream,
531+
int cmd, struct snd_soc_dai *dai)
532+
{
533+
if (cmd != SNDRV_PCM_TRIGGER_SUSPEND)
534+
return 0;
535+
536+
return ssp_dai_setup(substream, dai, false);
477537
}
478538

479539
static int ssp_dai_hw_free(struct snd_pcm_substream *substream,
480540
struct snd_soc_dai *dai)
481541
{
482-
return ssp_dai_setup_or_free(substream, dai, false);
542+
return ssp_dai_setup(substream, dai, false);
543+
}
544+
545+
static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
546+
struct snd_soc_dai *dai)
547+
{
548+
struct ssp_dai_dma_data *dma_data;
549+
550+
dma_data = snd_soc_dai_get_dma_data(dai, substream);
551+
if (!dma_data) {
552+
dev_err(dai->dev, "%s: failed to get dma_data\n", __func__);
553+
return;
554+
}
555+
snd_soc_dai_set_dma_data(dai, substream, NULL);
556+
kfree(dma_data);
483557
}
484558

485559
static const struct snd_soc_dai_ops ssp_dai_ops = {
560+
.startup = ssp_dai_startup,
486561
.hw_params = ssp_dai_hw_params,
562+
.prepare = ssp_dai_prepare,
563+
.trigger = ssp_dai_trigger,
487564
.hw_free = ssp_dai_hw_free,
565+
.shutdown = ssp_dai_shutdown,
488566
};
489567

490568
/*

0 commit comments

Comments
 (0)