Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 14 additions & 43 deletions sound/soc/sof/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -116,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;

Expand All @@ -147,8 +118,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,
Expand Down Expand Up @@ -210,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)
Expand All @@ -238,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;
Expand Down
36 changes: 36 additions & 0 deletions sound/soc/sof/sof-audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down
37 changes: 26 additions & 11 deletions sound/soc/sof/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/debugfs.h>
#include <linux/sched/signal.h>
#include "sof-priv.h"
#include "sof-audio.h"
#include "ops.h"

#define TRACE_FILTER_ELEMENTS_PER_ENTRY 4
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -429,14 +433,15 @@ 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,
"error: snd_sof_dma_trace_trigger: start: %d\n", ret);
goto trace_release;
}

sdev->dtrace_is_enabled = true;
sdev->dtrace_state = SOF_DTRACE_ENABLED;

return 0;

Expand All @@ -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,
Expand Down Expand Up @@ -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;

Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -540,21 +546,30 @@ 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);
if (ret < 0)
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);
}
Expand Down