Unverified Commit 051744b1 authored by Ranjani Sridharan's avatar Ranjani Sridharan Committed by Mark Brown
Browse files

ASoC: SOF: Make sof_widget_setup/free IPC agnostic



Add 3 new topology IPC ops for widget_setup, widget_free and dai_config
in order to make the pipeline management code IPC agnostic and implement
the ops for IPC3.

Use the newly introduced tplg dai_config op to configure the DAI during
BE DAI hw_params and hw_free.

Also, in preparation for IPC4, modify BE hw_params callback to skip
setting up the DAI widget. All widgets will be set up during FW
hw_params and the DAI_CONFIG IPC should be sent only if the widget
use_count is > 0. With setting up/freeing removed from the BE hw_params,
remove the configured flag as it is no longer needed.

Signed-off-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220317175044.1752400-3-ranjani.sridharan@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 40c2c63a
Loading
Loading
Loading
Loading
+13 −84
Original line number Diff line number Diff line
@@ -162,58 +162,19 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
	return 0;
}

/* Update config for the DAI widget */
static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w,
							int channel)
{
	struct snd_sof_widget *swidget = w->dobj.private;
	struct sof_dai_private_data *private;
	struct sof_ipc_dai_config *config;
	struct snd_sof_dai *sof_dai;

	if (!swidget)
		return NULL;

	sof_dai = swidget->private;

	if (!sof_dai || !sof_dai->private) {
		dev_err(swidget->scomp->dev, "%s: No private data for DAI %s\n", __func__,
			w->name);
		return NULL;
	}

	private = sof_dai->private;
	if (!private->dai_config) {
		dev_err(swidget->scomp->dev, "%s: No config for DAI %s\n", __func__, w->name);
		return NULL;
	}

	config = &private->dai_config[sof_dai->current_config];

	/* update config with stream tag */
	config->hda.link_dma_ch = channel;

	return config;
}

static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
				      struct snd_soc_dapm_widget *w,
				      int channel, bool widget_setup)
{
	struct snd_sof_dev *sdev = hda_stream->sdev;
	struct sof_ipc_dai_config *config;
	struct snd_sof_dai_config_data data;

	config = hda_dai_update_config(w, channel);
	if (!config) {
		dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
		return -ENOENT;
	}
	data.dai_data = channel;

	/* set up/free DAI widget and send DAI_CONFIG IPC */
	if (widget_setup)
		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP);
		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);

	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}

static int hda_link_hw_params(struct snd_pcm_substream *substream,
@@ -302,34 +263,15 @@ static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
	struct snd_sof_widget *swidget = w->dobj.private;
	struct snd_soc_component *component = swidget->scomp;
	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
	struct sof_dai_private_data *private;
	struct sof_ipc_dai_config *config;
	struct snd_sof_dai *sof_dai;
	struct sof_ipc_reply reply;
	int ret;

	sof_dai = swidget->private;

	if (!sof_dai || !sof_dai->private) {
		dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
		return -EINVAL;
	}

	private = sof_dai->private;
	if (!private->dai_config) {
		dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
		return -EINVAL;
	}

	config = &private->dai_config[sof_dai->current_config];

	/* set PAUSE command flag */
	config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_CMD_MASK, SOF_DAI_CONFIG_FLAGS_PAUSE);
	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
	int ret = 0;

	ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
				 &reply, sizeof(reply));
	if (tplg_ops->dai_config) {
		ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
		if (ret < 0)
		dev_err(sdev->dev, "DAI config for %s failed during pause push\n", w->name);
			dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
				w->name);
	}

	return ret;
}
@@ -470,30 +412,17 @@ struct ssp_dai_dma_data {
static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
				 bool setup)
{
	struct snd_soc_component *component;
	struct snd_sof_widget *swidget;
	struct snd_soc_dapm_widget *w;
	struct sof_ipc_fw_version *v;
	struct snd_sof_dev *sdev;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		w = dai->playback_widget;
	else
		w = dai->capture_widget;

	swidget = w->dobj.private;
	component = swidget->scomp;
	sdev = snd_soc_component_get_drvdata(component);
	v = &sdev->fw_ready.version;

	/* DAI_CONFIG IPC during hw_params is not supported in older firmware */
	if (v->abi_version < SOF_ABI_VER(3, 18, 0))
		return 0;

	if (setup)
		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE);
		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);

	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
}

