File Index
Files and directories
Sign in
FILE

iosm_ipc_trace.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wwan/iosm/iosm_ipc_trace.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2020-2021 Intel Corporation.
  4 */
  5
  6#include <linux/wwan.h>
  7#include "iosm_ipc_trace.h"
  8
  9/* sub buffer size and number of sub buffer */
 10#define IOSM_TRC_SUB_BUFF_SIZE 131072
 11#define IOSM_TRC_N_SUB_BUFF 32
 12
 13#define IOSM_TRC_FILE_PERM 0600
 14
 15#define IOSM_TRC_DEBUGFS_TRACE "trace"
 16#define IOSM_TRC_DEBUGFS_TRACE_CTRL "trace_ctrl"
 17
 18/**
 19 * ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer
 20 * @ipc_imem:   Pointer to iosm_imem structure
 21 * @skb:        Pointer to struct sk_buff
 22 */
 23void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
 24{
 25	struct iosm_trace *ipc_trace = ipc_imem->trace;
 26
 27	if (ipc_trace->ipc_rchan)
 28		relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
 29
 30	dev_kfree_skb(skb);
 31}
 32
 33/* Creates relay file in debugfs. */
 34static struct dentry *
 35ipc_trace_create_buf_file_handler(const char *filename,
 36				  struct dentry *parent,
 37				  umode_t mode,
 38				  struct rchan_buf *buf,
 39				  int *is_global)
 40{
 41	*is_global = 1;
 42	return debugfs_create_file(filename, mode, parent, buf,
 43				   &relay_file_operations);
 44}
 45
 46/* Removes relay file from debugfs. */
 47static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
 48{
 49	debugfs_remove(dentry);
 50	return 0;
 51}
 52
 53static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
 54					  void *prev_subbuf)
 55{
 56	if (relay_buf_full(buf)) {
 57		pr_err_ratelimited("Relay_buf full dropping traces");
 58		return 0;
 59	}
 60
 61	return 1;
 62}
 63
 64/* Relay interface callbacks */
 65static struct rchan_callbacks relay_callbacks = {
 66	.subbuf_start = ipc_trace_subbuf_start_handler,
 67	.create_buf_file = ipc_trace_create_buf_file_handler,
 68	.remove_buf_file = ipc_trace_remove_buf_file_handler,
 69};
 70
 71/* Copy the trace control mode to user buffer */
 72static ssize_t ipc_trace_ctrl_file_read(struct file *filp, char __user *buffer,
 73					size_t count, loff_t *ppos)
 74{
 75	struct iosm_trace *ipc_trace = filp->private_data;
 76	char buf[16];
 77	int len;
 78
 79	mutex_lock(&ipc_trace->trc_mutex);
 80	len = snprintf(buf, sizeof(buf), "%d\n", ipc_trace->mode);
 81	mutex_unlock(&ipc_trace->trc_mutex);
 82
 83	return simple_read_from_buffer(buffer, count, ppos, buf, len);
 84}
 85
 86/* Open and close the trace channel depending on user input */
 87static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
 88					 const char __user *buffer,
 89					 size_t count, loff_t *ppos)
 90{
 91	struct iosm_trace *ipc_trace = filp->private_data;
 92	unsigned long val;
 93	int ret;
 94
 95	ret = kstrtoul_from_user(buffer, count, 10, &val);
 96	if (ret)
 97		return ret;
 98
 99	mutex_lock(&ipc_trace->trc_mutex);
100	if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) {
101		ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem,
102							    ipc_trace->chl_id,
103							    IPC_HP_CDEV_OPEN);
104		if (!ipc_trace->channel) {
105			ret = -EIO;
106			goto unlock;
107		}
108		ipc_trace->mode = TRACE_ENABLE;
109	} else if (val == TRACE_DISABLE && ipc_trace->mode != TRACE_DISABLE) {
110		ipc_trace->mode = TRACE_DISABLE;
111		/* close trace channel */
112		ipc_imem_sys_port_close(ipc_trace->ipc_imem,
113					ipc_trace->channel);
114		relay_flush(ipc_trace->ipc_rchan);
115	}
116	ret = count;
117unlock:
118	mutex_unlock(&ipc_trace->trc_mutex);
119	return ret;
120}
121
122static const struct file_operations ipc_trace_fops = {
123	.open = simple_open,
124	.write = ipc_trace_ctrl_file_write,
125	.read  = ipc_trace_ctrl_file_read,
126};
127
128/**
129 * ipc_trace_init - Create trace interface & debugfs entries
130 * @ipc_imem:   Pointer to iosm_imem structure
131 *
132 * Returns: Pointer to trace instance on success else NULL
133 */
134struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
135{
136	struct ipc_chnl_cfg chnl_cfg = { 0 };
137	struct iosm_trace *ipc_trace;
138
139	ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
140	ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
141			      IRQ_MOD_OFF);
142
143	ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
144	if (!ipc_trace)
145		return NULL;
146
147	ipc_trace->mode = TRACE_DISABLE;
148	ipc_trace->dev = ipc_imem->dev;
149	ipc_trace->ipc_imem = ipc_imem;
150	ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3;
151
152	mutex_init(&ipc_trace->trc_mutex);
153
154	ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
155						   IOSM_TRC_FILE_PERM,
156						   ipc_imem->debugfs_dir,
157						   ipc_trace, &ipc_trace_fops);
158
159	ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
160					  ipc_imem->debugfs_dir,
161					  IOSM_TRC_SUB_BUFF_SIZE,
162					  IOSM_TRC_N_SUB_BUFF,
163					  &relay_callbacks, NULL);
164
165	return ipc_trace;
166}
167
168/**
169 * ipc_trace_deinit - Closing relayfs, removing debugfs entries
170 * @ipc_trace: Pointer to the iosm_trace data struct
171 */
172void ipc_trace_deinit(struct iosm_trace *ipc_trace)
173{
174	if (!ipc_trace)
175		return;
176
177	debugfs_remove(ipc_trace->ctrl_file);
178	relay_close(ipc_trace->ipc_rchan);
179	mutex_destroy(&ipc_trace->trc_mutex);
180	kfree(ipc_trace);
181}
~/ Read-only file preview.