1313#include "ipc4-topology.h"
1414
1515static int sof_ipc4_set_get_kcontrol_data (struct snd_sof_control * scontrol ,
16- bool set , bool lock )
16+ bool set , bool lock ,
17+ void * data_ptr , size_t data_size )
1718{
1819 struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
1920 struct snd_soc_component * scomp = scontrol -> scomp ;
@@ -50,6 +51,14 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
5051 if (!swidget -> use_count )
5152 goto unlock ;
5253
54+ /*
55+ * Set the data pointer and size on the msg under the mutex to prevent
56+ * concurrent callers (e.g. widget setup vs userspace volume_put) from
57+ * overwriting each other's data fields on the shared cdata->msg.
58+ */
59+ msg -> data_ptr = data_ptr ;
60+ msg -> data_size = data_size ;
61+
5362 msg -> primary &= ~SOF_IPC4_MOD_INSTANCE_MASK ;
5463 msg -> primary |= SOF_IPC4_MOD_INSTANCE (swidget -> instance_id );
5564
@@ -60,7 +69,7 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
6069 /* It is a set-data operation, and we have a valid backup that we can restore */
6170 if (ret < 0 ) {
6271 if (!scontrol -> old_ipc_control_data )
63- goto unlock ;
72+ goto clear ;
6473 /*
6574 * Current ipc_control_data is not valid, we use the last known good
6675 * configuration
@@ -69,12 +78,21 @@ static int sof_ipc4_set_get_kcontrol_data(struct snd_sof_control *scontrol,
6978 scontrol -> size );
7079 kfree (scontrol -> old_ipc_control_data );
7180 scontrol -> old_ipc_control_data = NULL ;
81+ /*
82+ * The memcpy above overwrites cdata->msg, restore the data
83+ * fields from the function arguments for the retry.
84+ */
85+ msg -> data_ptr = data_ptr ;
86+ msg -> data_size = data_size ;
7287 /* Send the last known good configuration to firmware */
7388 ret = iops -> set_get_data (sdev , msg , msg -> data_size , set );
74- if (ret < 0 )
75- goto unlock ;
7689 }
7790
91+ clear :
92+ /* Clear data fields for set operations to avoid dangling pointers */
93+ msg -> data_ptr = NULL ;
94+ msg -> data_size = 0 ;
95+
7896unlock :
7997 if (lock )
8098 mutex_unlock (& swidget -> setup_mutex );
@@ -88,7 +106,6 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
88106{
89107 struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
90108 struct sof_ipc4_gain * gain = swidget -> private ;
91- struct sof_ipc4_msg * msg = & cdata -> msg ;
92109 struct sof_ipc4_gain_params params ;
93110 bool all_channels_equal = true;
94111 u32 value ;
@@ -121,12 +138,8 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
121138 params .curve_duration_h = gain -> data .params .curve_duration_h ;
122139 params .curve_type = gain -> data .params .curve_type ;
123140
124- msg -> data_ptr = & params ;
125- msg -> data_size = sizeof (params );
126-
127- ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock );
128- msg -> data_ptr = NULL ;
129- msg -> data_size = 0 ;
141+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock ,
142+ & params , sizeof (params ));
130143 if (ret < 0 ) {
131144 dev_err (sdev -> dev , "Failed to set volume update for %s\n" ,
132145 scontrol -> name );
@@ -208,7 +221,6 @@ sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev,
208221{
209222 struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
210223 struct sof_ipc4_control_msg_payload * data ;
211- struct sof_ipc4_msg * msg = & cdata -> msg ;
212224 size_t data_size ;
213225 unsigned int i ;
214226 int ret ;
@@ -225,12 +237,8 @@ sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev,
225237 data -> chanv [i ].value = cdata -> chanv [i ].value ;
226238 }
227239
228- msg -> data_ptr = data ;
229- msg -> data_size = data_size ;
230-
231- ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock );
232- msg -> data_ptr = NULL ;
233- msg -> data_size = 0 ;
240+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock ,
241+ data , data_size );
234242 if (ret < 0 )
235243 dev_err (sdev -> dev , "Failed to set control update for %s\n" ,
236244 scontrol -> name );
@@ -245,7 +253,6 @@ static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol)
245253 struct sof_ipc4_control_data * cdata = scontrol -> ipc_control_data ;
246254 struct snd_soc_component * scomp = scontrol -> scomp ;
247255 struct sof_ipc4_control_msg_payload * data ;
248- struct sof_ipc4_msg * msg = & cdata -> msg ;
249256 size_t data_size ;
250257 unsigned int i ;
251258 int ret ;
@@ -263,13 +270,10 @@ static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol)
263270
264271 data -> id = cdata -> index ;
265272 data -> num_elems = scontrol -> num_channels ;
266- msg -> data_ptr = data ;
267- msg -> data_size = data_size ;
268273
269274 scontrol -> comp_data_dirty = false;
270- ret = sof_ipc4_set_get_kcontrol_data (scontrol , false, true);
271- msg -> data_ptr = NULL ;
272- msg -> data_size = 0 ;
275+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , false, true,
276+ data , data_size );
273277 if (!ret ) {
274278 for (i = 0 ; i < scontrol -> num_channels ; i ++ ) {
275279 cdata -> chanv [i ].channel = data -> chanv [i ].channel ;
@@ -306,12 +310,8 @@ sof_ipc4_set_bytes_control_data(struct snd_sof_control *scontrol, bool lock)
306310
307311 msg -> extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID (data -> type );
308312
309- msg -> data_ptr = msg_data ;
310- msg -> data_size = data_size ;
311-
312- ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock );
313- msg -> data_ptr = NULL ;
314- msg -> data_size = 0 ;
313+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , true, lock ,
314+ msg_data , data_size );
315315 if (ret < 0 )
316316 dev_err (scomp -> dev , "%s: Failed to set control update for %s\n" ,
317317 __func__ , scontrol -> name );
@@ -351,11 +351,9 @@ sof_ipc4_refresh_bytes_control(struct snd_sof_control *scontrol, bool lock)
351351 msg_data -> id = cdata -> index ;
352352 msg_data -> num_elems = 0 ; /* ignored for bytes */
353353
354- msg -> data_ptr = msg_data ;
355- msg -> data_size = data_size ;
356-
357354 scontrol -> comp_data_dirty = false;
358- ret = sof_ipc4_set_get_kcontrol_data (scontrol , false, lock );
355+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , false, lock ,
356+ msg_data , data_size );
359357 if (!ret ) {
360358 if (msg -> data_size > scontrol -> max_size - sizeof (* data )) {
361359 dev_err (scomp -> dev ,
@@ -532,13 +530,10 @@ static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
532530
533531 msg -> extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID (data -> type );
534532
535- msg -> data_ptr = data -> data ;
536- if (set )
537- msg -> data_size = data -> size ;
538- else
539- msg -> data_size = scontrol -> max_size - sizeof (* data );
540-
541- ret = sof_ipc4_set_get_kcontrol_data (scontrol , set , lock );
533+ ret = sof_ipc4_set_get_kcontrol_data (scontrol , set , lock ,
534+ data -> data ,
535+ set ? data -> size :
536+ scontrol -> max_size - sizeof (* data ));
542537 if (ret < 0 ) {
543538 dev_err (sdev -> dev , "Failed to %s for %s\n" ,
544539 set ? "set bytes update" : "get bytes" ,
@@ -549,9 +544,6 @@ static int sof_ipc4_set_get_bytes_data(struct snd_sof_dev *sdev,
549544 scontrol -> size = sizeof (* cdata ) + sizeof (* data ) + data -> size ;
550545 }
551546
552- msg -> data_ptr = NULL ;
553- msg -> data_size = 0 ;
554-
555547 return ret ;
556548}
557549
0 commit comments