static int ssp_dai_startup(struct snd_pcm_substream *substream,
+44 −125
Original line number Diff line number Diff line
@@ -41,114 +41,68 @@
#define EXCEPT_MAX_HDR_SIZE	0x400
#define HDA_EXT_ROM_STATUS_SIZE 8

int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags)
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
			      struct snd_sof_dai_config_data *data)
{
	struct snd_sof_widget *swidget = w->dobj.private;
	struct snd_soc_component *component = swidget->scomp;
	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
	struct sof_ipc_dai_config *config;
	struct sof_dai_private_data *private;
	struct snd_sof_dai *sof_dai;
	struct sof_ipc_reply reply;
	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
	struct snd_sof_dai *sof_dai = swidget->private;
	int ret;

	sof_dai = swidget->private;

	if (!sof_dai || !sof_dai->private) {
		dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
		return -EINVAL;
	}

	private = sof_dai->private;
	if (!private->dai_config) {
		dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
	if (!sof_dai) {
		dev_err(sdev->dev, "%s: No DAI for DAI widget %s\n", __func__, w->name);
		return -EINVAL;
	}

	/* DAI already configured, reset it before reconfiguring it */
	if (sof_dai->configured) {
		ret = hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
		if (ret < 0)
			return ret;
	}

	config = &private->dai_config[sof_dai->current_config];

	/*
	 * For static pipelines, the DAI widget would already be set up and calling
	 * sof_widget_setup() simply returns without doing anything.
	 * For dynamic pipelines, the DAI widget will be set up now.
	 */
	ret = sof_widget_setup(sdev, swidget);
	if (ret < 0) {
		dev_err(sdev->dev, "error: failed setting up DAI widget %s\n", w->name);
		return ret;
	}
	if (tplg_ops->dai_config) {
		unsigned int flags;

		/* set HW_PARAMS flag along with quirks */
	config->flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS |
		flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS |
			quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;


	/* send DAI_CONFIG IPC */
	ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
				 &reply, sizeof(reply));
		ret = tplg_ops->dai_config(sdev, swidget, flags, data);
		if (ret < 0) {
		dev_err(sdev->dev, "error: failed setting DAI config for %s\n", w->name);
			dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
				w->name);
			return ret;
		}

	sof_dai->configured = true;
	}

	return 0;
}

int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags)
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
			     struct snd_sof_dai_config_data *data)
{
	struct snd_sof_widget *swidget = w->dobj.private;
	struct snd_soc_component *component = swidget->scomp;
	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
	struct sof_dai_private_data *private;
	struct sof_ipc_dai_config *config;
	struct snd_sof_dai *sof_dai;
	struct sof_ipc_reply reply;
	int ret;

	sof_dai = swidget->private;
	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
	struct snd_sof_dai *sof_dai = swidget->private;

	if (!sof_dai || !sof_dai->private) {
		dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
	if (!sof_dai) {
		dev_err(sdev->dev, "%s: No DAI for BE DAI widget %s\n", __func__, w->name);
		return -EINVAL;
	}

	private = sof_dai->private;
	if (!private->dai_config) {
		dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
		return -EINVAL;
	}

	/* nothing to do if hw_free() is called without restarting the stream after resume. */
	if (!sof_dai->configured)
		return 0;

	config = &private->dai_config[sof_dai->current_config];
	if (tplg_ops->dai_config) {
		unsigned int flags;
		int ret;

		/* set HW_FREE flag along with any quirks */
	config->flags = SOF_DAI_CONFIG_FLAGS_HW_FREE |
		flags = SOF_DAI_CONFIG_FLAGS_HW_FREE |
			quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;

	ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
				 &reply, sizeof(reply));
		ret = tplg_ops->dai_config(sdev, swidget, flags, data);
		if (ret < 0)
		dev_err(sdev->dev, "error: failed resetting DAI config for %s\n", w->name);

	/*
	 * Reset the configured_flag and free the widget even if the IPC fails to keep
	 * the widget use_count balanced
	 */
	sof_dai->configured = false;
			dev_err(sdev->dev, "%s: DAI config failed for widget '%s'\n", __func__,
				w->name);
	}

