18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci// redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved. 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 98c2ecf20Sopenharmony_ci// 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 128c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 138c2ecf20Sopenharmony_ci#include "sof-priv.h" 148c2ecf20Sopenharmony_ci#include "ops.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic size_t sof_trace_avail(struct snd_sof_dev *sdev, 178c2ecf20Sopenharmony_ci loff_t pos, size_t buffer_size) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci loff_t host_offset = READ_ONCE(sdev->host_offset); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* 228c2ecf20Sopenharmony_ci * If host offset is less than local pos, it means write pointer of 238c2ecf20Sopenharmony_ci * host DMA buffer has been wrapped. We should output the trace data 248c2ecf20Sopenharmony_ci * at the end of host DMA buffer at first. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci if (host_offset < pos) 278c2ecf20Sopenharmony_ci return buffer_size - pos; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* If there is available trace data now, it is unnecessary to wait. */ 308c2ecf20Sopenharmony_ci if (host_offset > pos) 318c2ecf20Sopenharmony_ci return host_offset - pos; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, 378c2ecf20Sopenharmony_ci loff_t pos, size_t buffer_size) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci wait_queue_entry_t wait; 408c2ecf20Sopenharmony_ci size_t ret = sof_trace_avail(sdev, pos, buffer_size); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* data immediately available */ 438c2ecf20Sopenharmony_ci if (ret) 448c2ecf20Sopenharmony_ci return ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_enabled && sdev->dtrace_draining) { 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * tracing has ended and all traces have been 498c2ecf20Sopenharmony_ci * read by client, return EOF 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci sdev->dtrace_draining = false; 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* wait for available trace data from FW */ 568c2ecf20Sopenharmony_ci init_waitqueue_entry(&wait, current); 578c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 588c2ecf20Sopenharmony_ci add_wait_queue(&sdev->trace_sleep, &wait); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (!signal_pending(current)) { 618c2ecf20Sopenharmony_ci /* set timeout to max value, no error code */ 628c2ecf20Sopenharmony_ci schedule_timeout(MAX_SCHEDULE_TIMEOUT); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci remove_wait_queue(&sdev->trace_sleep, &wait); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return sof_trace_avail(sdev, pos, buffer_size); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, 708c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct snd_sof_dfsentry *dfse = file->private_data; 738c2ecf20Sopenharmony_ci struct snd_sof_dev *sdev = dfse->sdev; 748c2ecf20Sopenharmony_ci unsigned long rem; 758c2ecf20Sopenharmony_ci loff_t lpos = *ppos; 768c2ecf20Sopenharmony_ci size_t avail, buffer_size = dfse->size; 778c2ecf20Sopenharmony_ci u64 lpos_64; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* make sure we know about any failures on the DSP side */ 808c2ecf20Sopenharmony_ci sdev->dtrace_error = false; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* check pos and count */ 838c2ecf20Sopenharmony_ci if (lpos < 0) 848c2ecf20Sopenharmony_ci return -EINVAL; 858c2ecf20Sopenharmony_ci if (!count) 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* check for buffer wrap and count overflow */ 898c2ecf20Sopenharmony_ci lpos_64 = lpos; 908c2ecf20Sopenharmony_ci lpos = do_div(lpos_64, buffer_size); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (count > buffer_size - lpos) /* min() not used to avoid sparse warnings */ 938c2ecf20Sopenharmony_ci count = buffer_size - lpos; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* get available count based on current host offset */ 968c2ecf20Sopenharmony_ci avail = sof_wait_trace_avail(sdev, lpos, buffer_size); 978c2ecf20Sopenharmony_ci if (sdev->dtrace_error) { 988c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: trace IO error\n"); 998c2ecf20Sopenharmony_ci return -EIO; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* make sure count is <= avail */ 1038c2ecf20Sopenharmony_ci count = avail > count ? count : avail; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* copy available trace data to debugfs */ 1068c2ecf20Sopenharmony_ci rem = copy_to_user(buffer, ((u8 *)(dfse->buf) + lpos), count); 1078c2ecf20Sopenharmony_ci if (rem) 1088c2ecf20Sopenharmony_ci return -EFAULT; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci *ppos += count; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* move debugfs reading position */ 1138c2ecf20Sopenharmony_ci return count; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int sof_dfsentry_trace_release(struct inode *inode, struct file *file) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct snd_sof_dfsentry *dfse = inode->i_private; 1198c2ecf20Sopenharmony_ci struct snd_sof_dev *sdev = dfse->sdev; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* avoid duplicate traces at next open */ 1228c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_enabled) 1238c2ecf20Sopenharmony_ci sdev->host_offset = 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const struct file_operations sof_dfs_trace_fops = { 1298c2ecf20Sopenharmony_ci .open = simple_open, 1308c2ecf20Sopenharmony_ci .read = sof_dfsentry_trace_read, 1318c2ecf20Sopenharmony_ci .llseek = default_llseek, 1328c2ecf20Sopenharmony_ci .release = sof_dfsentry_trace_release, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int trace_debugfs_create(struct snd_sof_dev *sdev) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct snd_sof_dfsentry *dfse; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (!sdev) 1408c2ecf20Sopenharmony_ci return -EINVAL; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); 1438c2ecf20Sopenharmony_ci if (!dfse) 1448c2ecf20Sopenharmony_ci return -ENOMEM; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci dfse->type = SOF_DFSENTRY_TYPE_BUF; 1478c2ecf20Sopenharmony_ci dfse->buf = sdev->dmatb.area; 1488c2ecf20Sopenharmony_ci dfse->size = sdev->dmatb.bytes; 1498c2ecf20Sopenharmony_ci dfse->sdev = sdev; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci debugfs_create_file("trace", 0444, sdev->debugfs_root, dfse, 1528c2ecf20Sopenharmony_ci &sof_dfs_trace_fops); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciint snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct sof_ipc_fw_ready *ready = &sdev->fw_ready; 1608c2ecf20Sopenharmony_ci struct sof_ipc_fw_version *v = &ready->version; 1618c2ecf20Sopenharmony_ci struct sof_ipc_dma_trace_params_ext params; 1628c2ecf20Sopenharmony_ci struct sof_ipc_reply ipc_reply; 1638c2ecf20Sopenharmony_ci int ret; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_supported) 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages) 1698c2ecf20Sopenharmony_ci return -EINVAL; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* set IPC parameters */ 1728c2ecf20Sopenharmony_ci params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG; 1738c2ecf20Sopenharmony_ci /* PARAMS_EXT is only supported from ABI 3.7.0 onwards */ 1748c2ecf20Sopenharmony_ci if (v->abi_version >= SOF_ABI_VER(3, 7, 0)) { 1758c2ecf20Sopenharmony_ci params.hdr.size = sizeof(struct sof_ipc_dma_trace_params_ext); 1768c2ecf20Sopenharmony_ci params.hdr.cmd |= SOF_IPC_TRACE_DMA_PARAMS_EXT; 1778c2ecf20Sopenharmony_ci params.timestamp_ns = ktime_get(); /* in nanosecond */ 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci params.hdr.size = sizeof(struct sof_ipc_dma_trace_params); 1808c2ecf20Sopenharmony_ci params.hdr.cmd |= SOF_IPC_TRACE_DMA_PARAMS; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci params.buffer.phy_addr = sdev->dmatp.addr; 1838c2ecf20Sopenharmony_ci params.buffer.size = sdev->dmatb.bytes; 1848c2ecf20Sopenharmony_ci params.buffer.pages = sdev->dma_trace_pages; 1858c2ecf20Sopenharmony_ci params.stream_tag = 0; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci sdev->host_offset = 0; 1888c2ecf20Sopenharmony_ci sdev->dtrace_draining = false; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = snd_sof_dma_trace_init(sdev, ¶ms.stream_tag); 1918c2ecf20Sopenharmony_ci if (ret < 0) { 1928c2ecf20Sopenharmony_ci dev_err(sdev->dev, 1938c2ecf20Sopenharmony_ci "error: fail in snd_sof_dma_trace_init %d\n", ret); 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* send IPC to the DSP */ 1998c2ecf20Sopenharmony_ci ret = sof_ipc_tx_message(sdev->ipc, 2008c2ecf20Sopenharmony_ci params.hdr.cmd, ¶ms, sizeof(params), 2018c2ecf20Sopenharmony_ci &ipc_reply, sizeof(ipc_reply)); 2028c2ecf20Sopenharmony_ci if (ret < 0) { 2038c2ecf20Sopenharmony_ci dev_err(sdev->dev, 2048c2ecf20Sopenharmony_ci "error: can't set params for DMA for trace %d\n", ret); 2058c2ecf20Sopenharmony_ci goto trace_release; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START); 2098c2ecf20Sopenharmony_ci if (ret < 0) { 2108c2ecf20Sopenharmony_ci dev_err(sdev->dev, 2118c2ecf20Sopenharmony_ci "error: snd_sof_dma_trace_trigger: start: %d\n", ret); 2128c2ecf20Sopenharmony_ci goto trace_release; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci sdev->dtrace_is_enabled = true; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_citrace_release: 2208c2ecf20Sopenharmony_ci snd_sof_dma_trace_release(sdev); 2218c2ecf20Sopenharmony_ci return ret; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciint snd_sof_init_trace(struct snd_sof_dev *sdev) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci int ret; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_supported) 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* set false before start initialization */ 2328c2ecf20Sopenharmony_ci sdev->dtrace_is_enabled = false; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* allocate trace page table buffer */ 2358c2ecf20Sopenharmony_ci ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, 2368c2ecf20Sopenharmony_ci PAGE_SIZE, &sdev->dmatp); 2378c2ecf20Sopenharmony_ci if (ret < 0) { 2388c2ecf20Sopenharmony_ci dev_err(sdev->dev, 2398c2ecf20Sopenharmony_ci "error: can't alloc page table for trace %d\n", ret); 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* allocate trace data buffer */ 2448c2ecf20Sopenharmony_ci ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 2458c2ecf20Sopenharmony_ci DMA_BUF_SIZE_FOR_TRACE, &sdev->dmatb); 2468c2ecf20Sopenharmony_ci if (ret < 0) { 2478c2ecf20Sopenharmony_ci dev_err(sdev->dev, 2488c2ecf20Sopenharmony_ci "error: can't alloc buffer for trace %d\n", ret); 2498c2ecf20Sopenharmony_ci goto page_err; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* create compressed page table for audio firmware */ 2538c2ecf20Sopenharmony_ci ret = snd_sof_create_page_table(sdev->dev, &sdev->dmatb, 2548c2ecf20Sopenharmony_ci sdev->dmatp.area, sdev->dmatb.bytes); 2558c2ecf20Sopenharmony_ci if (ret < 0) 2568c2ecf20Sopenharmony_ci goto table_err; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci sdev->dma_trace_pages = ret; 2598c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "dma_trace_pages: %d\n", sdev->dma_trace_pages); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (sdev->first_boot) { 2628c2ecf20Sopenharmony_ci ret = trace_debugfs_create(sdev); 2638c2ecf20Sopenharmony_ci if (ret < 0) 2648c2ecf20Sopenharmony_ci goto table_err; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci init_waitqueue_head(&sdev->trace_sleep); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ret = snd_sof_init_trace_ipc(sdev); 2708c2ecf20Sopenharmony_ci if (ret < 0) 2718c2ecf20Sopenharmony_ci goto table_err; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_citable_err: 2758c2ecf20Sopenharmony_ci sdev->dma_trace_pages = 0; 2768c2ecf20Sopenharmony_ci snd_dma_free_pages(&sdev->dmatb); 2778c2ecf20Sopenharmony_cipage_err: 2788c2ecf20Sopenharmony_ci snd_dma_free_pages(&sdev->dmatp); 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_init_trace); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciint snd_sof_trace_update_pos(struct snd_sof_dev *sdev, 2848c2ecf20Sopenharmony_ci struct sof_ipc_dma_trace_posn *posn) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_supported) 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) { 2908c2ecf20Sopenharmony_ci sdev->host_offset = posn->host_offset; 2918c2ecf20Sopenharmony_ci wake_up(&sdev->trace_sleep); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (posn->overflow != 0) 2958c2ecf20Sopenharmony_ci dev_err(sdev->dev, 2968c2ecf20Sopenharmony_ci "error: DSP trace buffer overflow %u bytes. Total messages %d\n", 2978c2ecf20Sopenharmony_ci posn->overflow, posn->messages); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* an error has occurred within the DSP that prevents further trace */ 3038c2ecf20Sopenharmony_civoid snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_supported) 3068c2ecf20Sopenharmony_ci return; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (sdev->dtrace_is_enabled) { 3098c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: waking up any trace sleepers\n"); 3108c2ecf20Sopenharmony_ci sdev->dtrace_error = true; 3118c2ecf20Sopenharmony_ci wake_up(&sdev->trace_sleep); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_trace_notify_for_error); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_civoid snd_sof_release_trace(struct snd_sof_dev *sdev) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci int ret; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_supported || !sdev->dtrace_is_enabled) 3218c2ecf20Sopenharmony_ci return; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); 3248c2ecf20Sopenharmony_ci if (ret < 0) 3258c2ecf20Sopenharmony_ci dev_err(sdev->dev, 3268c2ecf20Sopenharmony_ci "error: snd_sof_dma_trace_trigger: stop: %d\n", ret); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci ret = snd_sof_dma_trace_release(sdev); 3298c2ecf20Sopenharmony_ci if (ret < 0) 3308c2ecf20Sopenharmony_ci dev_err(sdev->dev, 3318c2ecf20Sopenharmony_ci "error: fail in snd_sof_dma_trace_release %d\n", ret); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci sdev->dtrace_is_enabled = false; 3348c2ecf20Sopenharmony_ci sdev->dtrace_draining = true; 3358c2ecf20Sopenharmony_ci wake_up(&sdev->trace_sleep); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_release_trace); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_civoid snd_sof_free_trace(struct snd_sof_dev *sdev) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci if (!sdev->dtrace_is_supported) 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci snd_sof_release_trace(sdev); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (sdev->dma_trace_pages) { 3478c2ecf20Sopenharmony_ci snd_dma_free_pages(&sdev->dmatb); 3488c2ecf20Sopenharmony_ci snd_dma_free_pages(&sdev->dmatp); 3498c2ecf20Sopenharmony_ci sdev->dma_trace_pages = 0; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_free_trace); 353