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