From b79934a24f6b8e0b1e9bf405775d69b853d81173 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 3 Sep 2021 11:43:37 +0300 Subject: [PATCH 01/12] ASoC: SOF: trace: Simplify count adjustment in trace_read The first count check and fixup against "buffer - lpos" can be removed as we will do the adjustment later against the "avail" in sof_dfsentry_trace_read() Signed-off-by: Peter Ujfalusi --- sound/soc/sof/trace.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index e3afc3dac7d17a..584e37a9fb8f75 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -308,9 +308,6 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, lpos_64 = lpos; lpos = do_div(lpos_64, buffer_size); - if (count > buffer_size - lpos) /* min() not used to avoid sparse warnings */ - count = buffer_size - lpos; - /* get available count based on current host offset */ avail = sof_wait_trace_avail(sdev, lpos, buffer_size); if (sdev->dtrace_error) { @@ -319,7 +316,8 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, } /* make sure count is <= avail */ - count = avail > count ? count : avail; + if (count > avail) + count = avail; /* copy available trace data to debugfs */ rem = copy_to_user(buffer, ((u8 *)(dfse->buf) + lpos), count); From e52de07919c1fe528d2b53f739677486b84f9891 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 13 Aug 2021 16:09:20 +0300 Subject: [PATCH 02/12] ASoC: SOF: Move the definition of enum snd_sof_fw_state to global header Move the enum snd_sof_fw_state to include/sound/sof.h for it to be accessible outside of the core SOF stack. Signed-off-by: Peter Ujfalusi --- include/sound/sof.h | 18 ++++++++++++++++++ sound/soc/sof/sof-priv.h | 9 --------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 23b374311d1616..989a8006d8efba 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -17,6 +17,24 @@ struct snd_sof_dsp_ops; +/** + * enum snd_sof_fw_state - DSP firmware state definitions + * @SOF_FW_BOOT_NOT_STARTED: firmware boot is not yet started + * @SOF_FW_BOOT_PREPARE: preparing for boot (firmware loading for exaqmple) + * @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress + * @SOF_FW_BOOT_FAILED: firmware boot failed + * @SOF_FW_BOOT_READY_FAILED: firmware booted but fw_ready op failed + * @SOF_FW_BOOT_COMPLETE: firmware is booted up and functional + */ +enum snd_sof_fw_state { + SOF_FW_BOOT_NOT_STARTED = 0, + SOF_FW_BOOT_PREPARE, + SOF_FW_BOOT_IN_PROGRESS, + SOF_FW_BOOT_FAILED, + SOF_FW_BOOT_READY_FAILED, + SOF_FW_BOOT_COMPLETE, +}; + /* * SOF Platform data. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index bac52ff8b50ca4..f1b5f41257f714 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -371,15 +371,6 @@ struct snd_sof_ipc_msg { bool ipc_complete; }; -enum snd_sof_fw_state { - SOF_FW_BOOT_NOT_STARTED = 0, - SOF_FW_BOOT_PREPARE, - SOF_FW_BOOT_IN_PROGRESS, - SOF_FW_BOOT_FAILED, - SOF_FW_BOOT_READY_FAILED, /* firmware booted but fw_ready op failed */ - SOF_FW_BOOT_COMPLETE, -}; - /* * SOF Device Level. */ From dc7adea325a9e1a40236633cef45107e2451efb2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 16 Aug 2021 11:38:04 +0300 Subject: [PATCH 03/12] ASoC: SOF: Introduce a macro to set the firmware state Add sof_set_fw_state() macro to wrap the sdev->fw_state management to allow actions to be taken when certain state is set or when state is changing. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 8 ++++---- sound/soc/sof/ipc.c | 4 ++-- sound/soc/sof/loader.c | 2 +- sound/soc/sof/pm.c | 6 +++--- sound/soc/sof/sof-priv.h | 13 +++++++++++++ 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 2ea29186e397b0..22a1c5090ae0ba 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -147,7 +147,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return ret; } - sdev->fw_state = SOF_FW_BOOT_PREPARE; + sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); /* check machine info */ ret = sof_machine_check(sdev); @@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_load_err; } - sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS; + sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS); /* * Boot the firmware. The FW boot status will be modified @@ -265,7 +265,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) snd_sof_remove(sdev); /* all resources freed, update state to match */ - sdev->fw_state = SOF_FW_BOOT_NOT_STARTED; + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); sdev->first_boot = true; return ret; @@ -300,7 +300,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->pdata = plat_data; sdev->first_boot = true; - sdev->fw_state = SOF_FW_BOOT_NOT_STARTED; + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) sdev->extractor_stream_tag = SOF_PROBE_INVALID_NODE_ID; #endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 70e067b434af57..e391bd09de87c2 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -452,9 +452,9 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) { err = sof_ops(sdev)->fw_ready(sdev, cmd); if (err < 0) - sdev->fw_state = SOF_FW_BOOT_READY_FAILED; + sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED); else - sdev->fw_state = SOF_FW_BOOT_COMPLETE; + sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); /* wake up firmware loader */ wake_up(&sdev->boot_wait); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 147441bd265258..5c22ca0dc0859e 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -839,7 +839,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: firmware boot failure\n"); snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); - sdev->fw_state = SOF_FW_BOOT_FAILED; + sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED); return -EIO; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index e65f4f4d6df943..ac8ae6e422a788 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -122,7 +122,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) old_state == SOF_DSP_PM_D0) return 0; - sdev->fw_state = SOF_FW_BOOT_PREPARE; + sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); /* load the firmware */ ret = snd_sof_load_firmware(sdev); @@ -133,7 +133,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } - sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS; + sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS); /* * Boot the firmware. The FW boot status will be modified @@ -257,7 +257,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) return ret; /* reset FW state */ - sdev->fw_state = SOF_FW_BOOT_NOT_STARTED; + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); sdev->enabled_cores_mask = 0; return ret; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f1b5f41257f714..1b5a074d19da61 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -577,6 +577,19 @@ static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) extern const struct dsp_arch_ops sof_xtensa_arch_ops; +/* + * Firmware state tracking + */ +static inline void sof_set_fw_state(struct snd_sof_dev *sdev, + enum snd_sof_fw_state new_state) +{ + if (sdev->fw_state == new_state) + return; + + dev_dbg(sdev->dev, "New firmware state: %d\n", new_state); + sdev->fw_state = new_state; +} + /* * Utilities */ From 3e0cb7c4816cc1017a03195ab08773a4c043e30d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 18 Aug 2021 14:19:59 +0300 Subject: [PATCH 04/12] ASoC: SOF: debug: Print out the fw_state along with the DSP dump The fw state can be an important information along with the DSP dump. Print it out before the dump. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index bcd381f495c0c5..34d971126237f5 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -831,6 +831,7 @@ void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) if (sof_ops(sdev)->dbg_dump && !sdev->dbg_dump_printed) { dev_err(sdev->dev, "------------[ DSP dump start ]------------\n"); + dev_err(sdev->dev, "DSP firmware state: %d\n", sdev->fw_state); sof_ops(sdev)->dbg_dump(sdev, flags); dev_err(sdev->dev, "------------[ DSP dump end ]------------\n"); if (!print_all) From 71779dcfa509681f75f0779b1cfcc1ecab387377 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 17 Aug 2021 09:42:41 +0300 Subject: [PATCH 05/12] ASoC: SOF: Introduce new firmware state: SOF_FW_CRASHED The SOF_FW_CRASHED state is meant to indicate the unfortunate case when the firmware has crashed after a successful boot. Signed-off-by: Peter Ujfalusi --- include/sound/sof.h | 2 ++ sound/soc/sof/debug.c | 1 + sound/soc/sof/ipc.c | 2 +- sound/soc/sof/ops.c | 1 + sound/soc/sof/pm.c | 7 +++++++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 989a8006d8efba..cbaaa90c7b3311 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -25,6 +25,7 @@ struct snd_sof_dsp_ops; * @SOF_FW_BOOT_FAILED: firmware boot failed * @SOF_FW_BOOT_READY_FAILED: firmware booted but fw_ready op failed * @SOF_FW_BOOT_COMPLETE: firmware is booted up and functional + * @SOF_FW_CRASHED: firmware crashed after successful boot */ enum snd_sof_fw_state { SOF_FW_BOOT_NOT_STARTED = 0, @@ -33,6 +34,7 @@ enum snd_sof_fw_state { SOF_FW_BOOT_FAILED, SOF_FW_BOOT_READY_FAILED, SOF_FW_BOOT_COMPLETE, + SOF_FW_CRASHED, }; /* diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 34d971126237f5..6d937ee7de910e 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -865,6 +865,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) /* dump vital information to the logs */ snd_sof_ipc_dump(sdev); snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + sof_set_fw_state(sdev, SOF_FW_CRASHED); snd_sof_trace_notify_for_error(sdev); } EXPORT_SYMBOL(snd_sof_handle_fw_exception); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index e391bd09de87c2..cfb1af87029a81 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -281,7 +281,7 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, struct snd_sof_ipc_msg *msg; int ret; - if (ipc->disable_ipc_tx) + if (ipc->disable_ipc_tx || sdev->fw_state == SOF_FW_CRASHED) return -ENODEV; /* diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 11ecebd079073f..92a64114bfd0ac 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -158,6 +158,7 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) sdev->dsp_oops_offset, offset); snd_sof_dsp_dbg_dump(sdev, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); + sof_set_fw_state(sdev, SOF_FW_CRASHED); snd_sof_trace_notify_for_error(sdev); } EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index ac8ae6e422a788..f22b5ee2347868 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -312,6 +312,13 @@ int snd_sof_prepare(struct device *dev) /* will suspend to S3 by default */ sdev->system_suspend_target = SOF_SUSPEND_S3; + /* + * if the firmware is crashed then we try to aim for S3 to reboot the + * firmware + */ + if (sdev->fw_state == SOF_FW_CRASHED) + return 0; + if (!desc->use_acpi_target_states) return 0; From 759888a5af9cefd2efbe1428fd1a7c9ad9caa61f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 27 Aug 2021 12:27:29 +0300 Subject: [PATCH 06/12] ASoC: SOF: Introduce new firmware state: SOF_FW_BOOT_READY_OK The SOF_FW_BOOT_READY_OK fw_state indicates that the boot ready message has been received and there were no errors found. The SOF_FW_BOOT_COMPLETE state will be reached after the snd_sof_dsp_post_fw_run() completes without error. Signed-off-by: Peter Ujfalusi --- include/sound/sof.h | 2 ++ sound/soc/sof/ipc.c | 2 +- sound/soc/sof/loader.c | 7 ++++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index cbaaa90c7b3311..9102fdbe1d4615 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -24,6 +24,7 @@ struct snd_sof_dsp_ops; * @SOF_FW_BOOT_IN_PROGRESS: firmware boot is in progress * @SOF_FW_BOOT_FAILED: firmware boot failed * @SOF_FW_BOOT_READY_FAILED: firmware booted but fw_ready op failed + * @SOF_FW_BOOT_READY_OK: firmware booted and fw_ready op is OK * @SOF_FW_BOOT_COMPLETE: firmware is booted up and functional * @SOF_FW_CRASHED: firmware crashed after successful boot */ @@ -33,6 +34,7 @@ enum snd_sof_fw_state { SOF_FW_BOOT_IN_PROGRESS, SOF_FW_BOOT_FAILED, SOF_FW_BOOT_READY_FAILED, + SOF_FW_BOOT_READY_OK, SOF_FW_BOOT_COMPLETE, SOF_FW_CRASHED, }; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index cfb1af87029a81..5caff5468c65b7 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -454,7 +454,7 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) if (err < 0) sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED); else - sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); + sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK); /* wake up firmware loader */ wake_up(&sdev->boot_wait); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 5c22ca0dc0859e..462de18e7d5aaf 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -843,9 +843,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) return -EIO; } - if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) - dev_dbg(sdev->dev, "firmware boot complete\n"); - else + if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED) return -EIO; /* FW boots but fw_ready op failed */ /* perform post fw run operations */ @@ -855,6 +853,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) return ret; } + dev_dbg(sdev->dev, "firmware boot complete\n"); + sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); + return 0; } EXPORT_SYMBOL(snd_sof_run_firmware); From fdac6cd8766d8850441bf7c69340be761981cf21 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Jul 2021 11:13:03 +0300 Subject: [PATCH 07/12] ASoC: SOF: core: Unregister machine driver before IPC and debugfs To ensure clean unload of the machine driver, components and topology, do the unregister before we free IPC and debugfs. It is a possibility that part of the unregister we would have IPC communication with the firmware. Suggested-by: Pierre-Louis Bossart Signed-off-by: Peter Ujfalusi --- sound/soc/sof/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 22a1c5090ae0ba..8625753e2bd81b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,6 +362,13 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); + /* + * Unregister machine driver. This will unbind the snd_card which + * will remove the component driver and unload the topology + * before freeing the snd_card. + */ + snd_sof_machine_unregister(sdev, pdata); + if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) { ret = snd_sof_dsp_power_down_notify(sdev); if (ret < 0) @@ -373,13 +380,6 @@ int snd_sof_device_remove(struct device *dev) snd_sof_free_trace(sdev); } - /* - * Unregister machine driver. This will unbind the snd_card which - * will remove the component driver and unload the topology - * before freeing the snd_card. - */ - snd_sof_machine_unregister(sdev, pdata); - /* * Unregistering the machine driver results in unloading the topology. * Some widgets, ex: scheduler, attempt to power down the core they are From 324543c24b485af06deb832f12b6eaac61af3bbf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 6 Jul 2021 16:38:08 +0300 Subject: [PATCH 08/12] ASoC: SOF: ipc: Read and pass the whole message to handlers for IPC events Change the parameter list for the firmware initiated message (IPC event) handler functions to: handler(struct snd_sof_dev *sdev, void *full_msg); Allocate memory and read the whole message in snd_sof_ipc_msgs_rx() then pass the pointer to the function handling the message. Do this only if we actually have a function which is tasked to process the given type. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc.c | 76 +++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 5caff5468c65b7..54dee28c439e52 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -18,8 +18,10 @@ #include "sof-audio.h" #include "ops.h" -static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_type); -static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); +typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *full_msg); + +static void ipc_trace_message(struct snd_sof_dev *sdev, void *full_msg); +static void ipc_stream_message(struct snd_sof_dev *sdev, void *full_msg); /* * IPC message Tx/Rx message handling. @@ -391,44 +393,30 @@ 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, - struct sof_ipc_cmd_hdr *hdr) +static void ipc_comp_notification(struct snd_sof_dev *sdev, void *full_msg) { + struct sof_ipc_cmd_hdr *hdr = full_msg; u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; - struct sof_ipc_ctrl_data *cdata; - int ret; switch (msg_type) { case SOF_IPC_COMP_GET_VALUE: case SOF_IPC_COMP_GET_DATA: - cdata = kmalloc(hdr->size, GFP_KERNEL); - if (!cdata) - return; - - /* read back full message */ - ret = snd_sof_ipc_msg_data(sdev, NULL, cdata, hdr->size); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to read component event: %d\n", ret); - goto err; - } break; default: dev_err(sdev->dev, "error: unhandled component message %#x\n", msg_type); return; } - snd_sof_control_notify(sdev, cdata); - -err: - kfree(cdata); + snd_sof_control_notify(sdev, full_msg); } /* 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; - u32 cmd, type; + void *full_msg; + u32 cmd; int err; /* read back header */ @@ -440,7 +428,6 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); cmd = hdr.cmd & SOF_GLB_TYPE_MASK; - type = hdr.cmd & SOF_CMD_TYPE_MASK; /* check message type */ switch (cmd) { @@ -465,20 +452,34 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) case SOF_IPC_GLB_PM_MSG: break; case SOF_IPC_GLB_COMP_MSG: - ipc_comp_notification(sdev, &hdr); + rx_callback = ipc_comp_notification; break; case SOF_IPC_GLB_STREAM_MSG: - /* need to pass msg id into the function */ - ipc_stream_message(sdev, hdr.cmd); + rx_callback = ipc_stream_message; break; case SOF_IPC_GLB_TRACE_MSG: - ipc_trace_message(sdev, type); + rx_callback = ipc_trace_message; break; default: dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd); break; } + if (rx_callback) { + /* read the full message as there we have rx handler for it */ + full_msg = kmalloc(hdr.size, GFP_KERNEL); + if (!full_msg) + return; + + err = snd_sof_ipc_msg_data(sdev, NULL, full_msg, hdr.size); + if (err < 0) + dev_err(sdev->dev, "failed to read message\n"); + else + rx_callback(sdev, full_msg); + + kfree(full_msg); + } + ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); @@ -487,19 +488,14 @@ EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); * IPC trace mechanism. */ -static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_type) +static void ipc_trace_message(struct snd_sof_dev *sdev, void *full_msg) { - struct sof_ipc_dma_trace_posn posn; - int ret; + struct sof_ipc_cmd_hdr *hdr = full_msg; + u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK; switch (msg_type) { case SOF_IPC_TRACE_DMA_POSITION: - /* read back full message */ - ret = snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn)); - if (ret < 0) - dev_warn(sdev->dev, "failed to read trace position: %d\n", ret); - else - snd_sof_trace_update_pos(sdev, &posn); + snd_sof_trace_update_pos(sdev, full_msg); break; default: dev_err(sdev->dev, "error: unhandled trace message %#x\n", msg_type); @@ -580,11 +576,11 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) } /* stream notifications from DSP FW */ -static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) +static void ipc_stream_message(struct snd_sof_dev *sdev, void *full_msg) { - /* get msg cmd type and msd id */ - u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK; - u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd); + struct sof_ipc_cmd_hdr *hdr = full_msg; + 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: From bee7d645431a2f813428c75d1ddc16747f57c4a2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Jul 2021 11:30:59 +0300 Subject: [PATCH 09/12] ASoC: SOF: intel: hda-trace: Pass the dma buffer pointer to hda_dsp_trace_prepare Pass the snd_dma_buffer pointer as parameter to hda_dsp_trace_prepare() function. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-trace.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 29e3da3c63db01..c5dc833b57b8fc 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -19,16 +19,15 @@ #include "../ops.h" #include "hda.h" -static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) +static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_ext_stream *stream = hda->dtrace_stream; struct hdac_stream *hstream = &stream->hstream; - struct snd_dma_buffer *dmab = &sdev->dmatb; int ret; hstream->period_bytes = 0;/* initialize period_bytes */ - hstream->bufsize = sdev->dmatb.bytes; + hstream->bufsize = dmab->bytes; ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); if (ret < 0) @@ -57,7 +56,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) * initialize capture stream, set BDL address and return corresponding * stream tag which will be sent to the firmware by IPC message. */ - ret = hda_dsp_trace_prepare(sdev); + ret = hda_dsp_trace_prepare(sdev, &sdev->dmatb); if (ret < 0) { dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret); hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag); From a339017301ac5f8ca8cf0ce7b29eaed318e84a45 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 15 Jul 2021 15:46:57 +0300 Subject: [PATCH 10/12] ASoC: SOF: Split up utils.c into sof-utils and iomem-utils The utils.c contains wrappers and implementation for accessing iomem mapped regions and a single unrelated function to create a compressed page table from snd_dma_buffer for firmware use. The later is used by the pcm and the trace code and it needs to be moved to a generic source/header for the client conversion to be possible. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/Makefile | 5 +- sound/soc/sof/{utils.c => iomem-utils.c} | 61 +------------------ sound/soc/sof/pcm.c | 1 + sound/soc/sof/sof-priv.h | 4 -- sound/soc/sof/sof-utils.c | 77 ++++++++++++++++++++++++ sound/soc/sof/sof-utils.h | 19 ++++++ sound/soc/sof/trace.c | 1 + 7 files changed, 103 insertions(+), 65 deletions(-) rename sound/soc/sof/{utils.c => iomem-utils.c} (59%) create mode 100644 sound/soc/sof/sof-utils.c create mode 100644 sound/soc/sof/sof-utils.h diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 06e5f49f7ee861..add7e9e214b45c 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o utils.o sof-audio.o stream-ipc.o + control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o snd-sof-$(CONFIG_SND_SOC_SOF_DEBUG_PROBES) += sof-probes.o snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += compress.o @@ -12,9 +12,12 @@ snd-sof-of-objs := sof-of-dev.o snd-sof-nocodec-objs := nocodec.o +snd-sof-utils-objs := sof-utils.o + obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o +obj-$(CONFIG_SND_SOC_SOF) += snd-sof-utils.o obj-$(CONFIG_SND_SOC_SOF_ACPI_DEV) += snd-sof-acpi.o obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/iomem-utils.c similarity index 59% rename from sound/soc/sof/utils.c rename to sound/soc/sof/iomem-utils.c index 66fa6602fb67a3..7228a6e041c39f 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/iomem-utils.c @@ -3,7 +3,7 @@ // This file is provided under a dual BSD/GPLv2 license. When using or // redistributing this file, you may do so under either license. // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. // // Author: Keyon Jie // @@ -125,62 +125,3 @@ int sof_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, return 0; } EXPORT_SYMBOL(sof_block_read); - -/* - * Generic buffer page table creation. - * Take the each physical page address and drop the least significant unused - * bits from each (based on PAGE_SIZE). Then pack valid page address bits - * into compressed page table. - */ - -int snd_sof_create_page_table(struct device *dev, - struct snd_dma_buffer *dmab, - unsigned char *page_table, size_t size) -{ - int i, pages; - - pages = snd_sgbuf_aligned_pages(size); - - dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n", - dmab->area, size, pages); - - for (i = 0; i < pages; i++) { - /* - * The number of valid address bits for each page is 20. - * idx determines the byte position within page_table - * where the current page's address is stored - * in the compressed page_table. - * This can be calculated by multiplying the page number by 2.5. - */ - u32 idx = (5 * i) >> 1; - u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; - u8 *pg_table; - - dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - - pg_table = (u8 *)(page_table + idx); - - /* - * pagetable compression: - * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 - * ___________pfn 0__________ __________pfn 1___________ _pfn 2... - * .... .... .... .... .... .... .... .... .... .... .... - * It is created by: - * 1. set current location to 0, PFN index i to 0 - * 2. put pfn[i] at current location in Little Endian byte order - * 3. calculate an intermediate value as - * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) - * 4. put x at offset (current location + 2) in LE byte order - * 5. increment current location by 5 bytes, increment i by 2 - * 6. continue to (2) - */ - if (i & 1) - put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, - pg_table); - else - put_unaligned_le32(pfn, pg_table); - } - - return pages; -} -EXPORT_SYMBOL(snd_sof_create_page_table); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 56db927390c98b..506ddad6f5c058 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -19,6 +19,7 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES) #include "sof-probes.h" #endif +#include "sof-utils.h" /* Create DMA buffer page table for DSP */ static int create_page_table(struct snd_soc_component *component, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1b5a074d19da61..5075924c16d962 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -503,10 +503,6 @@ void snd_sof_complete(struct device *dev); void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); -int snd_sof_create_page_table(struct device *dev, - struct snd_dma_buffer *dmab, - unsigned char *page_table, size_t size); - /* * Firmware loading. */ diff --git a/sound/soc/sof/sof-utils.c b/sound/soc/sof/sof-utils.c new file mode 100644 index 00000000000000..0d48f7174ec237 --- /dev/null +++ b/sound/soc/sof/sof-utils.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// +// Author: Keyon Jie +// + +#include +#include +#include +#include +#include +#include "sof-utils.h" + +/* + * Generic buffer page table creation. + * Take the each physical page address and drop the least significant unused + * bits from each (based on PAGE_SIZE). Then pack valid page address bits + * into compressed page table. + */ + +int snd_sof_create_page_table(struct device *dev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size) +{ + int i, pages; + + pages = snd_sgbuf_aligned_pages(size); + + dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n", + dmab->area, size, pages); + + for (i = 0; i < pages; i++) { + /* + * The number of valid address bits for each page is 20. + * idx determines the byte position within page_table + * where the current page's address is stored + * in the compressed page_table. + * This can be calculated by multiplying the page number by 2.5. + */ + u32 idx = (5 * i) >> 1; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; + u8 *pg_table; + + dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); + + pg_table = (u8 *)(page_table + idx); + + /* + * pagetable compression: + * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 + * ___________pfn 0__________ __________pfn 1___________ _pfn 2... + * .... .... .... .... .... .... .... .... .... .... .... + * It is created by: + * 1. set current location to 0, PFN index i to 0 + * 2. put pfn[i] at current location in Little Endian byte order + * 3. calculate an intermediate value as + * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) + * 4. put x at offset (current location + 2) in LE byte order + * 5. increment current location by 5 bytes, increment i by 2 + * 6. continue to (2) + */ + if (i & 1) + put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, + pg_table); + else + put_unaligned_le32(pfn, pg_table); + } + + return pages; +} +EXPORT_SYMBOL(snd_sof_create_page_table); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/sof-utils.h b/sound/soc/sof/sof-utils.h new file mode 100644 index 00000000000000..cf508ff7ff5ede --- /dev/null +++ b/sound/soc/sof/sof-utils.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Intel Corporation. All rights reserved. + */ + +#ifndef __SOC_SOF_UTILS_H +#define __SOC_SOF_UTILS_H + +struct snd_dma_buffer; +struct device; + +int snd_sof_create_page_table(struct device *dev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size); + +#endif diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 584e37a9fb8f75..a5f8b9e74cc2d6 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -12,6 +12,7 @@ #include #include "sof-priv.h" #include "ops.h" +#include "sof-utils.h" #define TRACE_FILTER_ELEMENTS_PER_ENTRY 4 #define TRACE_FILTER_MAX_CONFIG_STRING_LENGTH 1024 From fcb2d9e8f218d04b9efebf62f3b67abc461b243d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 1 Sep 2021 10:18:25 +0300 Subject: [PATCH 11/12] ASoC: soc-component: Convert the mark_module to void* The mark_module of the snd_soc_component is strict snd_pcm_substream type which prevents it to be used by compressed streams. Change the type to void* along with the snd_soc_component_module_get() and snd_soc_component_module_put() to allow the same mark to be used by compressed when it's module_get_upon_open is set to 1. Signed-off-by: Peter Ujfalusi --- include/sound/soc-component.h | 8 +++----- sound/soc/soc-component.c | 16 +++++++--------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 8c4d6830597fff..a393ac397eca86 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -220,7 +220,7 @@ struct snd_soc_component { int (*init)(struct snd_soc_component *component); /* function mark */ - struct snd_pcm_substream *mark_module; + void *mark_module; struct snd_pcm_substream *mark_open; struct snd_pcm_substream *mark_hw_params; struct snd_pcm_substream *mark_trigger; @@ -391,15 +391,13 @@ void snd_soc_component_exit_regmap(struct snd_soc_component *component); #define snd_soc_component_module_get_when_open(component, substream) \ snd_soc_component_module_get(component, substream, 1) int snd_soc_component_module_get(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open); + void *mark, int upon_open); #define snd_soc_component_module_put_when_remove(component) \ snd_soc_component_module_put(component, NULL, 0, 0) #define snd_soc_component_module_put_when_close(component, substream, rollback) \ snd_soc_component_module_put(component, substream, 1, rollback) void snd_soc_component_module_put(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open, int rollback); + void *mark, int upon_open, int rollback); static inline void snd_soc_component_set_drvdata(struct snd_soc_component *c, void *data) diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 8e8d917d22f8ff..82a1430313dccd 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -251,8 +251,7 @@ int snd_soc_component_set_jack(struct snd_soc_component *component, EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); int snd_soc_component_module_get(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open) + void *mark, int upon_open) { int ret = 0; @@ -260,25 +259,24 @@ int snd_soc_component_module_get(struct snd_soc_component *component, !try_module_get(component->dev->driver->owner)) ret = -ENODEV; - /* mark substream if succeeded */ + /* mark module if succeeded */ if (ret == 0) - soc_component_mark_push(component, substream, module); + soc_component_mark_push(component, mark, module); return soc_component_ret(component, ret); } void snd_soc_component_module_put(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int upon_open, int rollback) + void *mark, int upon_open, int rollback) { - if (rollback && !soc_component_mark_match(component, substream, module)) + if (rollback && !soc_component_mark_match(component, mark, module)) return; if (component->driver->module_get_upon_open == !!upon_open) module_put(component->dev->driver->owner); - /* remove marked substream */ - soc_component_mark_pop(component, substream, module); + /* remove the mark from module */ + soc_component_mark_pop(component, mark, module); } int snd_soc_component_open(struct snd_soc_component *component, From ce59c6f8a54a9645dcc8025933fe32da578889a8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 1 Sep 2021 11:18:31 +0300 Subject: [PATCH 12/12] ASoC: compress/component: Use module_get_when_open/put_when_close for cstream Currently the try_module_get() and module_put() is not possible for compressed streams if the module_get_upon_open is set to 1 which means that\ the components are not protected in a same way as components when normal audio is used. SOF is setting module_get_upon_open to 1 for component drivers which works correctly for audio stream but when compressed stream is used then the module is not protected. Convert the compress open and free operation to mimic the steps of it's pcm counterpart to fix this issue. Signed-off-by: Peter Ujfalusi --- include/sound/soc-component.h | 6 +++-- sound/soc/soc-component.c | 45 +++++++++++++++-------------------- sound/soc/soc-compress.c | 43 +++++++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index a393ac397eca86..e09a2d108e8c42 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -453,8 +453,10 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, const struct of_phandle_args *args, const char **dai_name); -int snd_soc_component_compr_open(struct snd_compr_stream *cstream); -void snd_soc_component_compr_free(struct snd_compr_stream *cstream, +int snd_soc_component_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream); +void snd_soc_component_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int rollback); int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd); int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 82a1430313dccd..a08a897c52305f 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -423,43 +423,36 @@ EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); #endif -int snd_soc_component_compr_open(struct snd_compr_stream *cstream) +int snd_soc_component_compr_open(struct snd_soc_component *component, + struct snd_compr_stream *cstream) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i, ret; + int ret = 0; - for_each_rtd_components(rtd, i, component) { - if (component->driver->compress_ops && - component->driver->compress_ops->open) { - ret = component->driver->compress_ops->open(component, cstream); - if (ret < 0) - return soc_component_ret(component, ret); - } + if (component->driver->compress_ops && + component->driver->compress_ops->open) + ret = component->driver->compress_ops->open(component, cstream); + + /* mark substream if succeeded */ + if (ret == 0) soc_component_mark_push(component, cstream, compr_open); - } - return 0; + return soc_component_ret(component, ret); } EXPORT_SYMBOL_GPL(snd_soc_component_compr_open); -void snd_soc_component_compr_free(struct snd_compr_stream *cstream, +void snd_soc_component_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *cstream, int rollback) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component; - int i; - - for_each_rtd_components(rtd, i, component) { - if (rollback && !soc_component_mark_match(component, cstream, compr_open)) - continue; + if (rollback && !soc_component_mark_match(component, cstream, compr_open)) + return; - if (component->driver->compress_ops && - component->driver->compress_ops->free) - component->driver->compress_ops->free(component, cstream); + if (component->driver->compress_ops && + component->driver->compress_ops->free) + component->driver->compress_ops->free(component, cstream); - soc_component_mark_pop(component, cstream, compr_open); - } + /* remove marked substream */ + soc_component_mark_pop(component, cstream, compr_open); } EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 36060800e9bd97..8e2494a9f3a7f0 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -22,6 +22,39 @@ #include #include +static int snd_soc_compr_components_open(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int ret = 0; + int i; + + for_each_rtd_components(rtd, i, component) { + ret = snd_soc_component_module_get_when_open(component, cstream); + if (ret < 0) + break; + + ret = snd_soc_component_compr_open(component, cstream); + if (ret < 0) + break; + } + + return ret; +} + +static void snd_soc_compr_components_free(struct snd_compr_stream *cstream, + int rollback) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component; + int i; + + for_each_rtd_components(rtd, i, component) { + snd_soc_component_compr_free(component, cstream, rollback); + snd_soc_component_module_put_when_close(component, cstream, rollback); + } +} + static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; @@ -44,7 +77,7 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) snd_soc_link_compr_shutdown(cstream, rollback); - snd_soc_component_compr_free(cstream, rollback); + snd_soc_compr_components_free(cstream, rollback); snd_soc_dai_compr_shutdown(cpu_dai, cstream, rollback); @@ -80,7 +113,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) if (ret < 0) goto err; - ret = snd_soc_component_compr_open(cstream); + ret = snd_soc_compr_components_open(cstream); if (ret < 0) goto err; @@ -137,7 +170,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) if (ret < 0) goto out; - ret = snd_soc_component_compr_open(cstream); + ret = snd_soc_compr_components_open(cstream); if (ret < 0) goto open_err; @@ -160,7 +193,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) return 0; machine_err: - snd_soc_component_compr_free(cstream, 1); + snd_soc_compr_components_free(cstream, 1); open_err: snd_soc_dai_compr_shutdown(cpu_dai, cstream, 1); out: @@ -205,7 +238,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) snd_soc_link_compr_shutdown(cstream, 0); - snd_soc_component_compr_free(cstream, 0); + snd_soc_compr_components_free(cstream, 0); snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);