From 5af165ff0f919be14e1c0241812d3fa8fb5757a4 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 22 Sep 2021 12:46:20 +0800 Subject: [PATCH 1/2] ASoC: SOF: Add one more state for DMA trace Currently DMA trace has only 2 states: enabled or disabled. However DMA trace may have more states. For example, enabled but not started. This patch refines the dma trace to provide a mechanism to store more states than enabled/disabled and adds SOF_DTRACE_STOPPED state. Peter Ujfalusi Signed-off-by: Libin Yang --- sound/soc/sof/pm.c | 40 ++------------------------------------- sound/soc/sof/sof-audio.h | 36 +++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 10 ++++++++-- sound/soc/sof/trace.c | 37 +++++++++++++++++++++++++----------- 4 files changed, 72 insertions(+), 51 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index e65f4f4d6df943..b91f5952855472 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -12,42 +12,6 @@ #include "sof-priv.h" #include "sof-audio.h" -/* - * Helper function to determine the target DSP state during - * system suspend. This function only cares about the device - * D-states. Platform-specific substates, if any, should be - * handled by the platform-specific parts. - */ -static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev) -{ - u32 target_dsp_state; - - switch (sdev->system_suspend_target) { - case SOF_SUSPEND_S3: - /* DSP should be in D3 if the system is suspending to S3 */ - target_dsp_state = SOF_DSP_PM_D3; - break; - case SOF_SUSPEND_S0IX: - /* - * Currently, the only criterion for retaining the DSP in D0 - * is that there are streams that ignored the suspend trigger. - * Additional criteria such Soundwire clock-stop mode and - * device suspend latency considerations will be added later. - */ - if (snd_sof_stream_suspend_ignored(sdev)) - target_dsp_state = SOF_DSP_PM_D0; - else - target_dsp_state = SOF_DSP_PM_D3; - break; - default: - /* This case would be during runtime suspend */ - target_dsp_state = SOF_DSP_PM_D3; - break; - } - - return target_dsp_state; -} - static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx; @@ -147,8 +111,8 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } - /* resume DMA trace, only need send ipc */ - ret = snd_sof_init_trace_ipc(sdev); + /* Re-enable DMA trace */ + ret = snd_sof_enable_trace(sdev); if (ret < 0) { /* non fatal */ dev_warn(sdev->dev, diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 1c4f59d347177a..d09e84e369edef 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -255,6 +255,42 @@ int sof_set_hw_params_upon_resume(struct device *dev); bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev); bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev); +/* + * Helper function to determine the target DSP state during + * system suspend. This function only cares about the device + * D-states. Platform-specific substates, if any, should be + * handled by the platform-specific parts. + */ +static inline u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev) +{ + u32 target_dsp_state; + + switch (sdev->system_suspend_target) { + case SOF_SUSPEND_S3: + /* DSP should be in D3 if the system is suspending to S3 */ + target_dsp_state = SOF_DSP_PM_D3; + break; + case SOF_SUSPEND_S0IX: + /* + * Currently, the only criterion for retaining the DSP in D0 + * is that there are streams that ignored the suspend trigger. + * Additional criteria such Soundwire clock-stop mode and + * device suspend latency considerations will be added later. + */ + if (snd_sof_stream_suspend_ignored(sdev)) + target_dsp_state = SOF_DSP_PM_D0; + else + target_dsp_state = SOF_DSP_PM_D3; + break; + default: + /* This case would be during runtime suspend */ + target_dsp_state = SOF_DSP_PM_D3; + break; + } + + return target_dsp_state; +} + /* Machine driver enumeration */ int sof_machine_register(struct snd_sof_dev *sdev, void *pdata); void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 4f7017ef7d5aeb..2a59156372a1bd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -384,6 +384,12 @@ enum snd_sof_fw_state { SOF_FW_BOOT_COMPLETE, }; +enum sof_dtrace_state { + SOF_DTRACE_DISABLED = 0, + SOF_DTRACE_STOPPED, + SOF_DTRACE_ENABLED, +}; + /* * SOF Device Level. */ @@ -475,9 +481,9 @@ struct snd_sof_dev { wait_queue_head_t trace_sleep; u32 host_offset; bool dtrace_is_supported; /* set with Kconfig or module parameter */ - bool dtrace_is_enabled; bool dtrace_error; bool dtrace_draining; + enum sof_dtrace_state dtrace_state; bool msi_enabled; @@ -572,7 +578,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, u32 tracep_code, void *oops, struct sof_ipc_panic_info *panic_info, void *stack, size_t stack_words); -int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); +int snd_sof_enable_trace(struct snd_sof_dev *sdev); void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); int snd_sof_dbg_memory_info_init(struct snd_sof_dev *sdev); int snd_sof_debugfs_add_region_item_iomem(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index e3afc3dac7d17a..d53fb79c44f0cb 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -11,6 +11,7 @@ #include #include #include "sof-priv.h" +#include "sof-audio.h" #include "ops.h" #define TRACE_FILTER_ELEMENTS_PER_ENTRY 4 @@ -262,7 +263,7 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, if (ret) return ret; - if (!sdev->dtrace_is_enabled && sdev->dtrace_draining) { + if (sdev->dtrace_state != SOF_DTRACE_ENABLED && sdev->dtrace_draining) { /* * tracing has ended and all traces have been * read by client, return EOF @@ -338,7 +339,7 @@ static int sof_dfsentry_trace_release(struct inode *inode, struct file *file) struct snd_sof_dev *sdev = dfse->sdev; /* avoid duplicate traces at next open */ - if (!sdev->dtrace_is_enabled) + if (sdev->dtrace_state != SOF_DTRACE_ENABLED) sdev->host_offset = 0; return 0; @@ -378,7 +379,7 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) return 0; } -int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) +int snd_sof_enable_trace(struct snd_sof_dev *sdev) { struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; @@ -389,9 +390,12 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) if (!sdev->dtrace_is_supported) return 0; - if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages) + if (sdev->dtrace_state == SOF_DTRACE_ENABLED || !sdev->dma_trace_pages) return -EINVAL; + if (sdev->dtrace_state == SOF_DTRACE_STOPPED) + goto start_only; + /* set IPC parameters */ params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG; /* PARAMS_EXT is only supported from ABI 3.7.0 onwards */ @@ -429,6 +433,7 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) goto trace_release; } +start_only: ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START); if (ret < 0) { dev_err(sdev->dev, @@ -436,7 +441,7 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) goto trace_release; } - sdev->dtrace_is_enabled = true; + sdev->dtrace_state = SOF_DTRACE_ENABLED; return 0; @@ -453,7 +458,7 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) return 0; /* set false before start initialization */ - sdev->dtrace_is_enabled = false; + sdev->dtrace_state = SOF_DTRACE_DISABLED; /* allocate trace page table buffer */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, @@ -491,7 +496,7 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) init_waitqueue_head(&sdev->trace_sleep); - ret = snd_sof_init_trace_ipc(sdev); + ret = snd_sof_enable_trace(sdev); if (ret < 0) goto table_err; @@ -511,7 +516,8 @@ int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, if (!sdev->dtrace_is_supported) return 0; - if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) { + if (sdev->dtrace_state == SOF_DTRACE_ENABLED && + sdev->host_offset != posn->host_offset) { sdev->host_offset = posn->host_offset; wake_up(&sdev->trace_sleep); } @@ -530,7 +536,7 @@ void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev) if (!sdev->dtrace_is_supported) return; - if (sdev->dtrace_is_enabled) { + if (sdev->dtrace_state == SOF_DTRACE_ENABLED) { sdev->dtrace_error = true; wake_up(&sdev->trace_sleep); } @@ -540,8 +546,9 @@ EXPORT_SYMBOL(snd_sof_trace_notify_for_error); void snd_sof_release_trace(struct snd_sof_dev *sdev) { int ret; + bool only_stop; - if (!sdev->dtrace_is_supported || !sdev->dtrace_is_enabled) + if (!sdev->dtrace_is_supported || sdev->dtrace_state == SOF_DTRACE_DISABLED) return; ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); @@ -549,12 +556,20 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: snd_sof_dma_trace_trigger: stop: %d\n", ret); + only_stop = (snd_sof_dsp_power_target(sdev) == SOF_DSP_PM_D0); + if (only_stop) { + sdev->dtrace_state = SOF_DTRACE_STOPPED; + goto out; + } + ret = snd_sof_dma_trace_release(sdev); if (ret < 0) dev_err(sdev->dev, "error: fail in snd_sof_dma_trace_release %d\n", ret); - sdev->dtrace_is_enabled = false; + sdev->dtrace_state = SOF_DTRACE_DISABLED; + +out: sdev->dtrace_draining = true; wake_up(&sdev->trace_sleep); } From dc933f6d16a7571ce71cedea88fe37f68c7b8c79 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 29 Sep 2021 15:08:58 +0800 Subject: [PATCH 2/2] ASoC: SOF: disable dma trace in s0ix When system enters s0ix, the dma trace won't be used. Otherwise, the DMA will access the host memory, which will prevent entering S0ix. Driver has notified firmware not to send message through dma trace. Let's also trigger stop dma trace in driver side. Signed-off-by: Libin Yang --- sound/soc/sof/pm.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index b91f5952855472..ebd143488b8cec 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -80,11 +80,18 @@ static int sof_resume(struct device *dev, bool runtime_resume) /* * Nothing further to be done for platforms that support the low power - * D0 substate. + * D0 substate, and we need to re-enable the DMA trace if it was stopped */ if (!runtime_resume && sof_ops(sdev)->set_power_state && - old_state == SOF_DSP_PM_D0) + old_state == SOF_DSP_PM_D0) { + ret = snd_sof_enable_trace(sdev); + if (ret < 0) + /* non fatal */ + dev_warn(sdev->dev, + "failed to enable trace after resume %d\n", + ret); return 0; + } sdev->fw_state = SOF_FW_BOOT_PREPARE; @@ -174,9 +181,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) sof_tear_down_pipelines(sdev, false); - /* release trace */ - snd_sof_release_trace(sdev); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* cache debugfs contents during runtime suspend */ if (runtime_suspend) @@ -202,6 +206,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) suspend: + /* release trace */ + snd_sof_release_trace(sdev); + /* return if the DSP was not probed successfully */ if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED) return 0;