Unverified Commit d96cb0b8 authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown
Browse files

ASoC: SOF: ipc4: Support for sending payload along with LARGE_CONFIG_GET



There are message types when we would need to send a payload along with
the LARGE_CONFIG_GET message to provide information to the firmware on
what data is requested.
Such cases are the ALSA Kcontrol related messages when the high level
param_id tells only the type of the control, but the ID/index of the exact
control is specified in the payload area.

The caller must place the payload for TX before calling the set_get_data()
and this payload will be sent alongside with the message to the firmware.

The data area will be overwritten by the received data from firmware.

Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarSeppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://patch.msgid.link/20251217143945.2667-7-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2fdde18a
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "sof-audio.h"
#include "ipc4-fw-reg.h"
#include "ipc4-priv.h"
#include "ipc4-topology.h"
#include "ipc4-telemetry.h"
#include "ops.h"

@@ -433,6 +434,23 @@ static int sof_ipc4_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_
	return ret;
}

static bool sof_ipc4_tx_payload_for_get_data(struct sof_ipc4_msg *tx)
{
	/*
	 * Messages that require TX payload with LARGE_CONFIG_GET.
	 * The TX payload is placed into the IPC message data section by caller,
	 * which needs to be copied to temporary buffer since the received data
	 * will overwrite it.
	 */
	switch (tx->extension & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) {
	case SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_SWITCH_CONTROL_PARAM_ID):
	case SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_ENUM_CONTROL_PARAM_ID):
		return true;
	default:
		return false;
	}
}

static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,
				 size_t payload_bytes, bool set)
{
@@ -444,6 +462,8 @@ static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,
	struct sof_ipc4_msg tx = {{ 0 }};
	struct sof_ipc4_msg rx = {{ 0 }};
	size_t remaining = payload_bytes;
	void *tx_payload_for_get = NULL;
	size_t tx_data_size = 0;
	size_t offset = 0;
	size_t chunk_size;
	int ret;
@@ -469,10 +489,20 @@ static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,

	tx.extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1);

	if (sof_ipc4_tx_payload_for_get_data(&tx)) {
		tx_data_size = min(ipc4_msg->data_size, payload_limit);
		tx_payload_for_get = kmemdup(ipc4_msg->data_ptr, tx_data_size,
					     GFP_KERNEL);
		if (!tx_payload_for_get)
			return -ENOMEM;
	}

	/* ensure the DSP is in D0i0 before sending IPC */
	ret = snd_sof_dsp_set_power_state(sdev, &target_state);
	if (ret < 0)
	if (ret < 0) {
		kfree(tx_payload_for_get);
		return ret;
	}

	/* Serialise IPC TX */
	mutex_lock(&sdev->ipc->tx_mutex);
@@ -506,7 +536,15 @@ static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,
			rx.data_size = chunk_size;
			rx.data_ptr = ipc4_msg->data_ptr + offset;

			if (tx_payload_for_get) {
				tx_size = tx_data_size;
				tx.data_size = tx_size;
				tx.data_ptr = tx_payload_for_get;
			} else {
				tx_size = 0;
				tx.data_size = 0;
				tx.data_ptr = NULL;
			}
			rx_size = chunk_size;
		}

@@ -553,6 +591,8 @@ static int sof_ipc4_set_get_data(struct snd_sof_dev *sdev, void *data,

	mutex_unlock(&sdev->ipc->tx_mutex);

	kfree(tx_payload_for_get);

	return ret;
}