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.

ASoC: SOF: ipoc4: Support for generic bytes

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

We support bytes control type for set and get, but these are module specific
controls and there is no way to handle notifications from them in a generic way.
Each control have module specific param_id and this param_id is only valid in
the module's scope, other modules might use the same id for different functions
for example.

This series will add a new generic control type, similar to the existing ones
for ENUM and SWITCH, which can be used to create bytes controls which can send
notifications from firmware on change.

The new param_id is 202 and the sof_ipc4_control_msg_payload is updated to
describe bytes payload also.

On set, the payload must include the sof_ipc4_control_msg_payload struct with
the control's ID and data size, followed by the data.

On get, the kernel needs to send the sof_ipc4_control_msg_payload struct along
with the LARGE_CONFIG_GET message as payload with the ID of the control that
needs to be retrieved. The raw data is received back without additional header.

A notification might contain data, in this case the num_elems reflects the size
in bytes, or without data. If no data is received then the control is marked as
dirty and on read the kernel will refresh the data from firmware.

The series includes mandatory fixes for existing code and adds support for
sending payload with LARGE_CONFIG_GET when the param_id is either generic ENUM,
SWITCH or BYTES control.

+251 -34
+173 -22
sound/soc/sof/ipc4-control.c
··· 66 66 * configuration 67 67 */ 68 68 memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, 69 - scontrol->max_size); 69 + scontrol->size); 70 70 kfree(scontrol->old_ipc_control_data); 71 71 scontrol->old_ipc_control_data = NULL; 72 72 /* Send the last known good configuration to firmware */ ··· 284 284 kfree(data); 285 285 } 286 286 287 + static int 288 + sof_ipc4_set_bytes_control_data(struct snd_sof_control *scontrol, bool lock) 289 + { 290 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 291 + struct snd_soc_component *scomp = scontrol->scomp; 292 + struct sof_ipc4_control_msg_payload *msg_data; 293 + struct sof_abi_hdr *data = cdata->data; 294 + struct sof_ipc4_msg *msg = &cdata->msg; 295 + size_t data_size; 296 + int ret; 297 + 298 + data_size = struct_size(msg_data, data, data->size); 299 + msg_data = kzalloc(data_size, GFP_KERNEL); 300 + if (!msg_data) 301 + return -ENOMEM; 302 + 303 + msg_data->id = cdata->index; 304 + msg_data->num_elems = data->size; 305 + memcpy(msg_data->data, data->data, data->size); 306 + 307 + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type); 308 + 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; 315 + if (ret < 0) 316 + dev_err(scomp->dev, "%s: Failed to set control update for %s\n", 317 + __func__, scontrol->name); 318 + 319 + kfree(msg_data); 320 + 321 + return ret; 322 + } 323 + 324 + static int 325 + sof_ipc4_refresh_bytes_control(struct snd_sof_control *scontrol, bool lock) 326 + { 327 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 328 + struct snd_soc_component *scomp = scontrol->scomp; 329 + struct sof_ipc4_control_msg_payload *msg_data; 330 + struct sof_abi_hdr *data = cdata->data; 331 + struct sof_ipc4_msg *msg = &cdata->msg; 332 + size_t data_size; 333 + int ret = 0; 334 + 335 + if (!scontrol->comp_data_dirty) 336 + return 0; 337 + 338 + if (!pm_runtime_active(scomp->dev)) 339 + return 0; 340 + 341 + data_size = scontrol->max_size - sizeof(*data); 342 + if (data_size < sizeof(*msg_data)) 343 + data_size = sizeof(*msg_data); 344 + 345 + msg_data = kzalloc(data_size, GFP_KERNEL); 346 + if (!msg_data) 347 + return -ENOMEM; 348 + 349 + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type); 350 + 351 + msg_data->id = cdata->index; 352 + msg_data->num_elems = 0; /* ignored for bytes */ 353 + 354 + msg->data_ptr = msg_data; 355 + msg->data_size = data_size; 356 + 357 + scontrol->comp_data_dirty = false; 358 + ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, lock); 359 + if (!ret) { 360 + if (msg->data_size > scontrol->max_size - sizeof(*data)) { 361 + dev_err(scomp->dev, 362 + "%s: no space for data in %s (%zu, %zu)\n", 363 + __func__, scontrol->name, msg->data_size, 364 + scontrol->max_size - sizeof(*data)); 365 + goto out; 366 + } 367 + 368 + data->size = msg->data_size; 369 + scontrol->size = sizeof(*cdata) + sizeof(*data) + data->size; 370 + memcpy(data->data, msg->data_ptr, data->size); 371 + } else { 372 + dev_err(scomp->dev, "Failed to read control data for %s\n", 373 + scontrol->name); 374 + scontrol->comp_data_dirty = true; 375 + } 376 + 377 + out: 378 + msg->data_ptr = NULL; 379 + msg->data_size = 0; 380 + 381 + kfree(msg_data); 382 + 383 + return ret; 384 + } 385 + 287 386 static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol, 288 387 struct snd_ctl_elem_value *ucontrol) 289 388 { ··· 511 412 int ret = 0; 512 413 513 414 /* Send the new data to the firmware only if it is powered up */ 514 - if (set && !pm_runtime_active(sdev->dev)) 515 - return 0; 415 + if (set) { 416 + if (!pm_runtime_active(sdev->dev)) 417 + return 0; 418 + 419 + if (!data->size) { 420 + dev_dbg(sdev->dev, "%s: No data to be sent.\n", 421 + scontrol->name); 422 + return 0; 423 + } 424 + } 425 + 426 + if (data->type == SOF_IPC4_BYTES_CONTROL_PARAM_ID) { 427 + if (set) 428 + return sof_ipc4_set_bytes_control_data(scontrol, lock); 429 + else 430 + return sof_ipc4_refresh_bytes_control(scontrol, lock); 431 + } 516 432 517 433 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(data->type); 518 434 519 435 msg->data_ptr = data->data; 520 - msg->data_size = data->size; 436 + if (set) 437 + msg->data_size = data->size; 438 + else 439 + msg->data_size = scontrol->max_size - sizeof(*data); 521 440 522 441 ret = sof_ipc4_set_get_kcontrol_data(scontrol, set, lock); 523 - if (ret < 0) 442 + if (ret < 0) { 524 443 dev_err(sdev->dev, "Failed to %s for %s\n", 525 444 set ? "set bytes update" : "get bytes", 526 445 scontrol->name); 446 + } else if (!set) { 447 + /* Update the sizes according to the received payload data */ 448 + data->size = msg->data_size; 449 + scontrol->size = sizeof(*cdata) + sizeof(*data) + data->size; 450 + } 527 451 528 452 msg->data_ptr = NULL; 529 453 msg->data_size = 0; ··· 562 440 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 563 441 struct sof_abi_hdr *data = cdata->data; 564 442 size_t size; 443 + int ret; 565 444 566 445 if (scontrol->max_size > sizeof(ucontrol->value.bytes.data)) { 567 446 dev_err_ratelimited(scomp->dev, ··· 584 461 /* copy from kcontrol */ 585 462 memcpy(data, ucontrol->value.bytes.data, size); 586 463 587 - sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); 464 + ret = sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); 465 + if (!ret) 466 + /* Update the cdata size */ 467 + scontrol->size = sizeof(*cdata) + size; 588 468 589 - return 0; 469 + return ret; 590 470 } 591 471 592 472 static int sof_ipc4_bytes_get(struct snd_sof_control *scontrol, ··· 612 486 data->size, scontrol->max_size - sizeof(*data)); 613 487 return -EINVAL; 614 488 } 489 + 490 + sof_ipc4_refresh_bytes_control(scontrol, true); 615 491 616 492 size = data->size + sizeof(*data); 617 493 ··· 687 559 if (!scontrol->old_ipc_control_data) { 688 560 /* Create a backup of the current, valid bytes control */ 689 561 scontrol->old_ipc_control_data = kmemdup(scontrol->ipc_control_data, 690 - scontrol->max_size, GFP_KERNEL); 562 + scontrol->size, GFP_KERNEL); 691 563 if (!scontrol->old_ipc_control_data) 692 564 return -ENOMEM; 693 565 } ··· 695 567 /* Copy the whole binary data which includes the ABI header and the payload */ 696 568 if (copy_from_user(data, tlvd->tlv, header.length)) { 697 569 memcpy(scontrol->ipc_control_data, scontrol->old_ipc_control_data, 698 - scontrol->max_size); 570 + scontrol->size); 699 571 kfree(scontrol->old_ipc_control_data); 700 572 scontrol->old_ipc_control_data = NULL; 701 573 return -EFAULT; 702 574 } 575 + 576 + /* Update the cdata size */ 577 + scontrol->size = sizeof(*cdata) + header.length; 703 578 704 579 return sof_ipc4_set_get_bytes_data(sdev, scontrol, true, true); 705 580 } ··· 769 638 const unsigned int __user *binary_data, 770 639 unsigned int size) 771 640 { 641 + sof_ipc4_refresh_bytes_control(scontrol, true); 642 + 772 643 return _sof_ipc4_bytes_ext_get(scontrol, binary_data, size, false); 773 644 } 774 645 ··· 824 691 case SOF_IPC4_ENUM_CONTROL_PARAM_ID: 825 692 type = SND_SOC_TPLG_TYPE_ENUM; 826 693 break; 694 + case SOF_IPC4_BYTES_CONTROL_PARAM_ID: 695 + type = SND_SOC_TPLG_TYPE_BYTES; 696 + break; 827 697 default: 828 698 dev_err(sdev->dev, 829 699 "%s: Invalid control type for module %u.%u: %u\n", ··· 877 741 * The message includes the updated value/data, update the 878 742 * control's local cache using the received notification 879 743 */ 880 - for (i = 0; i < msg_data->num_elems; i++) { 881 - u32 channel = msg_data->chanv[i].channel; 744 + if (type == SND_SOC_TPLG_TYPE_BYTES) { 745 + struct sof_abi_hdr *data = cdata->data; 882 746 883 - if (channel >= scontrol->num_channels) { 747 + if (msg_data->num_elems > scontrol->max_size - sizeof(*data)) { 884 748 dev_warn(sdev->dev, 885 - "Invalid channel index for %s: %u\n", 886 - scontrol->name, i); 887 - 888 - /* 889 - * Mark the scontrol as dirty to force a refresh 890 - * on next read 891 - */ 892 - scontrol->comp_data_dirty = true; 893 - break; 749 + "%s: no space for data in %s (%u, %zu)\n", 750 + __func__, scontrol->name, msg_data->num_elems, 751 + scontrol->max_size - sizeof(*data)); 752 + } else { 753 + memcpy(data->data, msg_data->data, msg_data->num_elems); 754 + data->size = msg_data->num_elems; 755 + scontrol->size = sizeof(*cdata) + sizeof(*data) + data->size; 894 756 } 757 + } else { 758 + for (i = 0; i < msg_data->num_elems; i++) { 759 + u32 channel = msg_data->chanv[i].channel; 895 760 896 - cdata->chanv[channel].value = msg_data->chanv[i].value; 761 + if (channel >= scontrol->num_channels) { 762 + dev_warn(sdev->dev, 763 + "Invalid channel index for %s: %u\n", 764 + scontrol->name, i); 765 + 766 + /* 767 + * Mark the scontrol as dirty to force a refresh 768 + * on next read 769 + */ 770 + scontrol->comp_data_dirty = true; 771 + break; 772 + } 773 + 774 + cdata->chanv[channel].value = msg_data->chanv[i].value; 775 + } 897 776 } 898 777 } else { 899 778 /*
+28 -8
sound/soc/sof/ipc4-topology.c
··· 2855 2855 struct sof_ipc4_msg *msg; 2856 2856 int ret; 2857 2857 2858 - if (scontrol->max_size < (sizeof(*control_data) + sizeof(struct sof_abi_hdr))) { 2859 - dev_err(sdev->dev, "insufficient size for a bytes control %s: %zu.\n", 2858 + /* 2859 + * The max_size is coming from topology and indicates the maximum size 2860 + * of sof_abi_hdr plus the payload, which excludes the local only 2861 + * 'struct sof_ipc4_control_data' 2862 + */ 2863 + if (scontrol->max_size < sizeof(struct sof_abi_hdr)) { 2864 + dev_err(sdev->dev, 2865 + "insufficient maximum size for a bytes control %s: %zu.\n", 2860 2866 scontrol->name, scontrol->max_size); 2861 2867 return -EINVAL; 2862 2868 } 2863 2869 2864 - if (scontrol->priv_size > scontrol->max_size - sizeof(*control_data)) { 2865 - dev_err(sdev->dev, "scontrol %s bytes data size %zu exceeds max %zu.\n", 2866 - scontrol->name, scontrol->priv_size, 2867 - scontrol->max_size - sizeof(*control_data)); 2870 + if (scontrol->priv_size > scontrol->max_size) { 2871 + dev_err(sdev->dev, 2872 + "bytes control %s initial data size %zu exceeds max %zu.\n", 2873 + scontrol->name, scontrol->priv_size, scontrol->max_size); 2868 2874 return -EINVAL; 2869 2875 } 2870 2876 2871 - scontrol->size = sizeof(struct sof_ipc4_control_data) + scontrol->priv_size; 2877 + if (scontrol->priv_size < sizeof(struct sof_abi_hdr)) { 2878 + dev_err(sdev->dev, 2879 + "bytes control %s initial data size %zu is insufficient.\n", 2880 + scontrol->name, scontrol->priv_size); 2881 + return -EINVAL; 2882 + } 2872 2883 2873 - scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL); 2884 + /* 2885 + * The used size behind the cdata pointer, which can be smaller than 2886 + * the maximum size 2887 + */ 2888 + scontrol->size = sizeof(*control_data) + scontrol->priv_size; 2889 + 2890 + /* Allocate the cdata: local struct size + maximum payload size */ 2891 + scontrol->ipc_control_data = kzalloc(sizeof(*control_data) + scontrol->max_size, 2892 + GFP_KERNEL); 2874 2893 if (!scontrol->ipc_control_data) 2875 2894 return -ENOMEM; 2876 2895 ··· 2924 2905 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 2925 2906 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2926 2907 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2908 + msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(control_data->data->type); 2927 2909 2928 2910 return 0; 2929 2911
+7 -2
sound/soc/sof/ipc4-topology.h
··· 368 368 369 369 #define SOF_IPC4_SWITCH_CONTROL_PARAM_ID 200 370 370 #define SOF_IPC4_ENUM_CONTROL_PARAM_ID 201 371 + #define SOF_IPC4_BYTES_CONTROL_PARAM_ID 202 371 372 372 373 /** 373 374 * struct sof_ipc4_control_msg_payload - IPC payload for kcontrol parameters 374 375 * @id: unique id of the control 375 - * @num_elems: Number of elements in the chanv array 376 + * @num_elems: Number of elements in the chanv array or number of bytes in data 376 377 * @reserved: reserved for future use, must be set to 0 377 378 * @chanv: channel ID and value array 379 + * @data: binary payload 378 380 */ 379 381 struct sof_ipc4_control_msg_payload { 380 382 uint16_t id; 381 383 uint16_t num_elems; 382 384 uint32_t reserved[4]; 383 - DECLARE_FLEX_ARRAY(struct sof_ipc4_ctrl_value_chan, chanv); 385 + union { 386 + DECLARE_FLEX_ARRAY(struct sof_ipc4_ctrl_value_chan, chanv); 387 + DECLARE_FLEX_ARRAY(uint8_t, data); 388 + }; 384 389 } __packed; 385 390 386 391 /**
+43 -2
sound/soc/sof/ipc4.c
··· 15 15 #include "sof-audio.h" 16 16 #include "ipc4-fw-reg.h" 17 17 #include "ipc4-priv.h" 18 + #include "ipc4-topology.h" 18 19 #include "ipc4-telemetry.h" 19 20 #include "ops.h" 20 21 ··· 434 433 return ret; 435 434 } 436 435 436 + static bool sof_ipc4_tx_payload_for_get_data(struct sof_ipc4_msg *tx) 437 + { 438 + /* 439 + * Messages that require TX payload with LARGE_CONFIG_GET. 440 + * The TX payload is placed into the IPC message data section by caller, 441 + * which needs to be copied to temporary buffer since the received data 442 + * will overwrite it. 443 + */ 444 + switch (tx->extension & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) { 445 + case SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID): 446 + case SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID): 447 + case SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_BYTES_CONTROL_PARAM_ID): 448 + return true; 449 + default: 450 + return false; 451 + } 452 + } 453 + 437 454 static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data, 438 455 size_t payload_bytes, bool set) 439 456 { ··· 463 444 struct sof_ipc4_msg tx = {{ 0 }}; 464 445 struct sof_ipc4_msg rx = {{ 0 }}; 465 446 size_t remaining = payload_bytes; 447 + void *tx_payload_for_get = NULL; 448 + size_t tx_data_size = 0; 466 449 size_t offset = 0; 467 450 size_t chunk_size; 468 451 int ret; ··· 490 469 491 470 tx.extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1); 492 471 472 + if (sof_ipc4_tx_payload_for_get_data(&tx)) { 473 + tx_data_size = min(ipc4_msg->data_size, payload_limit); 474 + tx_payload_for_get = kmemdup(ipc4_msg->data_ptr, tx_data_size, 475 + GFP_KERNEL); 476 + if (!tx_payload_for_get) 477 + return -ENOMEM; 478 + } 479 + 493 480 /* ensure the DSP is in D0i0 before sending IPC */ 494 481 ret = snd_sof_dsp_set_power_state(sdev, &target_state); 495 - if (ret < 0) 482 + if (ret < 0) { 483 + kfree(tx_payload_for_get); 496 484 return ret; 485 + } 497 486 498 487 /* Serialise IPC TX */ 499 488 mutex_lock(&sdev->ipc->tx_mutex); ··· 537 506 rx.data_size = chunk_size; 538 507 rx.data_ptr = ipc4_msg->data_ptr + offset; 539 508 540 - tx_size = 0; 509 + if (tx_payload_for_get) { 510 + tx_size = tx_data_size; 511 + tx.data_size = tx_size; 512 + tx.data_ptr = tx_payload_for_get; 513 + } else { 514 + tx_size = 0; 515 + tx.data_size = 0; 516 + tx.data_ptr = NULL; 517 + } 541 518 rx_size = chunk_size; 542 519 } 543 520 ··· 591 552 sof_ipc4_dump_payload(sdev, ipc4_msg->data_ptr, ipc4_msg->data_size); 592 553 593 554 mutex_unlock(&sdev->ipc->tx_mutex); 555 + 556 + kfree(tx_payload_for_get); 594 557 595 558 return ret; 596 559 }