1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2020-2021 Intel Corporation.
6 #include <linux/pm_runtime.h>
7 #include <linux/wwan.h>
9 #include "iosm_ipc_trace.h"
11 /* sub buffer size and number of sub buffer */
12 #define IOSM_TRC_SUB_BUFF_SIZE 131072
13 #define IOSM_TRC_N_SUB_BUFF 32
15 #define IOSM_TRC_FILE_PERM 0600
17 #define IOSM_TRC_DEBUGFS_TRACE "trace"
18 #define IOSM_TRC_DEBUGFS_TRACE_CTRL "trace_ctrl"
21 * ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer
22 * @ipc_imem: Pointer to iosm_imem structure
23 * @skb: Pointer to struct sk_buff
25 void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
27 struct iosm_trace *ipc_trace = ipc_imem->trace;
29 if (ipc_trace->ipc_rchan)
30 relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
35 /* Creates relay file in debugfs. */
36 static struct dentry *
37 ipc_trace_create_buf_file_handler(const char *filename,
38 struct dentry *parent,
40 struct rchan_buf *buf,
44 return debugfs_create_file(filename, mode, parent, buf,
45 &relay_file_operations);
48 /* Removes relay file from debugfs. */
49 static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
51 debugfs_remove(dentry);
55 static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
59 if (relay_buf_full(buf)) {
60 pr_err_ratelimited("Relay_buf full dropping traces");
67 /* Relay interface callbacks */
68 static struct rchan_callbacks relay_callbacks = {
69 .subbuf_start = ipc_trace_subbuf_start_handler,
70 .create_buf_file = ipc_trace_create_buf_file_handler,
71 .remove_buf_file = ipc_trace_remove_buf_file_handler,
74 /* Copy the trace control mode to user buffer */
75 static ssize_t ipc_trace_ctrl_file_read(struct file *filp, char __user *buffer,
76 size_t count, loff_t *ppos)
78 struct iosm_trace *ipc_trace = filp->private_data;
82 mutex_lock(&ipc_trace->trc_mutex);
83 len = snprintf(buf, sizeof(buf), "%d\n", ipc_trace->mode);
84 mutex_unlock(&ipc_trace->trc_mutex);
86 return simple_read_from_buffer(buffer, count, ppos, buf, len);
89 /* Open and close the trace channel depending on user input */
90 static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
91 const char __user *buffer,
92 size_t count, loff_t *ppos)
94 struct iosm_trace *ipc_trace = filp->private_data;
98 ret = kstrtoul_from_user(buffer, count, 10, &val);
102 pm_runtime_get_sync(ipc_trace->ipc_imem->dev);
104 mutex_lock(&ipc_trace->trc_mutex);
105 if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) {
106 ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem,
109 if (!ipc_trace->channel) {
113 ipc_trace->mode = TRACE_ENABLE;
114 } else if (val == TRACE_DISABLE && ipc_trace->mode != TRACE_DISABLE) {
115 ipc_trace->mode = TRACE_DISABLE;
116 /* close trace channel */
117 ipc_imem_sys_port_close(ipc_trace->ipc_imem,
119 relay_flush(ipc_trace->ipc_rchan);
123 mutex_unlock(&ipc_trace->trc_mutex);
125 pm_runtime_mark_last_busy(ipc_trace->ipc_imem->dev);
126 pm_runtime_put_autosuspend(ipc_trace->ipc_imem->dev);
131 static const struct file_operations ipc_trace_fops = {
133 .write = ipc_trace_ctrl_file_write,
134 .read = ipc_trace_ctrl_file_read,
138 * ipc_trace_init - Create trace interface & debugfs entries
139 * @ipc_imem: Pointer to iosm_imem structure
141 * Returns: Pointer to trace instance on success else NULL
143 struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
145 struct ipc_chnl_cfg chnl_cfg = { 0 };
146 struct iosm_trace *ipc_trace;
148 ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
149 ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
152 ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
156 ipc_trace->mode = TRACE_DISABLE;
157 ipc_trace->dev = ipc_imem->dev;
158 ipc_trace->ipc_imem = ipc_imem;
159 ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3;
161 mutex_init(&ipc_trace->trc_mutex);
163 ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
165 ipc_imem->debugfs_dir,
166 ipc_trace, &ipc_trace_fops);
168 ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
169 ipc_imem->debugfs_dir,
170 IOSM_TRC_SUB_BUFF_SIZE,
172 &relay_callbacks, NULL);
178 * ipc_trace_deinit - Closing relayfs, removing debugfs entries
179 * @ipc_trace: Pointer to the iosm_trace data struct
181 void ipc_trace_deinit(struct iosm_trace *ipc_trace)
186 debugfs_remove(ipc_trace->ctrl_file);
187 relay_close(ipc_trace->ipc_rchan);
188 mutex_destroy(&ipc_trace->trc_mutex);