]> Git Repo - linux.git/blob - drivers/net/wwan/iosm/iosm_ipc_trace.c
net: bgmac: Fix return value check for fixed_phy_register()
[linux.git] / drivers / net / wwan / iosm / iosm_ipc_trace.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020-2021 Intel Corporation.
4  */
5
6 #include <linux/pm_runtime.h>
7 #include <linux/wwan.h>
8
9 #include "iosm_ipc_trace.h"
10
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
14
15 #define IOSM_TRC_FILE_PERM 0600
16
17 #define IOSM_TRC_DEBUGFS_TRACE "trace"
18 #define IOSM_TRC_DEBUGFS_TRACE_CTRL "trace_ctrl"
19
20 /**
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
24  */
25 void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
26 {
27         struct iosm_trace *ipc_trace = ipc_imem->trace;
28
29         if (ipc_trace->ipc_rchan)
30                 relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
31
32         dev_kfree_skb(skb);
33 }
34
35 /* Creates relay file in debugfs. */
36 static struct dentry *
37 ipc_trace_create_buf_file_handler(const char *filename,
38                                   struct dentry *parent,
39                                   umode_t mode,
40                                   struct rchan_buf *buf,
41                                   int *is_global)
42 {
43         *is_global = 1;
44         return debugfs_create_file(filename, mode, parent, buf,
45                                    &relay_file_operations);
46 }
47
48 /* Removes relay file from debugfs. */
49 static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
50 {
51         debugfs_remove(dentry);
52         return 0;
53 }
54
55 static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
56                                           void *prev_subbuf,
57                                           size_t prev_padding)
58 {
59         if (relay_buf_full(buf)) {
60                 pr_err_ratelimited("Relay_buf full dropping traces");
61                 return 0;
62         }
63
64         return 1;
65 }
66
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,
72 };
73
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)
77 {
78         struct iosm_trace *ipc_trace = filp->private_data;
79         char buf[16];
80         int len;
81
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);
85
86         return simple_read_from_buffer(buffer, count, ppos, buf, len);
87 }
88
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)
93 {
94         struct iosm_trace *ipc_trace = filp->private_data;
95         unsigned long val;
96         int ret;
97
98         ret = kstrtoul_from_user(buffer, count, 10, &val);
99         if (ret)
100                 return ret;
101
102         pm_runtime_get_sync(ipc_trace->ipc_imem->dev);
103
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,
107                                                             ipc_trace->chl_id,
108                                                             IPC_HP_CDEV_OPEN);
109                 if (!ipc_trace->channel) {
110                         ret = -EIO;
111                         goto unlock;
112                 }
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,
118                                         ipc_trace->channel);
119                 relay_flush(ipc_trace->ipc_rchan);
120         }
121         ret = count;
122 unlock:
123         mutex_unlock(&ipc_trace->trc_mutex);
124
125         pm_runtime_mark_last_busy(ipc_trace->ipc_imem->dev);
126         pm_runtime_put_autosuspend(ipc_trace->ipc_imem->dev);
127
128         return ret;
129 }
130
131 static const struct file_operations ipc_trace_fops = {
132         .open = simple_open,
133         .write = ipc_trace_ctrl_file_write,
134         .read  = ipc_trace_ctrl_file_read,
135 };
136
137 /**
138  * ipc_trace_init - Create trace interface & debugfs entries
139  * @ipc_imem:   Pointer to iosm_imem structure
140  *
141  * Returns: Pointer to trace instance on success else NULL
142  */
143 struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
144 {
145         struct ipc_chnl_cfg chnl_cfg = { 0 };
146         struct iosm_trace *ipc_trace;
147
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,
150                               IRQ_MOD_OFF);
151
152         ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
153         if (!ipc_trace)
154                 return NULL;
155
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;
160
161         mutex_init(&ipc_trace->trc_mutex);
162
163         ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
164                                                    IOSM_TRC_FILE_PERM,
165                                                    ipc_imem->debugfs_dir,
166                                                    ipc_trace, &ipc_trace_fops);
167
168         ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
169                                           ipc_imem->debugfs_dir,
170                                           IOSM_TRC_SUB_BUFF_SIZE,
171                                           IOSM_TRC_N_SUB_BUFF,
172                                           &relay_callbacks, NULL);
173
174         return ipc_trace;
175 }
176
177 /**
178  * ipc_trace_deinit - Closing relayfs, removing debugfs entries
179  * @ipc_trace: Pointer to the iosm_trace data struct
180  */
181 void ipc_trace_deinit(struct iosm_trace *ipc_trace)
182 {
183         if (!ipc_trace)
184                 return;
185
186         debugfs_remove(ipc_trace->ctrl_file);
187         relay_close(ipc_trace->ipc_rchan);
188         mutex_destroy(&ipc_trace->trc_mutex);
189         kfree(ipc_trace);
190 }
This page took 0.043595 seconds and 4 git commands to generate.