	return sof_widget_free(sdev, swidget);
	return 0;
}

#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
@@ -163,69 +117,34 @@ static int sdw_clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET;
module_param(sdw_clock_stop_quirks, int, 0444);
MODULE_PARM_DESC(sdw_clock_stop_quirks, "SOF SoundWire clock stop quirks");

static int sdw_dai_config_ipc(struct snd_sof_dev *sdev,
			      struct snd_soc_dapm_widget *w,
			      int link_id, int alh_stream_id, int dai_id, bool setup)
{
	struct snd_sof_widget *swidget = w->dobj.private;
	struct sof_dai_private_data *private;
	struct sof_ipc_dai_config *config;
	struct snd_sof_dai *sof_dai;

	if (!swidget) {
		dev_err(sdev->dev, "error: No private data for widget %s\n", w->name);
		return -EINVAL;
	}

	sof_dai = swidget->private;

	if (!sof_dai || !sof_dai->private) {
		dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
		return -EINVAL;
	}

	private = sof_dai->private;
	if (!private->dai_config) {
		dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
		return -EINVAL;
	}

	config = &private->dai_config[sof_dai->current_config];

	/* update config with link and stream ID */
	config->dai_index = (link_id << 8) | dai_id;
	config->alh.stream_id = alh_stream_id;

	if (setup)
		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE);

	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
}

static int sdw_params_stream(struct device *dev,
			     struct sdw_intel_stream_params_data *params_data)
{
	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
	struct snd_soc_dai *d = params_data->dai;
	struct snd_sof_dai_config_data data;
	struct snd_soc_dapm_widget *w;

	w = snd_soc_dai_get_widget(d, params_data->stream);
	data.dai_index = (params_data->link_id << 8) | d->id;
	data.dai_data = params_data->alh_stream_id;

	return sdw_dai_config_ipc(sdev, w, params_data->link_id, params_data->alh_stream_id,
				  d->id, true);
	return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}

static int sdw_free_stream(struct device *dev,
			   struct sdw_intel_stream_free_data *free_data)
{
	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
	struct snd_soc_dai *d = free_data->dai;
	struct snd_sof_dai_config_data data;
	struct snd_soc_dapm_widget *w;

	w = snd_soc_dai_get_widget(d, free_data->stream);
	data.dai_index = (free_data->link_id << 8) | d->id;

	/* send invalid stream_id */
	return sdw_dai_config_ipc(sdev, w, free_data->link_id, 0xFFFF, d->id, false);
	data.dai_data = 0xFFFF;

	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}

static const struct sdw_intel_ops sdw_callback = {
+5 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <sound/hda_codec.h>
#include <sound/hdaudio_ext.h>
#include "../sof-client-probes.h"
#include "../sof-audio.h"
#include "shim.h"

/* PCI registers */
@@ -730,8 +731,10 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)

struct snd_sof_dai;
struct sof_ipc_dai_config;
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags);
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags);
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
			      struct snd_sof_dai_config_data *data);
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
			     struct snd_sof_dai_config_data *data);

#define SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY	(0) /* previous implementation */
#define SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS	(1) /* recommended if VC0 only */
+150 −0
Original line number Diff line number Diff line
@@ -1909,6 +1909,153 @@ static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_w
	return 1;
}

