diff options
Diffstat (limited to 'sound/soc/sof/ipc3-topology.c')
-rw-r--r-- | sound/soc/sof/ipc3-topology.c | 79 |
1 files changed, 51 insertions, 28 deletions
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 2f8450a8c0a1..043554d7cb4a 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -11,7 +11,7 @@ #include <sound/pcm_params.h> #include "sof-priv.h" #include "sof-audio.h" -#include "ipc3-ops.h" +#include "ipc3-priv.h" #include "ops.h" /* Full volume for default values */ @@ -20,7 +20,8 @@ struct sof_widget_data { int ctrl_type; int ipc_cmd; - struct sof_abi_hdr *pdata; + void *pdata; + size_t pdata_size; struct snd_sof_control *control; }; @@ -784,16 +785,26 @@ static int sof_get_control_data(struct snd_soc_component *scomp, } cdata = wdata[i].control->ipc_control_data; - wdata[i].pdata = cdata->data; - if (!wdata[i].pdata) - return -EINVAL; - /* make sure data is valid - data can be updated at runtime */ - if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES && - wdata[i].pdata->magic != SOF_ABI_MAGIC) - return -EINVAL; + if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES) { + /* make sure data is valid - data can be updated at runtime */ + if (cdata->data->magic != SOF_ABI_MAGIC) + return -EINVAL; + + wdata[i].pdata = cdata->data->data; + wdata[i].pdata_size = cdata->data->size; + } else { + /* points to the control data union */ + wdata[i].pdata = cdata->chanv; + /* + * wdata[i].control->size is calculated with struct_size + * and includes the size of struct sof_ipc_ctrl_data + */ + wdata[i].pdata_size = wdata[i].control->size - + sizeof(struct sof_ipc_ctrl_data); + } - *size += wdata[i].pdata->size; + *size += wdata[i].pdata_size; /* get data type */ switch (cdata->cmd) { @@ -876,10 +887,12 @@ static int sof_process_load(struct snd_soc_component *scomp, */ if (ipc_data_size) { for (i = 0; i < widget->num_kcontrols; i++) { - memcpy(&process->data[offset], - wdata[i].pdata->data, - wdata[i].pdata->size); - offset += wdata[i].pdata->size; + if (!wdata[i].pdata_size) + continue; + + memcpy(&process->data[offset], wdata[i].pdata, + wdata[i].pdata_size); + offset += wdata[i].pdata_size; } } @@ -1551,8 +1564,7 @@ static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * sroute->sink_widget->widget->name); /* send ipc */ - ret = sof_ipc_tx_message(sdev->ipc, connect.hdr.cmd, &connect, sizeof(connect), - &reply, sizeof(reply)); + ret = sof_ipc_tx_message(sdev->ipc, &connect, sizeof(connect), &reply, sizeof(reply)); if (ret < 0) dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__, sroute->src_widget->widget->name, sroute->sink_widget->widget->name); @@ -1592,6 +1604,7 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_ if (scontrol->priv_size > 0) { memcpy(cdata->data, scontrol->priv, scontrol->priv_size); kfree(scontrol->priv); + scontrol->priv = NULL; if (cdata->data->magic != SOF_ABI_MAGIC) { dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic); @@ -1697,7 +1710,7 @@ static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_contro fcomp.id = scontrol->comp_id; /* send IPC to the DSP */ - return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0); + return sof_ipc_tx_message(sdev->ipc, &fcomp, sizeof(fcomp), NULL, 0); } /* send pcm params ipc */ @@ -1749,7 +1762,7 @@ static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, in } /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), + ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm), &ipc_params_reply, sizeof(ipc_params_reply)); if (ret < 0) dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__, @@ -1773,8 +1786,7 @@ static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int c stream.comp_id = swidget->comp_id; /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + ret = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply)); if (ret < 0) dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name); @@ -1902,8 +1914,7 @@ static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_w ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE; ready.comp_id = swidget->comp_id; - ret = sof_ipc_tx_message(sdev->ipc, ready.hdr.cmd, &ready, sizeof(ready), &reply, - sizeof(reply)); + ret = sof_ipc_tx_message(sdev->ipc, &ready, sizeof(ready), &reply, sizeof(reply)); if (ret < 0) return ret; @@ -1939,7 +1950,7 @@ static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget break; } - ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free), + ret = sof_ipc_tx_message(sdev->ipc, &ipc_free, sizeof(ipc_free), &reply, sizeof(reply)); if (ret < 0) dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name); @@ -2003,7 +2014,7 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * /* 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, + ret = sof_ipc_tx_message(sdev->ipc, config, config->hdr.size, &reply, sizeof(reply)); if (ret < 0) dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name); @@ -2028,7 +2039,7 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget 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, + ret = sof_ipc_tx_message(sdev->ipc, dai_data->comp_dai, comp->hdr.size, &reply, sizeof(reply)); break; } @@ -2037,8 +2048,8 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget 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)); + ret = sof_ipc_tx_message(sdev->ipc, pipeline, sizeof(*pipeline), + &reply, sizeof(reply)); break; } default: @@ -2046,7 +2057,7 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget struct sof_ipc_cmd_hdr *hdr; hdr = swidget->private; - ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size, + ret = sof_ipc_tx_message(sdev->ipc, swidget->private, hdr->size, &reply, sizeof(reply)); break; } @@ -2249,6 +2260,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; } |