const struct sof_ipc_ops *ops;
};
+enum sof_dtrace_state {
+ SOF_DTRACE_DISABLED,
+ SOF_DTRACE_STOPPED,
+ SOF_DTRACE_ENABLED,
+};
+
/*
* SOF Device Level.
*/
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;
* Trace/debug
*/
int snd_sof_init_trace(struct snd_sof_dev *sdev);
-void snd_sof_release_trace(struct snd_sof_dev *sdev);
void snd_sof_free_trace(struct snd_sof_dev *sdev);
int snd_sof_dbg_init(struct snd_sof_dev *sdev);
void snd_sof_free_debug(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);
+void snd_sof_trace_suspend(struct snd_sof_dev *sdev, pm_message_t pm_state);
+int snd_sof_trace_resume(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,
#include <linux/debugfs.h>
#include <linux/sched/signal.h>
#include "sof-priv.h"
+#include "sof-audio.h"
#include "ops.h"
#include "sof-utils.h"
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
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;
return 0;
}
-int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev)
+static 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;
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;
+
/* set IPC parameters */
params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG;
/* PARAMS_EXT is only supported from ABI 3.7.0 onwards */
goto trace_release;
}
+start:
ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START);
if (ret < 0) {
dev_err(sdev->dev,
goto trace_release;
}
- sdev->dtrace_is_enabled = true;
+ sdev->dtrace_state = SOF_DTRACE_ENABLED;
return 0;
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,
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;
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);
}
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);
}
}
EXPORT_SYMBOL(snd_sof_trace_notify_for_error);
-void snd_sof_release_trace(struct snd_sof_dev *sdev)
+static void snd_sof_release_trace(struct snd_sof_dev *sdev, bool only_stop)
{
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
struct sof_ipc_reply ipc_reply;
int ret;
- 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);
+ sdev->dtrace_state = SOF_DTRACE_STOPPED;
/*
* stop and free trace DMA in the DSP. TRACE_DMA_FREE is only supported from
dev_err(sdev->dev, "DMA_TRACE_FREE failed with error: %d\n", ret);
}
+ if (only_stop)
+ 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);
}
-EXPORT_SYMBOL(snd_sof_release_trace);
+
+void snd_sof_trace_suspend(struct snd_sof_dev *sdev, pm_message_t pm_state)
+{
+ snd_sof_release_trace(sdev, pm_state.event == SOF_DSP_PM_D0);
+}
+EXPORT_SYMBOL(snd_sof_trace_suspend);
+
+int snd_sof_trace_resume(struct snd_sof_dev *sdev)
+{
+ return snd_sof_enable_trace(sdev);
+}
+EXPORT_SYMBOL(snd_sof_trace_resume);
void snd_sof_free_trace(struct snd_sof_dev *sdev)
{
if (!sdev->dtrace_is_supported)
return;
- snd_sof_release_trace(sdev);
+ /* release trace */
+ snd_sof_release_trace(sdev, false);
if (sdev->dma_trace_pages) {
snd_dma_free_pages(&sdev->dmatb);