static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
	struct sof_ipc_free ipc_free = {
		.hdr = {
			.size = sizeof(ipc_free),
			.cmd = SOF_IPC_GLB_TPLG_MSG,
		},
		.id = swidget->comp_id,
	};
	struct sof_ipc_reply reply;
	int ret;

	if (!swidget->private)
		return 0;

	switch (swidget->id) {
	case snd_soc_dapm_scheduler:
	{
		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
		break;
	}
	case snd_soc_dapm_buffer:
		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
		break;
	default:
		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
		break;
	}

	ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
				 &reply, sizeof(reply));
	if (ret < 0)
		dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);

	return ret;
}

static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
			       unsigned int flags, struct snd_sof_dai_config_data *data)
{
	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
	struct snd_sof_dai *dai = swidget->private;
	struct sof_dai_private_data *private;
	struct sof_ipc_dai_config *config;
	struct sof_ipc_reply reply;
	int ret = 0;

	if (!dai || !dai->private) {
		dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
		return -EINVAL;
	}

	private = dai->private;
	if (!private->dai_config) {
		dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
		return -EINVAL;
	}

	config = &private->dai_config[dai->current_config];
	if (!config) {
		dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
		return -EINVAL;
	}

	switch (config->type) {
	case SOF_DAI_INTEL_SSP:
		/*
		 * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
		 * firmware
		 */
		if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
		    ((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
		     (flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
			return 0;
		break;
	case SOF_DAI_INTEL_HDA:
		if (data)
			config->hda.link_dma_ch = data->dai_data;
		break;
	case SOF_DAI_INTEL_ALH:
		if (data) {
			config->dai_index = data->dai_index;
			config->alh.stream_id = data->dai_data;
		}
		break;
	default:
		break;
	}

	config->flags = flags;

	/* only send the IPC if the widget is set up in the DSP */
	if (swidget->use_count > 0) {
		ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
					 &reply, sizeof(reply));
		if (ret < 0)
			dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
	}

	return ret;
}

static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
	struct sof_ipc_comp_reply reply;
	int ret;

	if (!swidget->private)
		return 0;

	switch (swidget->id) {
	case snd_soc_dapm_dai_in:
	case snd_soc_dapm_dai_out:
	{
		struct snd_sof_dai *dai = swidget->private;
		struct sof_dai_private_data *dai_data = dai->private;
		struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;

		ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
					 comp->hdr.size, &reply, sizeof(reply));
		break;
	}
	case snd_soc_dapm_scheduler:
	{
		struct sof_ipc_pipe_new *pipeline;

		pipeline = swidget->private;
		ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
					 sizeof(*pipeline), &reply, sizeof(reply));
		break;
	}
	default:
	{
		struct sof_ipc_cmd_hdr *hdr;

		hdr = swidget->private;
		ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
					 &reply, sizeof(reply));
		break;
	}
	}
	if (ret < 0)
		dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);

	return ret;
}

/* token list for each topology object */
static enum sof_tokens host_token_list[] = {
	SOF_CORE_TOKENS,
@@ -2012,6 +2159,9 @@ static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
	.control_free = sof_ipc3_control_free,
	.pipeline_complete = sof_ipc3_complete_pipeline,
	.token_list = ipc3_token_list,
	.widget_free = sof_ipc3_widget_free,
	.widget_setup = sof_ipc3_widget_setup,
	.dai_config = sof_ipc3_dai_config,
};

const struct sof_ipc_ops ipc3_ops = {
+22 −114
Original line number Diff line number Diff line
@@ -27,31 +27,6 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *
	return ret;
}

static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai)
{
	struct sof_dai_private_data *private = dai->private;
	struct sof_ipc_dai_config *config;
	struct sof_ipc_reply reply;
	int ret;

	config = &private->dai_config[dai->current_config];
	if (!config) {
		dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name);
		return -EINVAL;
	}

	/* set NONE flag to clear all previous settings */
	config->flags = SOF_DAI_CONFIG_FLAGS_NONE;

	ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
				 &reply, sizeof(reply));

	if (ret < 0)
		dev_err(sdev->dev, "error: failed to set dai config for %s\n", dai->name);

	return ret;
}

