1 /*
2 * Copyright (c) 2019 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: wlan_hdd_debugfs_config.c
22 *
23 * WLAN Host Device Driver implementation to update
24 * debugfs with ini configs
25 */
26
27 #include "wlan_hdd_main.h"
28 #include "osif_psoc_sync.h"
29 #include "cfg_ucfg_api.h"
30 #include "wlan_hdd_debugfs_config.h"
31
32 #define DEBUGFS_CONFIG_BUF_SIZE (4096 * 8)
33
34 /**
35 * struct ini_config_buf - the buffer struct to save ini configs
36 * @len: buffer len
37 * @result: the pointer to buffer
38 */
39 struct ini_config_buf {
40 ssize_t len;
41 uint8_t result[DEBUGFS_CONFIG_BUF_SIZE];
42 };
43
44 /**
45 * wlan_hdd_config_update() - Update userspace with local statistics buffer
46 * @buf: userspace buffer (to which data is being copied into)
47 * @count: max data that can be copied into buf
48 * @pos: offset (where data should be copied into)
49 * @ini_config: buffer structure for ini config info
50 *
51 * This function should copies ini configs into debugfs entry.
52 *
53 * Return: number of characters copied; 0 on no-copy
54 */
wlan_hdd_config_update(char __user * buf,size_t count,loff_t * pos,struct ini_config_buf * ini_config)55 static ssize_t wlan_hdd_config_update(char __user *buf, size_t count,
56 loff_t *pos,
57 struct ini_config_buf *ini_config)
58 {
59 ssize_t ret_cnt;
60
61 ret_cnt = simple_read_from_buffer(buf, count, pos, ini_config->result,
62 ini_config->len);
63 hdd_debug("ini config read req: count: %zu, pos: %lld", count, *pos);
64
65 return ret_cnt;
66 }
67
68 /**
69 * wlan_hdd_config_get() - Function to save ini config to buffer
70 * @hdd_ctx: hdd context used to register the debugfs file
71 * @ini_config: buffer structure for ini config info
72 *
73 * Return: Errno
74 */
wlan_hdd_config_get(struct hdd_context * hdd_ctx,struct ini_config_buf * ini_config)75 static int wlan_hdd_config_get(struct hdd_context *hdd_ctx,
76 struct ini_config_buf *ini_config)
77 {
78 QDF_STATUS status;
79
80 status = ucfg_cfg_ini_config_print(hdd_ctx->psoc, ini_config->result,
81 &ini_config->len,
82 DEBUGFS_CONFIG_BUF_SIZE);
83 return qdf_status_to_os_return(status);
84 }
85
86 /**
87 * __wlan_hdd_read_config_debugfs() - function to get ini conifg
88 * @file: file pointer
89 * @buf: buffer
90 * @count: count
91 * @pos: position pointer
92 *
93 * Return: Number of bytes read on success, error number otherwise
94 */
__wlan_hdd_read_config_debugfs(struct file * file,char __user * buf,size_t count,loff_t * pos)95 static ssize_t __wlan_hdd_read_config_debugfs(struct file *file,
96 char __user *buf, size_t count,
97 loff_t *pos)
98 {
99 struct ini_config_buf *ini_config;
100 ssize_t err_size;
101
102 ini_config = (struct ini_config_buf *)file->private_data;
103 if (!ini_config)
104 return -ENOMEM;
105
106 err_size = wlan_hdd_config_update(buf, count, pos, ini_config);
107
108 return err_size;
109 }
110
111 /**
112 * wlan_hdd_read_config_debugfs() - wrapper function to get ini conifg
113 * @file: file pointer
114 * @buf: buffer
115 * @count: count
116 * @pos: position pointer
117 *
118 * Return: Number of bytes read on success, error number otherwise
119 */
wlan_hdd_read_config_debugfs(struct file * file,char __user * buf,size_t count,loff_t * pos)120 static ssize_t wlan_hdd_read_config_debugfs(struct file *file,
121 char __user *buf, size_t count,
122 loff_t *pos)
123 {
124 struct hdd_context *hdd_ctx = file_inode(file)->i_private;
125 struct osif_psoc_sync *psoc_sync;
126 ssize_t err_size;
127
128 err_size = wlan_hdd_validate_context(hdd_ctx);
129 if (err_size)
130 return err_size;
131
132 err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
133 &psoc_sync);
134 if (err_size)
135 return err_size;
136
137 err_size = __wlan_hdd_read_config_debugfs(file, buf, count, pos);
138
139 osif_psoc_sync_op_stop(psoc_sync);
140
141 return err_size;
142 }
143
144 /**
145 * __wlan_hdd_open_config_debugfs() - function to open config debugfs
146 * @inode: Pointer to inode structure
147 * @file: file pointer
148 *
149 * Return: Errno
150 */
__wlan_hdd_open_config_debugfs(struct inode * inode,struct file * file)151 static int __wlan_hdd_open_config_debugfs(struct inode *inode,
152 struct file *file)
153 {
154 struct hdd_context *hdd_ctx = file_inode(file)->i_private;
155 struct ini_config_buf *ini_config;
156 ssize_t errno;
157 void *buf;
158
159 buf = qdf_mem_malloc(sizeof(*ini_config));
160 if (!buf)
161 return -ENOMEM;
162
163 ini_config = (struct ini_config_buf *)buf;
164 hdd_nofl_debug("WLAN configuration written to debug log");
165 ucfg_cfg_store_print(hdd_ctx->psoc);
166 errno = wlan_hdd_config_get(hdd_ctx, ini_config);
167 if (errno) {
168 qdf_mem_free(buf);
169 return errno;
170 }
171
172 file->private_data = buf;
173 return 0;
174 }
175
176 /**
177 * wlan_hdd_open_config_debugfs() - wrapper function to open config debugfs
178 * @inode: Pointer to inode structure
179 * @file: file pointer
180 *
181 * Return: Errno
182 */
wlan_hdd_open_config_debugfs(struct inode * inode,struct file * file)183 static int wlan_hdd_open_config_debugfs(struct inode *inode, struct file *file)
184 {
185 struct hdd_context *hdd_ctx = file_inode(file)->i_private;
186 struct osif_psoc_sync *psoc_sync;
187 ssize_t errno;
188
189 errno = wlan_hdd_validate_context(hdd_ctx);
190 if (errno)
191 return errno;
192
193 errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
194 &psoc_sync);
195 if (errno)
196 return errno;
197
198 errno = __wlan_hdd_open_config_debugfs(inode, file);
199
200 osif_psoc_sync_op_stop(psoc_sync);
201 return errno;
202 }
203
204 /**
205 * wlan_hdd_release_config_debugfs() - wrapper to release
206 * @inode: Pointer to inode structure
207 * @file: file pointer
208 *
209 * Return: Errno
210 */
wlan_hdd_release_config_debugfs(struct inode * inode,struct file * file)211 static int wlan_hdd_release_config_debugfs(struct inode *inode,
212 struct file *file)
213 {
214 qdf_mem_free(file->private_data);
215 file->private_data = NULL;
216
217 return 0;
218 }
219
220 static const struct file_operations fops_config_debugfs = {
221 .read = wlan_hdd_read_config_debugfs,
222 .open = wlan_hdd_open_config_debugfs,
223 .release = wlan_hdd_release_config_debugfs,
224 .owner = THIS_MODULE,
225 .llseek = default_llseek,
226 };
227
hdd_debugfs_ini_config_init(struct hdd_context * hdd_ctx)228 int hdd_debugfs_ini_config_init(struct hdd_context *hdd_ctx)
229 {
230 if (!debugfs_create_file("ini_config", 0444, qdf_debugfs_get_root(),
231 hdd_ctx, &fops_config_debugfs))
232 return -EINVAL;
233
234 return 0;
235 }
236
hdd_debugfs_ini_config_deinit(struct hdd_context * hdd_ctx)237 void hdd_debugfs_ini_config_deinit(struct hdd_context *hdd_ctx)
238 {
239 /*
240 * Config ini doesn't have a directory it is removed
241 * as part of qdf remove
242 */
243 }
244