cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipc3-control.c (20258B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
      2//
      3// This file is provided under a dual BSD/GPLv2 license.  When using or
      4// redistributing this file, you may do so under either license.
      5//
      6// Copyright(c) 2021 Intel Corporation. All rights reserved.
      7//
      8//
      9
     10#include "sof-priv.h"
     11#include "sof-audio.h"
     12#include "ipc3-priv.h"
     13
     14/* IPC set()/get() for kcontrols. */
     15static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
     16{
     17	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp);
     18	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
     19	const struct sof_ipc_ops *iops = sdev->ipc->ops;
     20	enum sof_ipc_ctrl_type ctrl_type;
     21	struct snd_sof_widget *swidget;
     22	bool widget_found = false;
     23	u32 ipc_cmd, msg_bytes;
     24
     25	list_for_each_entry(swidget, &sdev->widget_list, list) {
     26		if (swidget->comp_id == scontrol->comp_id) {
     27			widget_found = true;
     28			break;
     29		}
     30	}
     31
     32	if (!widget_found) {
     33		dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__,
     34			scontrol->comp_id);
     35		return -EINVAL;
     36	}
     37
     38	/*
     39	 * Volatile controls should always be part of static pipelines and the widget use_count
     40	 * would always be > 0 in this case. For the others, just return the cached value if the
     41	 * widget is not set up.
     42	 */
     43	if (!swidget->use_count)
     44		return 0;
     45
     46	/*
     47	 * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the
     48	 * direction
     49	 * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently
     50	 *	 for ctrl_type
     51	 */
     52	if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
     53		ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA;
     54		ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET;
     55	} else {
     56		ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE;
     57		ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET;
     58	}
     59
     60	cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
     61	cdata->type = ctrl_type;
     62	cdata->comp_id = scontrol->comp_id;
     63	cdata->msg_index = 0;
     64
     65	/* calculate header and data size */
     66	switch (cdata->type) {
     67	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
     68	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
     69		cdata->num_elems = scontrol->num_channels;
     70
     71		msg_bytes = scontrol->num_channels *
     72			    sizeof(struct sof_ipc_ctrl_value_chan);
     73		msg_bytes += sizeof(struct sof_ipc_ctrl_data);
     74		break;
     75	case SOF_CTRL_TYPE_DATA_GET:
     76	case SOF_CTRL_TYPE_DATA_SET:
     77		cdata->num_elems = cdata->data->size;
     78
     79		msg_bytes = cdata->data->size;
     80		msg_bytes += sizeof(struct sof_ipc_ctrl_data) +
     81			     sizeof(struct sof_abi_hdr);
     82		break;
     83	default:
     84		return -EINVAL;
     85	}
     86
     87	cdata->rhdr.hdr.size = msg_bytes;
     88	cdata->elems_remaining = 0;
     89
     90	return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
     91}
     92
     93static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
     94{
     95	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
     96	struct snd_soc_component *scomp = scontrol->scomp;
     97	int ret;
     98
     99	if (!scontrol->comp_data_dirty)
    100		return;
    101
    102	if (!pm_runtime_active(scomp->dev))
    103		return;
    104
    105	/* set the ABI header values */
    106	cdata->data->magic = SOF_ABI_MAGIC;
    107	cdata->data->abi = SOF_ABI_VERSION;
    108
    109	/* refresh the component data from DSP */
    110	scontrol->comp_data_dirty = false;
    111	ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
    112	if (ret < 0) {
    113		dev_err(scomp->dev, "Failed to get control data: %d\n", ret);
    114
    115		/* Set the flag to re-try next time to get the data */
    116		scontrol->comp_data_dirty = true;
    117	}
    118}
    119
    120static int sof_ipc3_volume_get(struct snd_sof_control *scontrol,
    121			       struct snd_ctl_elem_value *ucontrol)
    122{
    123	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    124	unsigned int channels = scontrol->num_channels;
    125	unsigned int i;
    126
    127	snd_sof_refresh_control(scontrol);
    128
    129	/* read back each channel */
    130	for (i = 0; i < channels; i++)
    131		ucontrol->value.integer.value[i] = ipc_to_mixer(cdata->chanv[i].value,
    132								scontrol->volume_table,
    133								scontrol->max + 1);
    134
    135	return 0;
    136}
    137
    138static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol,
    139				struct snd_ctl_elem_value *ucontrol)
    140{
    141	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    142	struct snd_soc_component *scomp = scontrol->scomp;
    143	unsigned int channels = scontrol->num_channels;
    144	unsigned int i;
    145	bool change = false;
    146
    147	/* update each channel */
    148	for (i = 0; i < channels; i++) {
    149		u32 value = mixer_to_ipc(ucontrol->value.integer.value[i],
    150					 scontrol->volume_table, scontrol->max + 1);
    151
    152		change = change || (value != cdata->chanv[i].value);
    153		cdata->chanv[i].channel = i;
    154		cdata->chanv[i].value = value;
    155	}
    156
    157	/* notify DSP of mixer updates */
    158	if (pm_runtime_active(scomp->dev)) {
    159		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
    160
    161		if (ret < 0) {
    162			dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
    163				scontrol->name);
    164			return false;
    165		}
    166	}
    167
    168	return change;
    169}
    170
    171static int sof_ipc3_switch_get(struct snd_sof_control *scontrol,
    172			       struct snd_ctl_elem_value *ucontrol)
    173{
    174	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    175	unsigned int channels = scontrol->num_channels;
    176	unsigned int i;
    177
    178	snd_sof_refresh_control(scontrol);
    179
    180	/* read back each channel */
    181	for (i = 0; i < channels; i++)
    182		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
    183
    184	return 0;
    185}
    186
    187static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol,
    188				struct snd_ctl_elem_value *ucontrol)
    189{
    190	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    191	struct snd_soc_component *scomp = scontrol->scomp;
    192	unsigned int channels = scontrol->num_channels;
    193	unsigned int i;
    194	bool change = false;
    195	u32 value;
    196
    197	/* update each channel */
    198	for (i = 0; i < channels; i++) {
    199		value = ucontrol->value.integer.value[i];
    200		change = change || (value != cdata->chanv[i].value);
    201		cdata->chanv[i].channel = i;
    202		cdata->chanv[i].value = value;
    203	}
    204
    205	/* notify DSP of mixer updates */
    206	if (pm_runtime_active(scomp->dev)) {
    207		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
    208
    209		if (ret < 0) {
    210			dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
    211				scontrol->name);
    212			return false;
    213		}
    214	}
    215
    216	return change;
    217}
    218
    219static int sof_ipc3_enum_get(struct snd_sof_control *scontrol,
    220			     struct snd_ctl_elem_value *ucontrol)
    221{
    222	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    223	unsigned int channels = scontrol->num_channels;
    224	unsigned int i;
    225
    226	snd_sof_refresh_control(scontrol);
    227
    228	/* read back each channel */
    229	for (i = 0; i < channels; i++)
    230		ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
    231
    232	return 0;
    233}
    234
    235static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol,
    236			      struct snd_ctl_elem_value *ucontrol)
    237{
    238	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    239	struct snd_soc_component *scomp = scontrol->scomp;
    240	unsigned int channels = scontrol->num_channels;
    241	unsigned int i;
    242	bool change = false;
    243	u32 value;
    244
    245	/* update each channel */
    246	for (i = 0; i < channels; i++) {
    247		value = ucontrol->value.enumerated.item[i];
    248		change = change || (value != cdata->chanv[i].value);
    249		cdata->chanv[i].channel = i;
    250		cdata->chanv[i].value = value;
    251	}
    252
    253	/* notify DSP of enum updates */
    254	if (pm_runtime_active(scomp->dev)) {
    255		int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
    256
    257		if (ret < 0) {
    258			dev_err(scomp->dev, "Failed to set enum updates for %s\n",
    259				scontrol->name);
    260			return false;
    261		}
    262	}
    263
    264	return change;
    265}
    266
    267static int sof_ipc3_bytes_get(struct snd_sof_control *scontrol,
    268			      struct snd_ctl_elem_value *ucontrol)
    269{
    270	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    271	struct snd_soc_component *scomp = scontrol->scomp;
    272	struct sof_abi_hdr *data = cdata->data;
    273	size_t size;
    274
    275	snd_sof_refresh_control(scontrol);
    276
    277	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
    278		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
    279				    scontrol->max_size);
    280		return -EINVAL;
    281	}
    282
    283	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
    284	if (data->size > scontrol->max_size - sizeof(*data)) {
    285		dev_err_ratelimited(scomp->dev,
    286				    "%u bytes of control data is invalid, max is %zu\n",
    287				    data->size, scontrol->max_size - sizeof(*data));
    288		return -EINVAL;
    289	}
    290
    291	size = data->size + sizeof(*data);
    292
    293	/* copy back to kcontrol */
    294	memcpy(ucontrol->value.bytes.data, data, size);
    295
    296	return 0;
    297}
    298
    299static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
    300			      struct snd_ctl_elem_value *ucontrol)
    301{
    302	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    303	struct snd_soc_component *scomp = scontrol->scomp;
    304	struct sof_abi_hdr *data = cdata->data;
    305	size_t size;
    306
    307	if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) {
    308		dev_err_ratelimited(scomp->dev, "data max %zu exceeds ucontrol data array size\n",
    309				    scontrol->max_size);
    310		return -EINVAL;
    311	}
    312
    313	/* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */
    314	if (data->size > scontrol->max_size - sizeof(*data)) {
    315		dev_err_ratelimited(scomp->dev, "data size too big %u bytes max is %zu\n",
    316				    data->size, scontrol->max_size - sizeof(*data));
    317		return -EINVAL;
    318	}
    319
    320	size = data->size + sizeof(*data);
    321
    322	/* copy from kcontrol */
    323	memcpy(data, ucontrol->value.bytes.data, size);
    324
    325	/* notify DSP of byte control updates */
    326	if (pm_runtime_active(scomp->dev))
    327		return sof_ipc3_set_get_kcontrol_data(scontrol, true);
    328
    329	return 0;
    330}
    331
    332static int sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
    333				  const unsigned int __user *binary_data, unsigned int size)
    334{
    335	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
    336	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    337	struct snd_soc_component *scomp = scontrol->scomp;
    338	struct snd_ctl_tlv header;
    339	size_t data_size;
    340
    341	snd_sof_refresh_control(scontrol);
    342
    343	/*
    344	 * Decrement the limit by ext bytes header size to
    345	 * ensure the user space buffer is not exceeded.
    346	 */
    347	if (size < sizeof(struct snd_ctl_tlv))
    348		return -ENOSPC;
    349
    350	size -= sizeof(struct snd_ctl_tlv);
    351
    352	/* set the ABI header values */
    353	cdata->data->magic = SOF_ABI_MAGIC;
    354	cdata->data->abi = SOF_ABI_VERSION;
    355
    356	/* check data size doesn't exceed max coming from topology */
    357	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
    358		dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
    359				    cdata->data->size,
    360				    scontrol->max_size - sizeof(struct sof_abi_hdr));
    361		return -EINVAL;
    362	}
    363
    364	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
    365
    366	/* make sure we don't exceed size provided by user space for data */
    367	if (data_size > size)
    368		return -ENOSPC;
    369
    370	header.numid = cdata->cmd;
    371	header.length = data_size;
    372	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
    373		return -EFAULT;
    374
    375	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
    376		return -EFAULT;
    377
    378	return 0;
    379}
    380
    381static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
    382				  const unsigned int __user *binary_data,
    383				  unsigned int size)
    384{
    385	const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data;
    386	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    387	struct snd_soc_component *scomp = scontrol->scomp;
    388	struct snd_ctl_tlv header;
    389
    390	/*
    391	 * The beginning of bytes data contains a header from where
    392	 * the length (as bytes) is needed to know the correct copy
    393	 * length of data from tlvd->tlv.
    394	 */
    395	if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv)))
    396		return -EFAULT;
    397
    398	/* make sure TLV info is consistent */
    399	if (header.length + sizeof(struct snd_ctl_tlv) > size) {
    400		dev_err_ratelimited(scomp->dev, "Inconsistent TLV, data %d + header %zu > %d\n",
    401				    header.length, sizeof(struct snd_ctl_tlv), size);
    402		return -EINVAL;
    403	}
    404
    405	/* be->max is coming from topology */
    406	if (header.length > scontrol->max_size) {
    407		dev_err_ratelimited(scomp->dev, "Bytes data size %d exceeds max %zu\n",
    408				    header.length, scontrol->max_size);
    409		return -EINVAL;
    410	}
    411
    412	/* Check that header id matches the command */
    413	if (header.numid != cdata->cmd) {
    414		dev_err_ratelimited(scomp->dev, "Incorrect command for bytes put %d\n",
    415				    header.numid);
    416		return -EINVAL;
    417	}
    418
    419	if (copy_from_user(cdata->data, tlvd->tlv, header.length))
    420		return -EFAULT;
    421
    422	if (cdata->data->magic != SOF_ABI_MAGIC) {
    423		dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic);
    424		return -EINVAL;
    425	}
    426
    427	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
    428		dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n",
    429				    cdata->data->abi);
    430		return -EINVAL;
    431	}
    432
    433	/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */
    434	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
    435		dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n");
    436		return -EINVAL;
    437	}
    438
    439	/* notify DSP of byte control updates */
    440	if (pm_runtime_active(scomp->dev))
    441		return sof_ipc3_set_get_kcontrol_data(scontrol, true);
    442
    443	return 0;
    444}
    445
    446static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
    447					   const unsigned int __user *binary_data,
    448					   unsigned int size)
    449{
    450	struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
    451	struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
    452	struct snd_soc_component *scomp = scontrol->scomp;
    453	struct snd_ctl_tlv header;
    454	size_t data_size;
    455	int ret;
    456
    457	/*
    458	 * Decrement the limit by ext bytes header size to
    459	 * ensure the user space buffer is not exceeded.
    460	 */
    461	if (size < sizeof(struct snd_ctl_tlv))
    462		return -ENOSPC;
    463
    464	size -= sizeof(struct snd_ctl_tlv);
    465
    466	/* set the ABI header values */
    467	cdata->data->magic = SOF_ABI_MAGIC;
    468	cdata->data->abi = SOF_ABI_VERSION;
    469
    470	/* get all the component data from DSP */
    471	ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
    472	if (ret < 0)
    473		return ret;
    474
    475	/* check data size doesn't exceed max coming from topology */
    476	if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) {
    477		dev_err_ratelimited(scomp->dev, "User data size %d exceeds max size %zu\n",
    478				    cdata->data->size,
    479				    scontrol->max_size - sizeof(struct sof_abi_hdr));
    480		return -EINVAL;
    481	}
    482
    483	data_size = cdata->data->size + sizeof(struct sof_abi_hdr);
    484
    485	/* make sure we don't exceed size provided by user space for data */
    486	if (data_size > size)
    487		return -ENOSPC;
    488
    489	header.numid = cdata->cmd;
    490	header.length = data_size;
    491	if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv)))
    492		return -EFAULT;
    493
    494	if (copy_to_user(tlvd->tlv, cdata->data, data_size))
    495		return -EFAULT;
    496
    497	return ret;
    498}
    499
    500static void snd_sof_update_control(struct snd_sof_control *scontrol,
    501				   struct sof_ipc_ctrl_data *cdata)
    502{
    503	struct snd_soc_component *scomp = scontrol->scomp;
    504	struct sof_ipc_ctrl_data *local_cdata;
    505	int i;
    506
    507	local_cdata = scontrol->ipc_control_data;
    508
    509	if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
    510		if (cdata->num_elems != local_cdata->data->size) {
    511			dev_err(scomp->dev, "cdata binary size mismatch %u - %u\n",
    512				cdata->num_elems, local_cdata->data->size);
    513			return;
    514		}
    515
    516		/* copy the new binary data */
    517		memcpy(local_cdata->data, cdata->data, cdata->num_elems);
    518	} else if (cdata->num_elems != scontrol->num_channels) {
    519		dev_err(scomp->dev, "cdata channel count mismatch %u - %d\n",
    520			cdata->num_elems, scontrol->num_channels);
    521	} else {
    522		/* copy the new values */
    523		for (i = 0; i < cdata->num_elems; i++)
    524			local_cdata->chanv[i].value = cdata->chanv[i].value;
    525	}
    526}
    527
    528static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_message)
    529{
    530	struct sof_ipc_ctrl_data *cdata = ipc_control_message;
    531	struct snd_soc_dapm_widget *widget;
    532	struct snd_sof_control *scontrol;
    533	struct snd_sof_widget *swidget;
    534	struct snd_kcontrol *kc = NULL;
    535	struct soc_mixer_control *sm;
    536	struct soc_bytes_ext *be;
    537	size_t expected_size;
    538	struct soc_enum *se;
    539	bool found = false;
    540	int i, type;
    541
    542	if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET ||
    543	    cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) {
    544		dev_err(sdev->dev, "Component data is not supported in control notification\n");
    545		return;
    546	}
    547
    548	/* Find the swidget first */
    549	list_for_each_entry(swidget, &sdev->widget_list, list) {
    550		if (swidget->comp_id == cdata->comp_id) {
    551			found = true;
    552			break;
    553		}
    554	}
    555
    556	if (!found)
    557		return;
    558
    559	/* Translate SOF cmd to TPLG type */
    560	switch (cdata->cmd) {
    561	case SOF_CTRL_CMD_VOLUME:
    562	case SOF_CTRL_CMD_SWITCH:
    563		type = SND_SOC_TPLG_TYPE_MIXER;
    564		break;
    565	case SOF_CTRL_CMD_BINARY:
    566		type = SND_SOC_TPLG_TYPE_BYTES;
    567		break;
    568	case SOF_CTRL_CMD_ENUM:
    569		type = SND_SOC_TPLG_TYPE_ENUM;
    570		break;
    571	default:
    572		dev_err(sdev->dev, "Unknown cmd %u in %s\n", cdata->cmd, __func__);
    573		return;
    574	}
    575
    576	widget = swidget->widget;
    577	for (i = 0; i < widget->num_kcontrols; i++) {
    578		/* skip non matching types or non matching indexes within type */
    579		if (widget->dobj.widget.kcontrol_type[i] == type &&
    580		    widget->kcontrol_news[i].index == cdata->index) {
    581			kc = widget->kcontrols[i];
    582			break;
    583		}
    584	}
    585
    586	if (!kc)
    587		return;
    588
    589	switch (cdata->cmd) {
    590	case SOF_CTRL_CMD_VOLUME:
    591	case SOF_CTRL_CMD_SWITCH:
    592		sm = (struct soc_mixer_control *)kc->private_value;
    593		scontrol = sm->dobj.private;
    594		break;
    595	case SOF_CTRL_CMD_BINARY:
    596		be = (struct soc_bytes_ext *)kc->private_value;
    597		scontrol = be->dobj.private;
    598		break;
    599	case SOF_CTRL_CMD_ENUM:
    600		se = (struct soc_enum *)kc->private_value;
    601		scontrol = se->dobj.private;
    602		break;
    603	default:
    604		return;
    605	}
    606
    607	expected_size = sizeof(struct sof_ipc_ctrl_data);
    608	switch (cdata->type) {
    609	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
    610	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
    611		expected_size += cdata->num_elems *
    612				 sizeof(struct sof_ipc_ctrl_value_chan);
    613		break;
    614	case SOF_CTRL_TYPE_DATA_GET:
    615	case SOF_CTRL_TYPE_DATA_SET:
    616		expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr);
    617		break;
    618	default:
    619		return;
    620	}
    621
    622	if (cdata->rhdr.hdr.size != expected_size) {
    623		dev_err(sdev->dev, "Component notification size mismatch\n");
    624		return;
    625	}
    626
    627	if (cdata->num_elems)
    628		/*
    629		 * The message includes the updated value/data, update the
    630		 * control's local cache using the received notification
    631		 */
    632		snd_sof_update_control(scontrol, cdata);
    633	else
    634		/* Mark the scontrol that the value/data is changed in SOF */
    635		scontrol->comp_data_dirty = true;
    636
    637	snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
    638}
    639
    640static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev,
    641					  struct snd_sof_widget *swidget)
    642{
    643	struct snd_sof_control *scontrol;
    644	int ret;
    645
    646	/* set up all controls for the widget */
    647	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
    648		if (scontrol->comp_id == swidget->comp_id) {
    649			/* set kcontrol data in DSP */
    650			ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
    651			if (ret < 0) {
    652				dev_err(sdev->dev,
    653					"kcontrol %d set up failed for widget %s\n",
    654					scontrol->comp_id, swidget->widget->name);
    655				return ret;
    656			}
    657
    658			/*
    659			 * Read back the data from the DSP for static widgets.
    660			 * This is particularly useful for binary kcontrols
    661			 * associated with static pipeline widgets to initialize
    662			 * the data size to match that in the DSP.
    663			 */
    664			if (swidget->dynamic_pipeline_widget)
    665				continue;
    666
    667			ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
    668			if (ret < 0)
    669				dev_warn(sdev->dev,
    670					 "kcontrol %d read failed for widget %s\n",
    671					 scontrol->comp_id, swidget->widget->name);
    672		}
    673
    674	return 0;
    675}
    676
    677static int
    678sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
    679{
    680	int i;
    681
    682	/* init the volume table */
    683	scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
    684	if (!scontrol->volume_table)
    685		return -ENOMEM;
    686
    687	/* populate the volume table */
    688	for (i = 0; i < size ; i++)
    689		scontrol->volume_table[i] = vol_compute_gain(i, tlv);
    690
    691	return 0;
    692}
    693
    694const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
    695	.volume_put = sof_ipc3_volume_put,
    696	.volume_get = sof_ipc3_volume_get,
    697	.switch_put = sof_ipc3_switch_put,
    698	.switch_get = sof_ipc3_switch_get,
    699	.enum_put = sof_ipc3_enum_put,
    700	.enum_get = sof_ipc3_enum_get,
    701	.bytes_put = sof_ipc3_bytes_put,
    702	.bytes_get = sof_ipc3_bytes_get,
    703	.bytes_ext_put = sof_ipc3_bytes_ext_put,
    704	.bytes_ext_get = sof_ipc3_bytes_ext_get,
    705	.bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
    706	.update = sof_ipc3_control_update,
    707	.widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup,
    708	.set_up_volume_table = sof_ipc3_set_up_volume_table,
    709};