Commit 83f48ad5 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: Intel: improve HDaudio DAI support

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

The SOF CI and daily tests exposed a number of issues with corner
cases on platforms using the HDaudio DAI, such as UpExtreme boards or
usual HDaudio+DMIC laptops.

This patchset provides improvements for pause_push/pause_release,
suspend-resume, mixing use cases and combinations of all three.

The initial patches provide a cleanup, the last patches improve the
state machine and DMA handling.
parents 0386dd91 c4eb48f7
......@@ -43,6 +43,9 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
/* ipc */
sof_apl_ops.send_msg = hda_dsp_ipc_send_msg;
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_apl_ops);
/* debug */
sof_apl_ops.debug_map = apl_dsp_debugfs;
sof_apl_ops.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs);
......
......@@ -261,6 +261,9 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
/* ipc */
sof_cnl_ops.send_msg = cnl_ipc_send_msg;
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_cnl_ops);
/* debug */
sof_cnl_ops.debug_map = cnl_dsp_debugfs;
sof_cnl_ops.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs);
......
This diff is collapsed.
......@@ -894,44 +894,14 @@ int hda_dsp_shutdown(struct snd_sof_dev *sdev)
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_soc_pcm_runtime *rtd;
struct hdac_ext_stream *hext_stream;
struct hdac_ext_link *link;
struct hdac_stream *s;
const char *name;
int stream_tag;
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
hext_stream = stream_to_hdac_ext_stream(s);
/*
* clear stream. This should already be taken care for running
* streams when the SUSPEND trigger is called. But paused
* streams do not get suspended, so this needs to be done
* explicitly during suspend.
*/
if (hext_stream->link_substream) {
rtd = asoc_substream_to_rtd(hext_stream->link_substream);
name = asoc_rtd_to_codec(rtd, 0)->component->name;
link = snd_hdac_ext_bus_get_link(bus, name);
if (!link)
return -EINVAL;
hext_stream->link_prepared = 0;
int ret;
if (hdac_stream(hext_stream)->direction ==
SNDRV_PCM_STREAM_CAPTURE)
continue;
/* make sure all DAI resources are freed */
ret = hda_dsp_dais_suspend(sdev);
if (ret < 0)
dev_warn(sdev->dev, "%s: failure in hda_dsp_dais_suspend\n", __func__);
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
}
}
#endif
return 0;
return ret;
}
void hda_dsp_d0i3_work(struct work_struct *work)
......
......@@ -697,6 +697,7 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
/*
* Platform Specific HW abstraction Ops.
......@@ -761,4 +762,6 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_f
extern int sof_hda_position_quirk;
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops);
#endif
......@@ -127,6 +127,9 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
/* dsp core get/put */
sof_icl_ops.core_get = hda_dsp_core_get;
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_icl_ops);
return 0;
};
EXPORT_SYMBOL_NS(sof_icl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
......
......@@ -76,6 +76,9 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
/* ipc */
sof_tgl_ops.send_msg = cnl_ipc_send_msg;
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_tgl_ops);
/* debug */
sof_tgl_ops.debug_map = tgl_dsp_debugfs;
sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs);
......
......@@ -2247,6 +2247,18 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
list_for_each_entry(sroute, &sdev->route_list, list)
sroute->setup = false;
/*
* before suspending, make sure the refcounts are all zeroed out. There's no way
* to recover at this point but this will help root cause bad sequences leading to
* more issues on resume
*/
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->use_count != 0) {
dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n",
__func__, swidget->widget->name, swidget->use_count);
}
}
return 0;
}
......
......@@ -194,7 +194,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
/* prepare for streams to be resumed properly upon resume */
if (!runtime_suspend) {
ret = sof_set_hw_params_upon_resume(sdev->dev);
ret = snd_sof_dsp_hw_params_upon_resume(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: setting hw_params flag during suspend %d\n",
......
......@@ -413,42 +413,6 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
return false;
}
int sof_set_hw_params_upon_resume(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
snd_pcm_state_t state;
int dir;
/*
* SOF requires hw_params to be set-up internally upon resume.
* So, set the flag to indicate this for those streams that
* have been suspended.
*/
list_for_each_entry(spcm, &sdev->pcm_list, list) {
for_each_pcm_streams(dir) {
/*
* do not reset hw_params upon resume for streams that
* were kept running during suspend
*/
if (spcm->stream[dir].suspend_ignored)
continue;
substream = spcm->stream[dir].substream;
if (!substream || !substream->runtime)
continue;
state = substream->runtime->status->state;
if (state == SNDRV_PCM_STATE_SUSPENDED)
spcm->prepared[dir] = false;
}
}
/* set internal flag for BE */
return snd_sof_dsp_hw_params_upon_resume(sdev);
}
int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
{
......
......@@ -434,7 +434,6 @@ static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { }
int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
/* PM */
int sof_set_hw_params_upon_resume(struct device *dev);
bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev);
bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev);
......
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