static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
	struct snd_sof_control *scontrol;
@@ -96,15 +71,9 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so

int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
	struct sof_ipc_free ipc_free = {
		.hdr = {
			.size = sizeof(ipc_free),
			.cmd = SOF_IPC_GLB_TPLG_MSG,
		},
		.id = swidget->comp_id,
	};
	struct sof_ipc_reply reply;
	int ret, err;
	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
	int err = 0;
	int ret;

	if (!swidget->private)
		return 0;
@@ -113,33 +82,9 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
	if (--swidget->use_count)
		return 0;

	switch (swidget->id) {
	case snd_soc_dapm_scheduler:
	{
		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
		break;
	}
	case snd_soc_dapm_buffer:
		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
		break;
	case snd_soc_dapm_dai_in:
	case snd_soc_dapm_dai_out:
	{
		struct snd_sof_dai *dai = swidget->private;

		dai->configured = false;
		fallthrough;
	}
	default:
		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
		break;
	}

	/* continue to disable core even if IPC fails */
	err = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
				 &reply, sizeof(reply));
	if (err < 0)
		dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name);
	if (tplg_ops->widget_free)
		err = tplg_ops->widget_free(sdev, swidget);

	/*
	 * disable widget core. continue to route setup status and complete flag
@@ -176,11 +121,7 @@ EXPORT_SYMBOL(sof_widget_free);

int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
	struct sof_ipc_pipe_new *pipeline;
	struct sof_ipc_comp_reply r;
	struct sof_ipc_cmd_hdr *hdr;
	struct sof_ipc_comp *comp;
	struct snd_sof_dai *dai;
	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
	int ret;

	/* skip if there is no private data */
@@ -219,53 +160,22 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
		goto pipe_widget_free;
	}

	switch (swidget->id) {
	case snd_soc_dapm_dai_in:
	case snd_soc_dapm_dai_out:
	{
		struct sof_dai_private_data *dai_data;

		dai = swidget->private;
		dai_data = dai->private;
		comp = &dai_data->comp_dai->comp;
		dai->configured = false;

		ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
					 comp->hdr.size, &r, sizeof(r));
		if (ret < 0) {
			dev_err(sdev->dev, "error: failed to load widget %s\n",
				swidget->widget->name);
	/* setup widget in the DSP */
	if (tplg_ops->widget_setup) {
		ret = tplg_ops->widget_setup(sdev, swidget);
		if (ret < 0)
			goto core_put;
	}

		ret = sof_dai_config_setup(sdev, dai);
		if (ret < 0) {
			dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n",
				swidget->widget->name);
	/* send config for DAI components */
	if (WIDGET_IS_DAI(swidget->id)) {
		unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE;

			/*
			 * widget use_count and core ref_count will both be decremented by
			 * sof_widget_free()
			 */
			sof_widget_free(sdev, swidget);
			return ret;
		}
		break;
	}
	case snd_soc_dapm_scheduler:
		pipeline = swidget->private;
		ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
					 sizeof(*pipeline), &r, sizeof(r));
		break;
	default:
		hdr = swidget->private;
		ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
					 &r, sizeof(r));
		break;
		if (tplg_ops->dai_config) {
			ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
			if (ret < 0)
				goto widget_free;
		}
	if (ret < 0) {
		dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name);
		goto core_put;
	}

	/* restore kcontrols for widget */
@@ -273,18 +183,16 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
	if (ret < 0) {
		dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n",
			swidget->widget->name);
		/*
		 * widget use_count and core ref_count will both be decremented by
		 * sof_widget_free()
		 */
		sof_widget_free(sdev, swidget);
		return ret;
		goto widget_free;
	}

	dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);

	return 0;

widget_free:
	/* widget use_count and core ref_count will both be decremented by sof_widget_free() */
	sof_widget_free(sdev, swidget);
core_put:
	snd_sof_dsp_core_put(sdev, swidget->core);
pipe_widget_free:
Loading