From b4dcafe45e46f107b5f65a004d49e11e56fe4f87 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:26:54 -0700 Subject: ASoC: SOF: Add helper function to prepare and send an IPC message The new sof_ipc_send_msg() can be used by IPC dependent code to prepare the ipc->msg for a new message transmission and then call in to platform code to send the message. Higher level code should be handling the completion and reply. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 55 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 17dd51d342cf..a78b74514438 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -340,6 +340,59 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, return tx_wait_done(ipc, msg, reply_data); } +/** + * sof_ipc_send_msg - generic function to prepare and send one IPC message + * @sdev: pointer to SOF core device struct + * @msg_data: pointer to a message to send + * @msg_bytes: number of bytes in the message + * @reply_bytes: number of bytes available for the reply. + * The buffer for the reply data is not passed to this + * function, the available size is an information for the + * reply handling functions. + * + * On success the function returns 0, otherwise negative error number. + * + * Note: higher level sdev->ipc->tx_mutex must be held to make sure that + * transfers are synchronized. + */ +int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, + size_t reply_bytes) +{ + struct snd_sof_ipc *ipc = sdev->ipc; + struct snd_sof_ipc_msg *msg; + int ret; + + if (ipc->disable_ipc_tx || sdev->fw_state != SOF_FW_BOOT_COMPLETE) + return -ENODEV; + + /* + * The spin-lock is needed to protect message objects against other + * atomic contexts. + */ + spin_lock_irq(&sdev->ipc_lock); + + /* initialise the message */ + msg = &ipc->msg; + + /* attach message data */ + msg->msg_data = msg_data; + msg->msg_size = msg_bytes; + + msg->reply_size = reply_bytes; + msg->reply_error = 0; + + sdev->msg = msg; + + ret = snd_sof_dsp_send_msg(sdev, msg); + /* Next reply that we receive will be related to this message */ + if (!ret) + msg->ipc_complete = false; + + spin_unlock_irq(&sdev->ipc_lock); + + return ret; +} + /* send IPC message from host to DSP */ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index df19d58d8894..f6ae28a21482 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -588,6 +588,8 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes void *reply_data, size_t reply_bytes); int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes); +int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, + size_t reply_bytes); int sof_ipc_init_msg_memory(struct snd_sof_dev *sdev); static inline void snd_sof_ipc_process_reply(struct snd_sof_dev *sdev, u32 msg_id) { -- cgit From 25e77672c4e18fe76dbf2e21ab8c7c36d6a323cc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:26:55 -0700 Subject: ASoC: SOF: Add high level IPC IO callback definitions to ipc_ops Add tx_msg(), rx_msg(), set_get_data() and get_reply() ops, which can be used as a generic API for sending, receiving single messages and to write and read large data. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20220405172708.122168-3-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-priv.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f6ae28a21482..2bf7844f01d7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -377,11 +377,32 @@ struct sof_ipc_pcm_ops; * @tplg: Pointer to IPC-specific topology ops * @pm: Pointer to PM ops * @pcm: Pointer to PCM ops + * + * @tx_msg: Function pointer for sending a 'short' IPC message + * @set_get_data: Function pointer for set/get data ('large' IPC message). This + * function may split up the 'large' message and use the @tx_msg + * path to transfer individual chunks, or use other means to transfer + * the message. + * @get_reply: Function pointer for fetching the reply to + * sdev->ipc->msg.reply_data + * @rx_msg: Function pointer for handling a received message + * + * Note: both @tx_msg and @set_get_data considered as TX functions and they are + * serialized for the duration of the instructed transfer. A large message sent + * via @set_get_data is a single transfer even if at the hardware level it is + * handled with multiple chunks. */ struct sof_ipc_ops { const struct sof_ipc_tplg_ops *tplg; const struct sof_ipc_pm_ops *pm; const struct sof_ipc_pcm_ops *pcm; + + int (*tx_msg)(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, + void *reply_data, size_t reply_bytes, bool no_pm); + int (*set_get_data)(struct snd_sof_dev *sdev, void *data, size_t data_bytes, + bool set); + int (*get_reply)(struct snd_sof_dev *sdev); + void (*rx_msg)(struct snd_sof_dev *sdev); }; /* SOF generic IPC data */ -- cgit From 0881918087ac7adfeed2652a03b4edb1131826ba Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:26:56 -0700 Subject: ASoC: SOF: ipc3: Implement the tx_msg IPC ops Add the implementation for the IPC3 tx_msg callback for sending a single IPC message. The implementation is equivalent to the currently used code in ipc.c Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-4-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index a7289804efda..7f80035d3a88 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -9,6 +9,312 @@ #include "sof-priv.h" #include "ipc3-ops.h" +#include "ops.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) +static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) +{ + u8 *str; + u8 *str2 = NULL; + u32 glb; + u32 type; + bool vdbg = false; + + glb = cmd & SOF_GLB_TYPE_MASK; + type = cmd & SOF_CMD_TYPE_MASK; + + switch (glb) { + case SOF_IPC_GLB_REPLY: + str = "GLB_REPLY"; break; + case SOF_IPC_GLB_COMPOUND: + str = "GLB_COMPOUND"; break; + case SOF_IPC_GLB_TPLG_MSG: + str = "GLB_TPLG_MSG"; + switch (type) { + case SOF_IPC_TPLG_COMP_NEW: + str2 = "COMP_NEW"; break; + case SOF_IPC_TPLG_COMP_FREE: + str2 = "COMP_FREE"; break; + case SOF_IPC_TPLG_COMP_CONNECT: + str2 = "COMP_CONNECT"; break; + case SOF_IPC_TPLG_PIPE_NEW: + str2 = "PIPE_NEW"; break; + case SOF_IPC_TPLG_PIPE_FREE: + str2 = "PIPE_FREE"; break; + case SOF_IPC_TPLG_PIPE_CONNECT: + str2 = "PIPE_CONNECT"; break; + case SOF_IPC_TPLG_PIPE_COMPLETE: + str2 = "PIPE_COMPLETE"; break; + case SOF_IPC_TPLG_BUFFER_NEW: + str2 = "BUFFER_NEW"; break; + case SOF_IPC_TPLG_BUFFER_FREE: + str2 = "BUFFER_FREE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_PM_MSG: + str = "GLB_PM_MSG"; + switch (type) { + case SOF_IPC_PM_CTX_SAVE: + str2 = "CTX_SAVE"; break; + case SOF_IPC_PM_CTX_RESTORE: + str2 = "CTX_RESTORE"; break; + case SOF_IPC_PM_CTX_SIZE: + str2 = "CTX_SIZE"; break; + case SOF_IPC_PM_CLK_SET: + str2 = "CLK_SET"; break; + case SOF_IPC_PM_CLK_GET: + str2 = "CLK_GET"; break; + case SOF_IPC_PM_CLK_REQ: + str2 = "CLK_REQ"; break; + case SOF_IPC_PM_CORE_ENABLE: + str2 = "CORE_ENABLE"; break; + case SOF_IPC_PM_GATE: + str2 = "GATE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_COMP_MSG: + str = "GLB_COMP_MSG"; + switch (type) { + case SOF_IPC_COMP_SET_VALUE: + str2 = "SET_VALUE"; break; + case SOF_IPC_COMP_GET_VALUE: + str2 = "GET_VALUE"; break; + case SOF_IPC_COMP_SET_DATA: + str2 = "SET_DATA"; break; + case SOF_IPC_COMP_GET_DATA: + str2 = "GET_DATA"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_STREAM_MSG: + str = "GLB_STREAM_MSG"; + switch (type) { + case SOF_IPC_STREAM_PCM_PARAMS: + str2 = "PCM_PARAMS"; break; + case SOF_IPC_STREAM_PCM_PARAMS_REPLY: + str2 = "PCM_REPLY"; break; + case SOF_IPC_STREAM_PCM_FREE: + str2 = "PCM_FREE"; break; + case SOF_IPC_STREAM_TRIG_START: + str2 = "TRIG_START"; break; + case SOF_IPC_STREAM_TRIG_STOP: + str2 = "TRIG_STOP"; break; + case SOF_IPC_STREAM_TRIG_PAUSE: + str2 = "TRIG_PAUSE"; break; + case SOF_IPC_STREAM_TRIG_RELEASE: + str2 = "TRIG_RELEASE"; break; + case SOF_IPC_STREAM_TRIG_DRAIN: + str2 = "TRIG_DRAIN"; break; + case SOF_IPC_STREAM_TRIG_XRUN: + str2 = "TRIG_XRUN"; break; + case SOF_IPC_STREAM_POSITION: + vdbg = true; + str2 = "POSITION"; break; + case SOF_IPC_STREAM_VORBIS_PARAMS: + str2 = "VORBIS_PARAMS"; break; + case SOF_IPC_STREAM_VORBIS_FREE: + str2 = "VORBIS_FREE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_FW_READY: + str = "FW_READY"; break; + case SOF_IPC_GLB_DAI_MSG: + str = "GLB_DAI_MSG"; + switch (type) { + case SOF_IPC_DAI_CONFIG: + str2 = "CONFIG"; break; + case SOF_IPC_DAI_LOOPBACK: + str2 = "LOOPBACK"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_TRACE_MSG: + str = "GLB_TRACE_MSG"; + switch (type) { + case SOF_IPC_TRACE_DMA_PARAMS: + str2 = "DMA_PARAMS"; break; + case SOF_IPC_TRACE_DMA_POSITION: + str2 = "DMA_POSITION"; break; + case SOF_IPC_TRACE_DMA_PARAMS_EXT: + str2 = "DMA_PARAMS_EXT"; break; + case SOF_IPC_TRACE_FILTER_UPDATE: + str2 = "FILTER_UPDATE"; break; + case SOF_IPC_TRACE_DMA_FREE: + str2 = "DMA_FREE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_TEST_MSG: + str = "GLB_TEST_MSG"; + switch (type) { + case SOF_IPC_TEST_IPC_FLOOD: + str2 = "IPC_FLOOD"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_DEBUG: + str = "GLB_DEBUG"; + switch (type) { + case SOF_IPC_DEBUG_MEM_USAGE: + str2 = "MEM_USAGE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_PROBE: + str = "GLB_PROBE"; + switch (type) { + case SOF_IPC_PROBE_INIT: + str2 = "INIT"; break; + case SOF_IPC_PROBE_DEINIT: + str2 = "DEINIT"; break; + case SOF_IPC_PROBE_DMA_ADD: + str2 = "DMA_ADD"; break; + case SOF_IPC_PROBE_DMA_INFO: + str2 = "DMA_INFO"; break; + case SOF_IPC_PROBE_DMA_REMOVE: + str2 = "DMA_REMOVE"; break; + case SOF_IPC_PROBE_POINT_ADD: + str2 = "POINT_ADD"; break; + case SOF_IPC_PROBE_POINT_INFO: + str2 = "POINT_INFO"; break; + case SOF_IPC_PROBE_POINT_REMOVE: + str2 = "POINT_REMOVE"; break; + default: + str2 = "unknown type"; break; + } + break; + default: + str = "unknown GLB command"; break; + } + + if (str2) { + if (vdbg) + dev_vdbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + else + dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + } else { + dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); + } +} +#else +static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) +{ + if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG) + dev_dbg(dev, "%s: 0x%x\n", text, cmd); +} +#endif + +/* wait for IPC message reply */ +static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) +{ + struct snd_sof_ipc_msg *msg = &ipc->msg; + struct sof_ipc_cmd_hdr *hdr = msg->msg_data; + struct snd_sof_dev *sdev = ipc->sdev; + int ret; + + /* wait for DSP IPC completion */ + ret = wait_event_timeout(msg->waitq, msg->ipc_complete, + msecs_to_jiffies(sdev->ipc_timeout)); + + if (ret == 0) { + dev_err(sdev->dev, + "ipc tx timed out for %#x (msg/reply size: %d/%zu)\n", + hdr->cmd, hdr->size, msg->reply_size); + snd_sof_handle_fw_exception(ipc->sdev); + ret = -ETIMEDOUT; + } else { + ret = msg->reply_error; + if (ret < 0) { + dev_err(sdev->dev, + "ipc tx error for %#x (msg/reply size: %d/%zu): %d\n", + hdr->cmd, hdr->size, msg->reply_size, ret); + } else { + ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); + if (msg->reply_size) + /* copy the data returned from DSP */ + memcpy(reply_data, msg->reply_data, + msg->reply_size); + } + + /* re-enable dumps after successful IPC tx */ + if (sdev->ipc_dump_printed) { + sdev->dbg_dump_printed = false; + sdev->ipc_dump_printed = false; + } + } + + return ret; +} + +/* send IPC message from host to DSP */ +static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc, + void *msg_data, size_t msg_bytes, + void *reply_data, size_t reply_bytes) +{ + struct sof_ipc_cmd_hdr *hdr = msg_data; + struct snd_sof_dev *sdev = ipc->sdev; + int ret; + + ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes); + + if (ret) { + dev_err_ratelimited(sdev->dev, + "%s: ipc message send for %#x failed: %d\n", + __func__, hdr->cmd, ret); + return ret; + } + + ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd); + + /* now wait for completion */ + return ipc3_wait_tx_done(ipc, reply_data); +} + +static int sof_ipc3_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, + void *reply_data, size_t reply_bytes, bool no_pm) +{ + struct snd_sof_ipc *ipc = sdev->ipc; + int ret; + + if (!msg_data || msg_bytes < sizeof(struct sof_ipc_cmd_hdr)) { + dev_err_ratelimited(sdev->dev, "No IPC message to send\n"); + return -EINVAL; + } + + if (!no_pm) { + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + }; + + /* ensure the DSP is in D0 before sending a new IPC */ + ret = snd_sof_dsp_set_power_state(sdev, &target_state); + if (ret < 0) { + dev_err(sdev->dev, "%s: resuming DSP failed: %d\n", + __func__, ret); + return ret; + } + } + + /* Serialise IPC TX */ + mutex_lock(&ipc->tx_mutex); + + ret = ipc3_tx_msg_unlocked(ipc, msg_data, msg_bytes, reply_data, reply_bytes); + + mutex_unlock(&ipc->tx_mutex); + + return ret; +} static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { @@ -42,4 +348,6 @@ const struct sof_ipc_ops ipc3_ops = { .tplg = &ipc3_tplg_ops, .pm = &ipc3_pm_ops, .pcm = &ipc3_pcm_ops, + + .tx_msg = sof_ipc3_tx_msg, }; -- cgit From dbcf543cf91edc7f6fe833d51b58fe65265f2a72 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:26:57 -0700 Subject: ASoC: SOF: ipc3: Use sof_ipc3_tx_msg() internally for message sending Instead of using sof_ipc_tx_message() for sending message, use the sof_ipc3_tx_msg() directly within ipc3.c Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-5-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 7f80035d3a88..6b59d4d0727f 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -325,8 +325,8 @@ static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd) struct sof_ipc_reply reply; /* send ctx save ipc to dsp */ - return sof_ipc_tx_message(sdev->ipc, &pm_ctx, sizeof(pm_ctx), - &reply, sizeof(reply)); + return sof_ipc3_tx_msg(sdev, &pm_ctx, sizeof(pm_ctx), + &reply, sizeof(reply), false); } static int sof_ipc3_ctx_save(struct snd_sof_dev *sdev) -- cgit From e974b8e190d30fdd0c5edc1447ee1425a30d15ea Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:26:58 -0700 Subject: ASoC: SOF: ipc3: Implement the set_get_data IPC ops Add the implementation for the set_get_data callback for handling large data set and get. The set_get_data() in IPC3 can be used only for component messages. The function expects the caller to prepare the message behind the data pointer for sending/receiving data. The callback only implements the needed code to be able to split up a message if needed for transfer. The set_get_data ops is based on the existing snd_sof_ipc_set_get_comp_data() and sof_set_get_large_ctrl_data() but made it generic entry point. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-6-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 6b59d4d0727f..9aa263b4af0a 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -7,6 +7,8 @@ // // +#include +#include #include "sof-priv.h" #include "ipc3-ops.h" #include "ops.h" @@ -316,6 +318,106 @@ static int sof_ipc3_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_ return ret; } +static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t data_bytes, + bool set) +{ + size_t msg_bytes, hdr_bytes, payload_size, send_bytes; + struct sof_ipc_ctrl_data *cdata = data; + struct sof_ipc_ctrl_data *cdata_chunk; + struct snd_sof_ipc *ipc = sdev->ipc; + size_t offset = 0; + u8 *src, *dst; + u32 num_msg; + int ret = 0; + int i; + + if (!cdata || data_bytes < sizeof(*cdata)) + return -EINVAL; + + if ((cdata->rhdr.hdr.cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_COMP_MSG) { + dev_err(sdev->dev, "%s: Not supported message type of %#x\n", + __func__, cdata->rhdr.hdr.cmd); + return -EINVAL; + } + + /* send normal size ipc in one part */ + if (cdata->rhdr.hdr.size <= ipc->max_payload_size) + return sof_ipc3_tx_msg(sdev, cdata, cdata->rhdr.hdr.size, + cdata, cdata->rhdr.hdr.size, false); + + cdata_chunk = kzalloc(ipc->max_payload_size, GFP_KERNEL); + if (!cdata_chunk) + return -ENOMEM; + + switch (cdata->type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + hdr_bytes = sizeof(struct sof_ipc_ctrl_data); + if (set) { + src = (u8 *)cdata->chanv; + dst = (u8 *)cdata_chunk->chanv; + } else { + src = (u8 *)cdata_chunk->chanv; + dst = (u8 *)cdata->chanv; + } + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr); + if (set) { + src = (u8 *)cdata->data->data; + dst = (u8 *)cdata_chunk->data->data; + } else { + src = (u8 *)cdata_chunk->data->data; + dst = (u8 *)cdata->data->data; + } + break; + default: + kfree(cdata_chunk); + return -EINVAL; + } + + msg_bytes = cdata->rhdr.hdr.size - hdr_bytes; + payload_size = ipc->max_payload_size - hdr_bytes; + num_msg = DIV_ROUND_UP(msg_bytes, payload_size); + + /* copy the header data */ + memcpy(cdata_chunk, cdata, hdr_bytes); + + /* Serialise IPC TX */ + mutex_lock(&sdev->ipc->tx_mutex); + + /* copy the payload data in a loop */ + for (i = 0; i < num_msg; i++) { + send_bytes = min(msg_bytes, payload_size); + cdata_chunk->num_elems = send_bytes; + cdata_chunk->rhdr.hdr.size = hdr_bytes + send_bytes; + cdata_chunk->msg_index = i; + msg_bytes -= send_bytes; + cdata_chunk->elems_remaining = msg_bytes; + + if (set) + memcpy(dst, src + offset, send_bytes); + + ret = ipc3_tx_msg_unlocked(sdev->ipc, + cdata_chunk, cdata_chunk->rhdr.hdr.size, + cdata_chunk, cdata_chunk->rhdr.hdr.size); + if (ret < 0) + break; + + if (!set) + memcpy(dst + offset, src, send_bytes); + + offset += payload_size; + } + + mutex_unlock(&sdev->ipc->tx_mutex); + + kfree(cdata_chunk); + + return ret; +} + static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx = { @@ -350,4 +452,5 @@ const struct sof_ipc_ops ipc3_ops = { .pcm = &ipc3_pcm_ops, .tx_msg = sof_ipc3_tx_msg, + .set_get_data = sof_ipc3_set_get_data, }; -- cgit From 783b5f1797595a9df4476dd66f7bf34915be246b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:26:59 -0700 Subject: ASoC: SOF: ipc3: Implement the get_reply IPC ops Add the implementation for the get_reply callback to copy the reply message from mailbox to msg->reply_data buffer. The implementation is equivalent to the currently used code in ipc.c Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-7-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 9aa263b4af0a..2ecd3bb061f3 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -217,6 +217,60 @@ static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) } #endif +static int sof_ipc3_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply *reply; + int ret = 0; + + /* get the generic reply */ + reply = msg->reply_data; + snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, reply, sizeof(*reply)); + + if (reply->error < 0) + return reply->error; + + if (!reply->hdr.size) { + /* Reply should always be >= sizeof(struct sof_ipc_reply) */ + if (msg->reply_size) + dev_err(sdev->dev, + "empty reply received, expected %zu bytes\n", + msg->reply_size); + else + dev_err(sdev->dev, "empty reply received\n"); + + return -EINVAL; + } + + if (msg->reply_size > 0) { + if (reply->hdr.size == msg->reply_size) { + ret = 0; + } else if (reply->hdr.size < msg->reply_size) { + dev_dbg(sdev->dev, + "reply size (%u) is less than expected (%zu)\n", + reply->hdr.size, msg->reply_size); + + msg->reply_size = reply->hdr.size; + ret = 0; + } else { + dev_err(sdev->dev, + "reply size (%u) exceeds the buffer size (%zu)\n", + reply->hdr.size, msg->reply_size); + ret = -EINVAL; + } + + /* + * get the full message if reply->hdr.size <= msg->reply_size + * and the reply->hdr.size > sizeof(struct sof_ipc_reply) + */ + if (!ret && msg->reply_size > sizeof(*reply)) + snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + return ret; +} + /* wait for IPC message reply */ static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data) { @@ -453,4 +507,5 @@ const struct sof_ipc_ops ipc3_ops = { .tx_msg = sof_ipc3_tx_msg, .set_get_data = sof_ipc3_set_get_data, + .get_reply = sof_ipc3_get_reply, }; -- cgit From 74ad8ed6512186134527fc82440f62007a98ff48 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:00 -0700 Subject: ASoC: SOF: ipc3: Implement rx_msg IPC ops Add the implementation for the rx_msg callback to handle message reception for IPC3. The implementation is equivalent to the currently used code in ipc.c Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-8-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 2ecd3bb061f3..8480a1b5733a 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -10,9 +10,12 @@ #include #include #include "sof-priv.h" +#include "sof-audio.h" #include "ipc3-ops.h" #include "ops.h" +typedef void (*ipc3_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf); + #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) { @@ -472,6 +475,214 @@ static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t da return ret; } +/* IPC stream position. */ +static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct snd_soc_component *scomp = sdev->component; + struct snd_sof_pcm_stream *stream; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + int direction, ret; + + spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); + if (!spcm) { + dev_err(sdev->dev, "period elapsed for unknown stream, msg_id %d\n", + msg_id); + return; + } + + stream = &spcm->stream[direction]; + ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return; + } + + dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", + posn.host_posn, posn.dai_posn, posn.wallclock); + + memcpy(&stream->posn, &posn, sizeof(posn)); + + if (spcm->pcm.compress) + snd_sof_compr_fragment_elapsed(stream->cstream); + else if (stream->substream->runtime && + !stream->substream->runtime->no_period_wakeup) + /* only inform ALSA for period_wakeup mode */ + snd_sof_pcm_period_elapsed(stream->substream); +} + +/* DSP notifies host of an XRUN within FW */ +static void ipc3_xrun(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct snd_soc_component *scomp = sdev->component; + struct snd_sof_pcm_stream *stream; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + int direction, ret; + + spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); + if (!spcm) { + dev_err(sdev->dev, "XRUN for unknown stream, msg_id %d\n", + msg_id); + return; + } + + stream = &spcm->stream[direction]; + ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read overrun position: %d\n", ret); + return; + } + + dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", + posn.host_posn, posn.xrun_comp_id, posn.xrun_size); + +#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP) + /* stop PCM on XRUN - used for pipeline debug */ + memcpy(&stream->posn, &posn, sizeof(posn)); + snd_pcm_stop_xrun(stream->substream); +#endif +} + +/* stream notifications from firmware */ +static void ipc3_stream_message(struct snd_sof_dev *sdev, void *msg_buf) +{ + struct sof_ipc_cmd_hdr *hdr = msg_buf; + u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + u32 msg_id = SOF_IPC_MESSAGE_ID(hdr->cmd); + + switch (msg_type) { + case SOF_IPC_STREAM_POSITION: + ipc3_period_elapsed(sdev, msg_id); + break; + case SOF_IPC_STREAM_TRIG_XRUN: + ipc3_xrun(sdev, msg_id); + break; + default: + dev_err(sdev->dev, "unhandled stream message %#x\n", + msg_id); + break; + } +} + +/* component notifications from firmware */ +static void ipc3_comp_notification(struct snd_sof_dev *sdev, void *msg_buf) +{ + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + struct sof_ipc_cmd_hdr *hdr = msg_buf; + u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + + switch (msg_type) { + case SOF_IPC_COMP_GET_VALUE: + case SOF_IPC_COMP_GET_DATA: + break; + default: + dev_err(sdev->dev, "unhandled component message %#x\n", msg_type); + return; + } + + if (tplg_ops->control->update) + tplg_ops->control->update(sdev, msg_buf); +} + +static void ipc3_trace_message(struct snd_sof_dev *sdev, void *msg_buf) +{ + struct sof_ipc_cmd_hdr *hdr = msg_buf; + u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; + + switch (msg_type) { + case SOF_IPC_TRACE_DMA_POSITION: + snd_sof_trace_update_pos(sdev, msg_buf); + break; + default: + dev_err(sdev->dev, "unhandled trace message %#x\n", msg_type); + break; + } +} + +/* DSP firmware has sent host a message */ +static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev) +{ + ipc3_rx_callback rx_callback = NULL; + struct sof_ipc_cmd_hdr hdr; + void *msg_buf; + u32 cmd; + int err; + + /* read back header */ + err = snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr)); + if (err < 0) { + dev_warn(sdev->dev, "failed to read IPC header: %d\n", err); + return; + } + + if (hdr.size < sizeof(hdr)) { + dev_err(sdev->dev, "The received message size is invalid\n"); + return; + } + + ipc3_log_header(sdev->dev, "ipc rx", hdr.cmd); + + cmd = hdr.cmd & SOF_GLB_TYPE_MASK; + + /* check message type */ + switch (cmd) { + case SOF_IPC_GLB_REPLY: + dev_err(sdev->dev, "ipc reply unknown\n"); + break; + case SOF_IPC_FW_READY: + /* check for FW boot completion */ + if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) { + err = sof_ops(sdev)->fw_ready(sdev, cmd); + if (err < 0) + sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED); + else + sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK); + + /* wake up firmware loader */ + wake_up(&sdev->boot_wait); + } + break; + case SOF_IPC_GLB_COMPOUND: + case SOF_IPC_GLB_TPLG_MSG: + case SOF_IPC_GLB_PM_MSG: + break; + case SOF_IPC_GLB_COMP_MSG: + rx_callback = ipc3_comp_notification; + break; + case SOF_IPC_GLB_STREAM_MSG: + rx_callback = ipc3_stream_message; + break; + case SOF_IPC_GLB_TRACE_MSG: + rx_callback = ipc3_trace_message; + break; + default: + dev_err(sdev->dev, "%s: Unknown DSP message: 0x%x\n", __func__, cmd); + break; + } + + /* read the full message */ + msg_buf = kmalloc(hdr.size, GFP_KERNEL); + if (!msg_buf) + return; + + err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); + if (err < 0) { + dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err); + } else { + /* Call local handler for the message */ + if (rx_callback) + rx_callback(sdev, msg_buf); + + /* Notify registered clients */ + sof_client_ipc_rx_dispatcher(sdev, msg_buf); + } + + kfree(msg_buf); + + ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd); +} + static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx = { @@ -506,6 +717,7 @@ const struct sof_ipc_ops ipc3_ops = { .pcm = &ipc3_pcm_ops, .tx_msg = sof_ipc3_tx_msg, + .rx_msg = sof_ipc3_rx_msg, .set_get_data = sof_ipc3_set_get_data, .get_reply = sof_ipc3_get_reply, }; -- cgit From 785b3fbe61c6c1c413b696e335e9f288aaec4364 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:01 -0700 Subject: ASoC: SOF: ipc: Separate the ops checks by functions/topics Separate the mandatory ops checks by topics (pcm and topology for now) to be able to provide intuitive feedback on the possible missing ops and to make it easier to add new mandatory ops checks in the future. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-9-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index a78b74514438..4966a2a41704 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -1043,6 +1043,7 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) { struct snd_sof_ipc *ipc; struct snd_sof_ipc_msg *msg; + const struct sof_ipc_ops *ops; ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); if (!ipc) @@ -1062,11 +1063,16 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) * versions, this will need to be modified to use the selected version at runtime. */ ipc->ops = &ipc3_ops; + ops = ipc->ops; /* check for mandatory ops */ - if (!ipc->ops->pcm || !ipc->ops->tplg || !ipc->ops->tplg->widget || - !ipc->ops->tplg->control) { - dev_err(sdev->dev, "Invalid IPC ops\n"); + if (!ops->pcm) { + dev_err(sdev->dev, "Missing IPC PCM ops\n"); + return NULL; + } + + if (!ops->tplg || !ops->tplg->widget || !ops->tplg->control) { + dev_err(sdev->dev, "Missing IPC topology ops\n"); return NULL; } -- cgit From defad9d2e2703b040c3a001978c09c75970357f0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:02 -0700 Subject: ASoC: SOF: ipc: Add check for mandatory IPC message handling ops Make sure that the mandatory IPC message handling ops are provided by the IPC implementation. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-10-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 4966a2a41704..d11c5e6e57fb 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -1066,6 +1066,11 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) ops = ipc->ops; /* check for mandatory ops */ + if (!ops->tx_msg || !ops->rx_msg || !ops->set_get_data || !ops->get_reply) { + dev_err(sdev->dev, "Missing IPC message handling ops\n"); + return NULL; + } + if (!ops->pcm) { dev_err(sdev->dev, "Missing IPC PCM ops\n"); return NULL; -- cgit From 045bc49bc9572f883db1a0740cb36bf6eeb206db Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:03 -0700 Subject: ASoC: SOF: ipc: Use the get_reply ops in snd_sof_ipc_get_reply() Use the get_reply ops to allow IPC dependent handling of the reply message. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-11-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 50 ++------------------------------------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index d11c5e6e57fb..39ec4361048a 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -443,63 +443,17 @@ EXPORT_SYMBOL(sof_ipc_tx_message_no_pm); /* Generic helper function to retrieve the reply */ void snd_sof_ipc_get_reply(struct snd_sof_dev *sdev) { - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply *reply; - int ret = 0; - /* * Sometimes, there is unexpected reply ipc arriving. The reply * ipc belongs to none of the ipcs sent from driver. * In this case, the driver must ignore the ipc. */ - if (!msg) { + if (!sdev->msg) { dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); return; } - /* get the generic reply */ - reply = msg->reply_data; - snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, reply, sizeof(*reply)); - - if (reply->error < 0) { - ret = reply->error; - } else if (!reply->hdr.size) { - /* Reply should always be >= sizeof(struct sof_ipc_reply) */ - if (msg->reply_size) - dev_err(sdev->dev, - "empty reply received, expected %zu bytes\n", - msg->reply_size); - else - dev_err(sdev->dev, "empty reply received\n"); - - ret = -EINVAL; - } else if (msg->reply_size > 0) { - if (reply->hdr.size == msg->reply_size) { - ret = 0; - } else if (reply->hdr.size < msg->reply_size) { - dev_dbg(sdev->dev, - "reply size (%u) is less than expected (%zu)\n", - reply->hdr.size, msg->reply_size); - - msg->reply_size = reply->hdr.size; - ret = 0; - } else { - dev_err(sdev->dev, - "reply size (%u) exceeds the buffer size (%zu)\n", - reply->hdr.size, msg->reply_size); - ret = -EINVAL; - } - - /* - * get the full message if reply->hdr.size <= msg->reply_size - * and the reply->hdr.size > sizeof(struct sof_ipc_reply) - */ - if (!ret && msg->reply_size > sizeof(*reply)) - snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; + sdev->msg->reply_error = sdev->ipc->ops->get_reply(sdev); } EXPORT_SYMBOL(snd_sof_ipc_get_reply); -- cgit From 85d0f881471531ffb081711b13df32b1f6f1f637 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:04 -0700 Subject: ASoC: SOF: ipc: Switch over to use the tx_msg and set_get_data ops Use the new ops for sending messages and to handle large component data set get operation. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-12-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 301 ++++------------------------------------------------ 1 file changed, 23 insertions(+), 278 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 39ec4361048a..05c1ba0c2206 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -24,20 +24,6 @@ typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf); static void ipc_trace_message(struct snd_sof_dev *sdev, void *msg_buf); static void ipc_stream_message(struct snd_sof_dev *sdev, void *msg_buf); -/* - * IPC message Tx/Rx message handling. - */ - -struct sof_ipc_ctrl_data_params { - size_t msg_bytes; - size_t hdr_bytes; - size_t pl_size; - size_t elems; - u32 num_msg; - u8 *src; - u8 *dst; -}; - #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) { @@ -242,104 +228,6 @@ static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) } #endif -/* wait for IPC message reply */ -static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, - void *reply_data) -{ - struct snd_sof_dev *sdev = ipc->sdev; - struct sof_ipc_cmd_hdr *hdr = msg->msg_data; - int ret; - - /* wait for DSP IPC completion */ - ret = wait_event_timeout(msg->waitq, msg->ipc_complete, - msecs_to_jiffies(sdev->ipc_timeout)); - - if (ret == 0) { - dev_err(sdev->dev, - "ipc tx timed out for %#x (msg/reply size: %d/%zu)\n", - hdr->cmd, hdr->size, msg->reply_size); - snd_sof_handle_fw_exception(ipc->sdev); - ret = -ETIMEDOUT; - } else { - ret = msg->reply_error; - if (ret < 0) { - dev_err(sdev->dev, - "ipc tx error for %#x (msg/reply size: %d/%zu): %d\n", - hdr->cmd, hdr->size, msg->reply_size, ret); - } else { - ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); - if (msg->reply_size) - /* copy the data returned from DSP */ - memcpy(reply_data, msg->reply_data, - msg->reply_size); - } - - /* re-enable dumps after successful IPC tx */ - if (sdev->ipc_dump_printed) { - sdev->dbg_dump_printed = false; - sdev->ipc_dump_printed = false; - } - } - - return ret; -} - -/* send IPC message from host to DSP */ -static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, - void *msg_data, size_t msg_bytes, - void *reply_data, size_t reply_bytes) -{ - struct sof_ipc_cmd_hdr *hdr = msg_data; - struct snd_sof_dev *sdev = ipc->sdev; - struct snd_sof_ipc_msg *msg; - int ret; - - if (!msg_data || msg_bytes < sizeof(*hdr)) { - dev_err_ratelimited(sdev->dev, "No IPC message to send\n"); - return -EINVAL; - } - - if (ipc->disable_ipc_tx || sdev->fw_state != SOF_FW_BOOT_COMPLETE) - return -ENODEV; - - /* - * The spin-lock is also still needed to protect message objects against - * other atomic contexts. - */ - spin_lock_irq(&sdev->ipc_lock); - - /* initialise the message */ - msg = &ipc->msg; - - /* attach message data */ - msg->msg_data = msg_data; - msg->msg_size = msg_bytes; - - msg->reply_size = reply_bytes; - msg->reply_error = 0; - - sdev->msg = msg; - - ret = snd_sof_dsp_send_msg(sdev, msg); - /* Next reply that we receive will be related to this message */ - if (!ret) - msg->ipc_complete = false; - - spin_unlock_irq(&sdev->ipc_lock); - - if (ret) { - dev_err_ratelimited(sdev->dev, - "error: ipc tx failed with error %d\n", - ret); - return ret; - } - - ipc_log_header(sdev->dev, "ipc tx", hdr->cmd); - - /* now wait for completion */ - return tx_wait_done(ipc, msg, reply_data); -} - /** * sof_ipc_send_msg - generic function to prepare and send one IPC message * @sdev: pointer to SOF core device struct @@ -397,20 +285,12 @@ int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes) { - const struct sof_dsp_power_state target_state = { - .state = SOF_DSP_PM_D0, - }; - int ret; - - /* ensure the DSP is in D0 before sending a new IPC */ - ret = snd_sof_dsp_set_power_state(ipc->sdev, &target_state); - if (ret < 0) { - dev_err(ipc->sdev->dev, "error: resuming DSP %d\n", ret); - return ret; - } + if (msg_bytes > ipc->max_payload_size || + reply_bytes > ipc->max_payload_size) + return -ENOBUFS; - return sof_ipc_tx_message_no_pm(ipc, msg_data, msg_bytes, - reply_data, reply_bytes); + return ipc->ops->tx_msg(ipc->sdev, msg_data, msg_bytes, reply_data, + reply_bytes, false); } EXPORT_SYMBOL(sof_ipc_tx_message); @@ -422,21 +302,12 @@ EXPORT_SYMBOL(sof_ipc_tx_message); int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes) { - int ret; - if (msg_bytes > ipc->max_payload_size || reply_bytes > ipc->max_payload_size) return -ENOBUFS; - /* Serialise IPC TX */ - mutex_lock(&ipc->tx_mutex); - - ret = sof_ipc_tx_message_unlocked(ipc, msg_data, msg_bytes, - reply_data, reply_bytes); - - mutex_unlock(&ipc->tx_mutex); - - return ret; + return ipc->ops->tx_msg(ipc->sdev, msg_data, msg_bytes, reply_data, + reply_bytes, true); } EXPORT_SYMBOL(sof_ipc_tx_message_no_pm); @@ -718,103 +589,6 @@ int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp, } EXPORT_SYMBOL(snd_sof_ipc_stream_posn); -static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type, - struct sof_ipc_ctrl_data *src, - struct sof_ipc_ctrl_data *dst, - struct sof_ipc_ctrl_data_params *sparams) -{ - switch (ctrl_type) { - case SOF_CTRL_TYPE_VALUE_CHAN_GET: - case SOF_CTRL_TYPE_VALUE_CHAN_SET: - sparams->src = (u8 *)src->chanv; - sparams->dst = (u8 *)dst->chanv; - break; - case SOF_CTRL_TYPE_DATA_GET: - case SOF_CTRL_TYPE_DATA_SET: - sparams->src = (u8 *)src->data->data; - sparams->dst = (u8 *)dst->data->data; - break; - default: - return -EINVAL; - } - - /* calculate payload size and number of messages */ - sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes; - sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size); - - return 0; -} - -static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, - struct sof_ipc_ctrl_data *cdata, - struct sof_ipc_ctrl_data_params *sparams, - bool set) -{ - struct sof_ipc_ctrl_data *partdata; - size_t send_bytes; - size_t offset = 0; - size_t msg_bytes; - size_t pl_size; - int err; - int i; - - /* allocate max ipc size because we have at least one */ - partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); - if (!partdata) - return -ENOMEM; - - if (set) - err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata, - sparams); - else - err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata, - sparams); - if (err < 0) { - kfree(partdata); - return err; - } - - msg_bytes = sparams->msg_bytes; - pl_size = sparams->pl_size; - - /* copy the header data */ - memcpy(partdata, cdata, sparams->hdr_bytes); - - /* Serialise IPC TX */ - mutex_lock(&sdev->ipc->tx_mutex); - - /* copy the payload data in a loop */ - for (i = 0; i < sparams->num_msg; i++) { - send_bytes = min(msg_bytes, pl_size); - partdata->num_elems = send_bytes; - partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes; - partdata->msg_index = i; - msg_bytes -= send_bytes; - partdata->elems_remaining = msg_bytes; - - if (set) - memcpy(sparams->dst, sparams->src + offset, send_bytes); - - err = sof_ipc_tx_message_unlocked(sdev->ipc, - partdata, - partdata->rhdr.hdr.size, - partdata, - partdata->rhdr.hdr.size); - if (err < 0) - break; - - if (!set) - memcpy(sparams->dst + offset, sparams->src, send_bytes); - - offset += pl_size; - } - - mutex_unlock(&sdev->ipc->tx_mutex); - - kfree(partdata); - return err; -} - /* * IPC get()/set() for kcontrols. */ @@ -823,14 +597,11 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set) struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_fw_ready *ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &ready->version; - struct sof_ipc_ctrl_data_params sparams; + const struct sof_ipc_ops *iops = sdev->ipc->ops; enum sof_ipc_ctrl_type ctrl_type; struct snd_sof_widget *swidget; bool widget_found = false; - u32 ipc_cmd; - int err; + u32 ipc_cmd, msg_bytes; list_for_each_entry(swidget, &sdev->widget_list, list) { if (swidget->comp_id == scontrol->comp_id) { @@ -840,7 +611,8 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set) } if (!widget_found) { - dev_err(sdev->dev, "error: can't find widget with id %d\n", scontrol->comp_id); + dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__, + scontrol->comp_id); return -EINVAL; } @@ -875,55 +647,28 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set) switch (cdata->type) { case SOF_CTRL_TYPE_VALUE_CHAN_GET: case SOF_CTRL_TYPE_VALUE_CHAN_SET: - sparams.msg_bytes = scontrol->num_channels * - sizeof(struct sof_ipc_ctrl_value_chan); - sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); - sparams.elems = scontrol->num_channels; + cdata->num_elems = scontrol->num_channels; + + msg_bytes = scontrol->num_channels * + sizeof(struct sof_ipc_ctrl_value_chan); + msg_bytes += sizeof(struct sof_ipc_ctrl_data); break; case SOF_CTRL_TYPE_DATA_GET: case SOF_CTRL_TYPE_DATA_SET: - sparams.msg_bytes = cdata->data->size; - sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + - sizeof(struct sof_abi_hdr); - sparams.elems = cdata->data->size; + cdata->num_elems = cdata->data->size; + + msg_bytes = cdata->data->size; + msg_bytes += sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_abi_hdr); break; default: return -EINVAL; } - cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes; - cdata->num_elems = sparams.elems; + cdata->rhdr.hdr.size = msg_bytes; cdata->elems_remaining = 0; - /* send normal size ipc in one part */ - if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) { - err = sof_ipc_tx_message(sdev->ipc, cdata, cdata->rhdr.hdr.size, - cdata, cdata->rhdr.hdr.size); - - if (err < 0) - dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n", - cdata->comp_id); - - return err; - } - - /* data is bigger than max ipc size, chop into smaller pieces */ - dev_dbg(sdev->dev, "large ipc size %u, control size %u\n", - cdata->rhdr.hdr.size, scontrol->size); - - /* large messages is only supported from ABI 3.3.0 onwards */ - if (v->abi_version < SOF_ABI_VER(3, 3, 0)) { - dev_err(sdev->dev, "error: incompatible FW ABI version\n"); - return -EINVAL; - } - - err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, set); - - if (err < 0) - dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n", - cdata->comp_id); - - return err; + return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); } EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data); -- cgit From 2f1f5a438899a9d2933ef004a1f0f2c962b29fb4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:05 -0700 Subject: ASoC: SOF: ipc: Switch over to use the rx_msg ops Use the new ops for handling message reception. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-13-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 452 ----------------------------------------------- sound/soc/sof/sof-priv.h | 5 +- 2 files changed, 4 insertions(+), 453 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 05c1ba0c2206..45c487ab8b54 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -19,215 +19,6 @@ #include "ops.h" #include "ipc3-ops.h" -typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf); - -static void ipc_trace_message(struct snd_sof_dev *sdev, void *msg_buf); -static void ipc_stream_message(struct snd_sof_dev *sdev, void *msg_buf); - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) -static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) -{ - u8 *str; - u8 *str2 = NULL; - u32 glb; - u32 type; - bool vdbg = false; - - glb = cmd & SOF_GLB_TYPE_MASK; - type = cmd & SOF_CMD_TYPE_MASK; - - switch (glb) { - case SOF_IPC_GLB_REPLY: - str = "GLB_REPLY"; break; - case SOF_IPC_GLB_COMPOUND: - str = "GLB_COMPOUND"; break; - case SOF_IPC_GLB_TPLG_MSG: - str = "GLB_TPLG_MSG"; - switch (type) { - case SOF_IPC_TPLG_COMP_NEW: - str2 = "COMP_NEW"; break; - case SOF_IPC_TPLG_COMP_FREE: - str2 = "COMP_FREE"; break; - case SOF_IPC_TPLG_COMP_CONNECT: - str2 = "COMP_CONNECT"; break; - case SOF_IPC_TPLG_PIPE_NEW: - str2 = "PIPE_NEW"; break; - case SOF_IPC_TPLG_PIPE_FREE: - str2 = "PIPE_FREE"; break; - case SOF_IPC_TPLG_PIPE_CONNECT: - str2 = "PIPE_CONNECT"; break; - case SOF_IPC_TPLG_PIPE_COMPLETE: - str2 = "PIPE_COMPLETE"; break; - case SOF_IPC_TPLG_BUFFER_NEW: - str2 = "BUFFER_NEW"; break; - case SOF_IPC_TPLG_BUFFER_FREE: - str2 = "BUFFER_FREE"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_PM_MSG: - str = "GLB_PM_MSG"; - switch (type) { - case SOF_IPC_PM_CTX_SAVE: - str2 = "CTX_SAVE"; break; - case SOF_IPC_PM_CTX_RESTORE: - str2 = "CTX_RESTORE"; break; - case SOF_IPC_PM_CTX_SIZE: - str2 = "CTX_SIZE"; break; - case SOF_IPC_PM_CLK_SET: - str2 = "CLK_SET"; break; - case SOF_IPC_PM_CLK_GET: - str2 = "CLK_GET"; break; - case SOF_IPC_PM_CLK_REQ: - str2 = "CLK_REQ"; break; - case SOF_IPC_PM_CORE_ENABLE: - str2 = "CORE_ENABLE"; break; - case SOF_IPC_PM_GATE: - str2 = "GATE"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_COMP_MSG: - str = "GLB_COMP_MSG"; - switch (type) { - case SOF_IPC_COMP_SET_VALUE: - str2 = "SET_VALUE"; break; - case SOF_IPC_COMP_GET_VALUE: - str2 = "GET_VALUE"; break; - case SOF_IPC_COMP_SET_DATA: - str2 = "SET_DATA"; break; - case SOF_IPC_COMP_GET_DATA: - str2 = "GET_DATA"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_STREAM_MSG: - str = "GLB_STREAM_MSG"; - switch (type) { - case SOF_IPC_STREAM_PCM_PARAMS: - str2 = "PCM_PARAMS"; break; - case SOF_IPC_STREAM_PCM_PARAMS_REPLY: - str2 = "PCM_REPLY"; break; - case SOF_IPC_STREAM_PCM_FREE: - str2 = "PCM_FREE"; break; - case SOF_IPC_STREAM_TRIG_START: - str2 = "TRIG_START"; break; - case SOF_IPC_STREAM_TRIG_STOP: - str2 = "TRIG_STOP"; break; - case SOF_IPC_STREAM_TRIG_PAUSE: - str2 = "TRIG_PAUSE"; break; - case SOF_IPC_STREAM_TRIG_RELEASE: - str2 = "TRIG_RELEASE"; break; - case SOF_IPC_STREAM_TRIG_DRAIN: - str2 = "TRIG_DRAIN"; break; - case SOF_IPC_STREAM_TRIG_XRUN: - str2 = "TRIG_XRUN"; break; - case SOF_IPC_STREAM_POSITION: - vdbg = true; - str2 = "POSITION"; break; - case SOF_IPC_STREAM_VORBIS_PARAMS: - str2 = "VORBIS_PARAMS"; break; - case SOF_IPC_STREAM_VORBIS_FREE: - str2 = "VORBIS_FREE"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_FW_READY: - str = "FW_READY"; break; - case SOF_IPC_GLB_DAI_MSG: - str = "GLB_DAI_MSG"; - switch (type) { - case SOF_IPC_DAI_CONFIG: - str2 = "CONFIG"; break; - case SOF_IPC_DAI_LOOPBACK: - str2 = "LOOPBACK"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_TRACE_MSG: - str = "GLB_TRACE_MSG"; - switch (type) { - case SOF_IPC_TRACE_DMA_PARAMS: - str2 = "DMA_PARAMS"; break; - case SOF_IPC_TRACE_DMA_POSITION: - str2 = "DMA_POSITION"; break; - case SOF_IPC_TRACE_DMA_PARAMS_EXT: - str2 = "DMA_PARAMS_EXT"; break; - case SOF_IPC_TRACE_FILTER_UPDATE: - str2 = "FILTER_UPDATE"; break; - case SOF_IPC_TRACE_DMA_FREE: - str2 = "DMA_FREE"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_TEST_MSG: - str = "GLB_TEST_MSG"; - switch (type) { - case SOF_IPC_TEST_IPC_FLOOD: - str2 = "IPC_FLOOD"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_DEBUG: - str = "GLB_DEBUG"; - switch (type) { - case SOF_IPC_DEBUG_MEM_USAGE: - str2 = "MEM_USAGE"; break; - default: - str2 = "unknown type"; break; - } - break; - case SOF_IPC_GLB_PROBE: - str = "GLB_PROBE"; - switch (type) { - case SOF_IPC_PROBE_INIT: - str2 = "INIT"; break; - case SOF_IPC_PROBE_DEINIT: - str2 = "DEINIT"; break; - case SOF_IPC_PROBE_DMA_ADD: - str2 = "DMA_ADD"; break; - case SOF_IPC_PROBE_DMA_INFO: - str2 = "DMA_INFO"; break; - case SOF_IPC_PROBE_DMA_REMOVE: - str2 = "DMA_REMOVE"; break; - case SOF_IPC_PROBE_POINT_ADD: - str2 = "POINT_ADD"; break; - case SOF_IPC_PROBE_POINT_INFO: - str2 = "POINT_INFO"; break; - case SOF_IPC_PROBE_POINT_REMOVE: - str2 = "POINT_REMOVE"; break; - default: - str2 = "unknown type"; break; - } - break; - default: - str = "unknown GLB command"; break; - } - - if (str2) { - if (vdbg) - dev_vdbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); - else - dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); - } else { - dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); - } -} -#else -static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) -{ - if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG) - dev_dbg(dev, "%s: 0x%x\n", text, cmd); -} -#endif - /** * sof_ipc_send_msg - generic function to prepare and send one IPC message * @sdev: pointer to SOF core device struct @@ -346,249 +137,6 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } EXPORT_SYMBOL(snd_sof_ipc_reply); -static void ipc_comp_notification(struct snd_sof_dev *sdev, void *msg_buf) -{ - const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - struct sof_ipc_cmd_hdr *hdr = msg_buf; - u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; - - switch (msg_type) { - case SOF_IPC_COMP_GET_VALUE: - case SOF_IPC_COMP_GET_DATA: - break; - default: - dev_err(sdev->dev, "error: unhandled component message %#x\n", msg_type); - return; - } - - if (tplg_ops->control->update) - tplg_ops->control->update(sdev, msg_buf); -} - -/* DSP firmware has sent host a message */ -void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) -{ - ipc_rx_callback rx_callback = NULL; - struct sof_ipc_cmd_hdr hdr; - void *msg_buf; - u32 cmd; - int err; - - /* read back header */ - err = snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr)); - if (err < 0) { - dev_warn(sdev->dev, "failed to read IPC header: %d\n", err); - return; - } - - if (hdr.size < sizeof(hdr)) { - dev_err(sdev->dev, "The received message size is invalid\n"); - return; - } - - ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); - - cmd = hdr.cmd & SOF_GLB_TYPE_MASK; - - /* check message type */ - switch (cmd) { - case SOF_IPC_GLB_REPLY: - dev_err(sdev->dev, "error: ipc reply unknown\n"); - break; - case SOF_IPC_FW_READY: - /* check for FW boot completion */ - if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) { - err = sof_ops(sdev)->fw_ready(sdev, cmd); - if (err < 0) - sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED); - else - sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK); - - /* wake up firmware loader */ - wake_up(&sdev->boot_wait); - } - break; - case SOF_IPC_GLB_COMPOUND: - case SOF_IPC_GLB_TPLG_MSG: - case SOF_IPC_GLB_PM_MSG: - break; - case SOF_IPC_GLB_COMP_MSG: - rx_callback = ipc_comp_notification; - break; - case SOF_IPC_GLB_STREAM_MSG: - rx_callback = ipc_stream_message; - break; - case SOF_IPC_GLB_TRACE_MSG: - rx_callback = ipc_trace_message; - break; - default: - dev_err(sdev->dev, "%s: Unknown DSP message: 0x%x\n", __func__, cmd); - break; - } - - /* read the full message */ - msg_buf = kmalloc(hdr.size, GFP_KERNEL); - if (!msg_buf) - return; - - err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size); - if (err < 0) { - dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err); - } else { - /* Call local handler for the message */ - if (rx_callback) - rx_callback(sdev, msg_buf); - - /* Notify registered clients */ - sof_client_ipc_rx_dispatcher(sdev, msg_buf); - } - - kfree(msg_buf); - - ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); -} -EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); - -/* - * IPC trace mechanism. - */ - -static void ipc_trace_message(struct snd_sof_dev *sdev, void *msg_buf) -{ - struct sof_ipc_cmd_hdr *hdr = msg_buf; - u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; - - switch (msg_type) { - case SOF_IPC_TRACE_DMA_POSITION: - snd_sof_trace_update_pos(sdev, msg_buf); - break; - default: - dev_err(sdev->dev, "error: unhandled trace message %#x\n", msg_type); - break; - } -} - -/* - * IPC stream position. - */ - -static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct snd_soc_component *scomp = sdev->component; - struct snd_sof_pcm_stream *stream; - struct sof_ipc_stream_posn posn; - struct snd_sof_pcm *spcm; - int direction, ret; - - spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); - if (!spcm) { - dev_err(sdev->dev, - "error: period elapsed for unknown stream, msg_id %d\n", - msg_id); - return; - } - - stream = &spcm->stream[direction]; - ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); - if (ret < 0) { - dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); - return; - } - - dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", - posn.host_posn, posn.dai_posn, posn.wallclock); - - memcpy(&stream->posn, &posn, sizeof(posn)); - - if (spcm->pcm.compress) - snd_sof_compr_fragment_elapsed(stream->cstream); - else if (stream->substream->runtime && - !stream->substream->runtime->no_period_wakeup) - /* only inform ALSA for period_wakeup mode */ - snd_sof_pcm_period_elapsed(stream->substream); -} - -/* DSP notifies host of an XRUN within FW */ -static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct snd_soc_component *scomp = sdev->component; - struct snd_sof_pcm_stream *stream; - struct sof_ipc_stream_posn posn; - struct snd_sof_pcm *spcm; - int direction, ret; - - spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); - if (!spcm) { - dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n", - msg_id); - return; - } - - stream = &spcm->stream[direction]; - ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); - if (ret < 0) { - dev_warn(sdev->dev, "failed to read overrun position: %d\n", ret); - return; - } - - dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", - posn.host_posn, posn.xrun_comp_id, posn.xrun_size); - -#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP) - /* stop PCM on XRUN - used for pipeline debug */ - memcpy(&stream->posn, &posn, sizeof(posn)); - snd_pcm_stop_xrun(stream->substream); -#endif -} - -/* stream notifications from DSP FW */ -static void ipc_stream_message(struct snd_sof_dev *sdev, void *msg_buf) -{ - struct sof_ipc_cmd_hdr *hdr = msg_buf; - u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; - u32 msg_id = SOF_IPC_MESSAGE_ID(hdr->cmd); - - switch (msg_type) { - case SOF_IPC_STREAM_POSITION: - ipc_period_elapsed(sdev, msg_id); - break; - case SOF_IPC_STREAM_TRIG_XRUN: - ipc_xrun(sdev, msg_id); - break; - default: - dev_err(sdev->dev, "error: unhandled stream message %#x\n", - msg_id); - break; - } -} - -/* get stream position IPC - use faster MMIO method if available on platform */ -int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp, - struct snd_sof_pcm *spcm, int direction, - struct sof_ipc_stream_posn *posn) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_stream stream; - int err; - - /* read position via slower IPC */ - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION; - stream.comp_id = spcm->stream[direction].comp_id; - - /* send IPC to the DSP */ - err = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), posn, - sizeof(*posn)); - if (err < 0) { - dev_err(sdev->dev, "error: failed to get stream %d position\n", - stream.comp_id); - return err; - } - - return 0; -} -EXPORT_SYMBOL(snd_sof_ipc_stream_posn); - /* * IPC get()/set() for kcontrols. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2bf7844f01d7..6a09e5a73a50 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -603,7 +603,10 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev); void snd_sof_ipc_free(struct snd_sof_dev *sdev); void snd_sof_ipc_get_reply(struct snd_sof_dev *sdev); void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); -void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); +static inline void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) +{ + sdev->ipc->ops->rx_msg(sdev); +} int snd_sof_ipc_valid(struct snd_sof_dev *sdev); int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes); -- cgit From e394ffb82f9c24fd6f7f4d896cb4ef32771dae7a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:06 -0700 Subject: ASoC: SOF: Add widget_kcontrol_setup control ops for IPC3 Define and set the widget_kcontrol_setup control IPC ops for IPC3. The widget_kcontrol_setup callback can be used to set up all kcontrols associated with the swidget. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-14-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc3-control.c | 38 ++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-audio.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index cdd5ad860a94..4e647142dc2b 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -578,6 +578,43 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_ snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); } +static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget) +{ + struct snd_sof_control *scontrol; + int ret; + + /* set up all controls for the widget */ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) + if (scontrol->comp_id == swidget->comp_id) { + /* set kcontrol data in DSP */ + ret = snd_sof_ipc_set_get_comp_data(scontrol, true); + if (ret < 0) { + dev_err(sdev->dev, + "kcontrol %d set up failed for widget %s\n", + scontrol->comp_id, swidget->widget->name); + return ret; + } + + /* + * Read back the data from the DSP for static widgets. + * This is particularly useful for binary kcontrols + * associated with static pipeline widgets to initialize + * the data size to match that in the DSP. + */ + if (swidget->dynamic_pipeline_widget) + continue; + + ret = snd_sof_ipc_set_get_comp_data(scontrol, false); + if (ret < 0) + dev_warn(sdev->dev, + "kcontrol %d read failed for widget %s\n", + scontrol->comp_id, swidget->widget->name); + } + + return 0; +} + const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = { .volume_put = sof_ipc3_volume_put, .volume_get = sof_ipc3_volume_get, @@ -591,4 +628,5 @@ const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = { .bytes_ext_get = sof_ipc3_bytes_ext_get, .bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get, .update = sof_ipc3_control_update, + .widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup, }; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 4a8cd7f2a0eb..c85461dbe945 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -86,6 +86,8 @@ struct sof_ipc_tplg_control_ops { const unsigned int __user *binary_data, unsigned int size); /* update control data based on notification from the DSP */ void (*update)(struct snd_sof_dev *sdev, void *ipc_control_message); + /* Optional callback to setup kcontrols associated with an swidget */ + int (*widget_kcontrol_setup)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); }; /** -- cgit From 50d4d8cf544dfbb9668dce87a21580fedb6e827f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:07 -0700 Subject: ASoC: SOF: sof-audio: Use the widget_kcontrol_setup ops for kcontrol set up Remove the local implementation and switch to the IPC neutral ops to set up the kcontrols associated with the swidget. The set up call uses snd_sof_ipc_set_get_comp_data() which is largely an IPC3 parsing function. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-15-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 54 ++++------------------------------------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 49fdfe06a9a3..c0a442272ad6 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -12,51 +12,6 @@ #include "sof-audio.h" #include "ops.h" -static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) -{ - int ret; - - ret = snd_sof_ipc_set_get_comp_data(scontrol, true); - if (ret < 0) - dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", - scontrol->comp_id); - - return ret; -} - -static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) -{ - struct snd_sof_control *scontrol; - int ret; - - /* set up all controls for the widget */ - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) - if (scontrol->comp_id == swidget->comp_id) { - /* set kcontrol data in DSP */ - ret = sof_kcontrol_setup(sdev, scontrol); - if (ret < 0) { - dev_err(sdev->dev, "error: fail to set up kcontrols for widget %s\n", - swidget->widget->name); - return ret; - } - - /* - * Read back the data from the DSP for static widgets. This is particularly - * useful for binary kcontrols associated with static pipeline widgets to - * initialize the data size to match that in the DSP. - */ - if (swidget->dynamic_pipeline_widget) - continue; - - ret = snd_sof_ipc_set_get_comp_data(scontrol, false); - if (ret < 0) - dev_warn(sdev->dev, "Failed kcontrol get for control in widget %s\n", - swidget->widget->name); - } - - return 0; -} - static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) { struct snd_sof_route *sroute; @@ -176,11 +131,10 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) } /* restore kcontrols for widget */ - ret = sof_widget_kcontrol_setup(sdev, swidget); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n", - swidget->widget->name); - goto widget_free; + if (tplg_ops->control->widget_kcontrol_setup) { + ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget); + if (ret < 0) + goto widget_free; } dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name); -- cgit From e760f102c92c16307abebffd24a31bdb3ccd78ac Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 5 Apr 2022 10:27:08 -0700 Subject: ASoC: SOF: ipc: Move the ipc_set_get_comp_data() local to ipc3-control The snd_sof_ipc_set_get_comp_data() only used for kcontrol data update and it is an IPC3 message parsing function. Move it out from the generic ipc.c to ipc3-control.c and rename it to better describe it's function. Signed-off-by: Peter Ujfalusi Reviewed-by: Daniel Baluta Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20220405172708.122168-16-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc.c | 83 ------------------------------------- sound/soc/sof/ipc3-control.c | 97 ++++++++++++++++++++++++++++++++++++++++---- sound/soc/sof/sof-audio.h | 5 --- 3 files changed, 88 insertions(+), 97 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 45c487ab8b54..6f8ac3fb195f 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -137,89 +137,6 @@ void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } EXPORT_SYMBOL(snd_sof_ipc_reply); -/* - * IPC get()/set() for kcontrols. - */ -int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set) -{ - struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct sof_ipc_ops *iops = sdev->ipc->ops; - enum sof_ipc_ctrl_type ctrl_type; - struct snd_sof_widget *swidget; - bool widget_found = false; - u32 ipc_cmd, msg_bytes; - - list_for_each_entry(swidget, &sdev->widget_list, list) { - if (swidget->comp_id == scontrol->comp_id) { - widget_found = true; - break; - } - } - - if (!widget_found) { - dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__, - scontrol->comp_id); - return -EINVAL; - } - - /* - * Volatile controls should always be part of static pipelines and the widget use_count - * would always be > 0 in this case. For the others, just return the cached value if the - * widget is not set up. - */ - if (!swidget->use_count) - return 0; - - /* - * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the - * direction - * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently - * for ctrl_type - */ - if (cdata->cmd == SOF_CTRL_CMD_BINARY) { - ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA; - ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET; - } else { - ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE; - ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET; - } - - cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; - cdata->type = ctrl_type; - cdata->comp_id = scontrol->comp_id; - cdata->msg_index = 0; - - /* calculate header and data size */ - switch (cdata->type) { - case SOF_CTRL_TYPE_VALUE_CHAN_GET: - case SOF_CTRL_TYPE_VALUE_CHAN_SET: - cdata->num_elems = scontrol->num_channels; - - msg_bytes = scontrol->num_channels * - sizeof(struct sof_ipc_ctrl_value_chan); - msg_bytes += sizeof(struct sof_ipc_ctrl_data); - break; - case SOF_CTRL_TYPE_DATA_GET: - case SOF_CTRL_TYPE_DATA_SET: - cdata->num_elems = cdata->data->size; - - msg_bytes = cdata->data->size; - msg_bytes += sizeof(struct sof_ipc_ctrl_data) + - sizeof(struct sof_abi_hdr); - break; - default: - return -EINVAL; - } - - cdata->rhdr.hdr.size = msg_bytes; - cdata->elems_remaining = 0; - - return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); -} -EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data); - int snd_sof_ipc_valid(struct snd_sof_dev *sdev) { struct sof_ipc_fw_ready *ready = &sdev->fw_ready; diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index 4e647142dc2b..cde9e481f7f2 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -11,6 +11,85 @@ #include "sof-audio.h" #include "ipc3-ops.h" +/* IPC set()/get() for kcontrols. */ +static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp); + struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; + const struct sof_ipc_ops *iops = sdev->ipc->ops; + enum sof_ipc_ctrl_type ctrl_type; + struct snd_sof_widget *swidget; + bool widget_found = false; + u32 ipc_cmd, msg_bytes; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->comp_id == scontrol->comp_id) { + widget_found = true; + break; + } + } + + if (!widget_found) { + dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__, + scontrol->comp_id); + return -EINVAL; + } + + /* + * Volatile controls should always be part of static pipelines and the widget use_count + * would always be > 0 in this case. For the others, just return the cached value if the + * widget is not set up. + */ + if (!swidget->use_count) + return 0; + + /* + * Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the + * direction + * Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently + * for ctrl_type + */ + if (cdata->cmd == SOF_CTRL_CMD_BINARY) { + ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA; + ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET; + } else { + ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE; + ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET; + } + + cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; + cdata->type = ctrl_type; + cdata->comp_id = scontrol->comp_id; + cdata->msg_index = 0; + + /* calculate header and data size */ + switch (cdata->type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + cdata->num_elems = scontrol->num_channels; + + msg_bytes = scontrol->num_channels * + sizeof(struct sof_ipc_ctrl_value_chan); + msg_bytes += sizeof(struct sof_ipc_ctrl_data); + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + cdata->num_elems = cdata->data->size; + + msg_bytes = cdata->data->size; + msg_bytes += sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_abi_hdr); + break; + default: + return -EINVAL; + } + + cdata->rhdr.hdr.size = msg_bytes; + cdata->elems_remaining = 0; + + return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); +} + static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) { if (value >= size) @@ -49,7 +128,7 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol) /* refresh the component data from DSP */ scontrol->comp_data_dirty = false; - ret = snd_sof_ipc_set_get_comp_data(scontrol, false); + ret = sof_ipc3_set_get_kcontrol_data(scontrol, false); if (ret < 0) { dev_err(scomp->dev, "Failed to get control data: %d\n", ret); @@ -97,7 +176,7 @@ static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) { - int ret = snd_sof_ipc_set_get_comp_data(scontrol, true); + int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true); if (ret < 0) { dev_err(scomp->dev, "Failed to set mixer updates for %s\n", @@ -145,7 +224,7 @@ static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol, /* notify DSP of mixer updates */ if (pm_runtime_active(scomp->dev)) { - int ret = snd_sof_ipc_set_get_comp_data(scontrol, true); + int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true); if (ret < 0) { dev_err(scomp->dev, "Failed to set mixer updates for %s\n", @@ -193,7 +272,7 @@ static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol, /* notify DSP of enum updates */ if (pm_runtime_active(scomp->dev)) { - int ret = snd_sof_ipc_set_get_comp_data(scontrol, true); + int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true); if (ret < 0) { dev_err(scomp->dev, "Failed to set enum updates for %s\n", @@ -265,7 +344,7 @@ static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) - return snd_sof_ipc_set_get_comp_data(scontrol, true); + return sof_ipc3_set_get_kcontrol_data(scontrol, true); return 0; } @@ -379,7 +458,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol, /* notify DSP of byte control updates */ if (pm_runtime_active(scomp->dev)) - return snd_sof_ipc_set_get_comp_data(scontrol, true); + return sof_ipc3_set_get_kcontrol_data(scontrol, true); return 0; } @@ -409,7 +488,7 @@ static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol, cdata->data->abi = SOF_ABI_VERSION; /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(scontrol, false); + ret = sof_ipc3_set_get_kcontrol_data(scontrol, false); if (ret < 0) return ret; @@ -588,7 +667,7 @@ static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, list_for_each_entry(scontrol, &sdev->kcontrol_list, list) if (scontrol->comp_id == swidget->comp_id) { /* set kcontrol data in DSP */ - ret = snd_sof_ipc_set_get_comp_data(scontrol, true); + ret = sof_ipc3_set_get_kcontrol_data(scontrol, true); if (ret < 0) { dev_err(sdev->dev, "kcontrol %d set up failed for widget %s\n", @@ -605,7 +684,7 @@ static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, if (swidget->dynamic_pipeline_widget) continue; - ret = snd_sof_ipc_set_get_comp_data(scontrol, false); + ret = sof_ipc3_set_get_kcontrol_data(scontrol, false); if (ret < 0) dev_warn(sdev->dev, "kcontrol %d read failed for widget %s\n", diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index c85461dbe945..0898f4dbe29f 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -431,11 +431,6 @@ static inline void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstre static inline void snd_sof_compr_init_elapsed_work(struct work_struct *work) { } #endif -/* - * Mixer IPC - */ -int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set); - /* DAI link fixup */ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); -- cgit