Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve support for sof_ipc{3|4}_bytes_ext_put

Merge series from Daniel Baluta <daniel.baluta@oss.nxp.com>:

This patch series provides better handling of cases where sending
a data blob to FW results in a validation error.

In this case we restore to the last good known value instead of keeping
the data that firwmare rejected.

+84 -10
+48 -6
sound/soc/sof/ipc3-control.c
··· 96 96 cdata->elems_remaining = 0; 97 97 98 98 ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); 99 + if (!set) 100 + goto unlock; 101 + 102 + /* It is a set-data operation, and we have a backup that we can restore */ 103 + if (ret < 0) { 104 + if (!scontrol->old_ipc_control_data) 105 + goto unlock; 106 + /* 107 + * Current ipc_control_data is not valid, we use the last known good 108 + * configuration 109 + */ 110 + memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, 111 + scontrol->max_size); 112 + kfree(scontrol->old_ipc_control_data); 113 + scontrol->old_ipc_control_data = NULL; 114 + /* Send the last known good configuration to firmware */ 115 + ret = iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); 116 + if (ret < 0) 117 + goto unlock; 118 + } 99 119 100 120 unlock: 101 121 if (lock) ··· 371 351 struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; 372 352 struct snd_soc_component *scomp = scontrol->scomp; 373 353 struct snd_ctl_tlv header; 354 + int ret = -EINVAL; 374 355 375 356 /* 376 357 * The beginning of bytes data contains a header from where ··· 402 381 return -EINVAL; 403 382 } 404 383 405 - if (copy_from_user(cdata->data, tlvd->tlv, header.length)) 406 - return -EFAULT; 384 + if (!scontrol->old_ipc_control_data) { 385 + /* Create a backup of the current, valid bytes control */ 386 + scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data, 387 + scontrol->max_size, GFP_KERNEL); 388 + if (!scontrol->old_ipc_control_data) 389 + return -ENOMEM; 390 + } 391 + 392 + if (copy_from_user(cdata->data, tlvd->tlv, header.length)) { 393 + ret = -EFAULT; 394 + goto err_restore; 395 + } 407 396 408 397 if (cdata->data->magic != SOF_ABI_MAGIC) { 409 398 dev_err_ratelimited(scomp->dev, "Wrong ABI magic 0x%08x\n", cdata->data->magic); 410 - return -EINVAL; 399 + goto err_restore; 411 400 } 412 401 413 402 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { 414 403 dev_err_ratelimited(scomp->dev, "Incompatible ABI version 0x%08x\n", 415 404 cdata->data->abi); 416 - return -EINVAL; 405 + goto err_restore; 417 406 } 418 407 419 408 /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ 420 409 if (cdata->data->size > scontrol->max_size - sizeof(struct sof_abi_hdr)) { 421 410 dev_err_ratelimited(scomp->dev, "Mismatch in ABI data size (truncated?)\n"); 422 - return -EINVAL; 411 + goto err_restore; 423 412 } 424 413 425 414 /* notify DSP of byte control updates */ 426 - if (pm_runtime_active(scomp->dev)) 415 + if (pm_runtime_active(scomp->dev)) { 416 + /* Actually send the data to the DSP; this is an opportunity to validate the data */ 427 417 return sof_ipc3_set_get_kcontrol_data(scontrol, true, true); 418 + } 428 419 429 420 return 0; 421 + 422 + err_restore: 423 + /* If we have an issue, we restore the old, valid bytes control data */ 424 + if (scontrol->old_ipc_control_data) { 425 + memcpy(cdata->data, scontrol->old_ipc_control_data, scontrol->max_size); 426 + kfree(scontrol->old_ipc_control_data); 427 + scontrol->old_ipc_control_data = NULL; 428 + } 429 + return ret; 430 430 } 431 431 432 432 static int _sof_ipc3_bytes_ext_get(struct snd_sof_control *scontrol,
+35 -4
sound/soc/sof/ipc4-control.c
··· 54 54 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 55 55 56 56 ret = iops->set_get_data(sdev, msg, msg->data_size, set); 57 + if (!set) 58 + goto unlock; 59 + 60 + /* It is a set-data operation, and we have a valid backup that we can restore */ 61 + if (ret < 0) { 62 + if (!scontrol->old_ipc_control_data) 63 + goto unlock; 64 + /* 65 + * Current ipc_control_data is not valid, we use the last known good 66 + * configuration 67 + */ 68 + memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, 69 + scontrol->max_size); 70 + kfree(scontrol->old_ipc_control_data); 71 + scontrol->old_ipc_control_data = NULL; 72 + /* Send the last known good configuration to firmware */ 73 + ret = iops->set_get_data(sdev, msg, msg->data_size, set); 74 + if (ret < 0) 75 + goto unlock; 76 + } 57 77 58 78 unlock: 59 79 if (lock) ··· 347 327 return -EINVAL; 348 328 } 349 329 330 + if (!scontrol->old_ipc_control_data) { 331 + /* Create a backup of the current, valid bytes control */ 332 + scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data, 333 + scontrol->max_size, GFP_KERNEL); 334 + if (!scontrol->old_ipc_control_data) 335 + return -ENOMEM; 336 + } 337 + 350 338 /* Copy the whole binary data which includes the ABI header and the payload */ 351 - if (copy_from_user(data, tlvd->tlv, header.length)) 339 + if (copy_from_user(data, tlvd->tlv, header.length)) { 340 + memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, 341 + scontrol->max_size); 342 + kfree(scontrol->old_ipc_control_data); 343 + scontrol->old_ipc_control_data = NULL; 352 344 return -EFAULT; 345 + } 353 346 354 - sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); 355 - 356 - return 0; 347 + return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); 357 348 } 358 349 359 350 static int _sof_ipc4_bytes_ext_get(struct snd_sof_control *scontrol,
+1
sound/soc/sof/sof-audio.h
··· 362 362 size_t priv_size; /* size of private data */ 363 363 size_t max_size; 364 364 void *ipc_control_data; 365 + void *old_ipc_control_data; 365 366 int max; /* applicable to volume controls */ 366 367 u32 size; /* cdata size */ 367 368 u32 *volume_table; /* volume table computed from tlv data*/