xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: wlan_hdd_debugfs.c
22*5113495bSYour Name  *
23*5113495bSYour Name  * This driver currently supports the following debugfs files:
24*5113495bSYour Name  * wlan_wcnss/wow_enable to enable/disable WoWL.
25*5113495bSYour Name  * wlan_wcnss/wow_pattern to configure WoWL patterns.
26*5113495bSYour Name  * wlan_wcnss/pattern_gen to configure periodic TX patterns.
27*5113495bSYour Name  */
28*5113495bSYour Name 
29*5113495bSYour Name #include "osif_sync.h"
30*5113495bSYour Name #include <wlan_hdd_includes.h>
31*5113495bSYour Name #include <wlan_hdd_debugfs.h>
32*5113495bSYour Name #include <wlan_osif_request_manager.h>
33*5113495bSYour Name #include <wlan_hdd_wowl.h>
34*5113495bSYour Name #include <cds_sched.h>
35*5113495bSYour Name #include <wlan_hdd_debugfs_llstat.h>
36*5113495bSYour Name #include <wlan_hdd_debugfs_mibstat.h>
37*5113495bSYour Name #include "wlan_hdd_debugfs_unit_test.h"
38*5113495bSYour Name 
39*5113495bSYour Name 
40*5113495bSYour Name #define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
41*5113495bSYour Name #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
42*5113495bSYour Name #define MAX_USER_COMMAND_SIZE_FRAME 4096
43*5113495bSYour Name 
44*5113495bSYour Name #define MAX_DEBUGFS_WAIT_ITERATIONS 20
45*5113495bSYour Name #define DEBUGFS_WAIT_SLEEP_TIME 100
46*5113495bSYour Name 
47*5113495bSYour Name static bool hdd_periodic_pattern_map[MAXNUM_PERIODIC_TX_PTRNS];
48*5113495bSYour Name 
49*5113495bSYour Name static qdf_atomic_t debugfs_thread_count;
50*5113495bSYour Name 
hdd_debugfs_thread_increment(void)51*5113495bSYour Name void hdd_debugfs_thread_increment(void)
52*5113495bSYour Name {
53*5113495bSYour Name 	qdf_atomic_inc(&debugfs_thread_count);
54*5113495bSYour Name }
55*5113495bSYour Name 
hdd_debugfs_thread_decrement(void)56*5113495bSYour Name void hdd_debugfs_thread_decrement(void)
57*5113495bSYour Name {
58*5113495bSYour Name 	qdf_atomic_dec(&debugfs_thread_count);
59*5113495bSYour Name }
60*5113495bSYour Name 
hdd_return_debugfs_threads_count(void)61*5113495bSYour Name int hdd_return_debugfs_threads_count(void)
62*5113495bSYour Name {
63*5113495bSYour Name 	return qdf_atomic_read(&debugfs_thread_count);
64*5113495bSYour Name }
65*5113495bSYour Name 
hdd_wait_for_debugfs_threads_completion(void)66*5113495bSYour Name bool hdd_wait_for_debugfs_threads_completion(void)
67*5113495bSYour Name {
68*5113495bSYour Name 	int count = MAX_DEBUGFS_WAIT_ITERATIONS;
69*5113495bSYour Name 	int r;
70*5113495bSYour Name 
71*5113495bSYour Name 	while (count) {
72*5113495bSYour Name 		r = hdd_return_debugfs_threads_count();
73*5113495bSYour Name 		if (!r)
74*5113495bSYour Name 			break;
75*5113495bSYour Name 
76*5113495bSYour Name 		if (--count) {
77*5113495bSYour Name 			hdd_debug("Waiting for %d debugfs threads to exit", r);
78*5113495bSYour Name 			qdf_sleep(DEBUGFS_WAIT_SLEEP_TIME);
79*5113495bSYour Name 		}
80*5113495bSYour Name 	}
81*5113495bSYour Name 
82*5113495bSYour Name 	/* at least one debugfs thread is executing */
83*5113495bSYour Name 	if (!count) {
84*5113495bSYour Name 		hdd_err("Timed-out waiting for debugfs threads");
85*5113495bSYour Name 		return false;
86*5113495bSYour Name 	}
87*5113495bSYour Name 
88*5113495bSYour Name 	return true;
89*5113495bSYour Name }
90*5113495bSYour Name 
91*5113495bSYour Name /**
92*5113495bSYour Name  * __wcnss_wowpattern_write() - wow_pattern debugfs handler
93*5113495bSYour Name  * @net_dev: net_device context used to register the debugfs file
94*5113495bSYour Name  * @buf: text being written to the debugfs
95*5113495bSYour Name  * @count: size of @buf
96*5113495bSYour Name  * @ppos: (unused) offset into the virtual file system
97*5113495bSYour Name  *
98*5113495bSYour Name  * Return: number of bytes processed
99*5113495bSYour Name  */
__wcnss_wowpattern_write(struct net_device * net_dev,const char __user * buf,size_t count,loff_t * ppos)100*5113495bSYour Name static ssize_t __wcnss_wowpattern_write(struct net_device *net_dev,
101*5113495bSYour Name 					const char __user *buf, size_t count,
102*5113495bSYour Name 					loff_t *ppos)
103*5113495bSYour Name {
104*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
105*5113495bSYour Name 	struct hdd_context *hdd_ctx;
106*5113495bSYour Name 	char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
107*5113495bSYour Name 	char *sptr, *token;
108*5113495bSYour Name 	uint8_t pattern_idx = 0;
109*5113495bSYour Name 	uint8_t pattern_offset = 0;
110*5113495bSYour Name 	char *pattern_buf;
111*5113495bSYour Name 	char *pattern_mask;
112*5113495bSYour Name 	int ret;
113*5113495bSYour Name 
114*5113495bSYour Name 	hdd_enter();
115*5113495bSYour Name 
116*5113495bSYour Name 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
117*5113495bSYour Name 		hdd_err("Invalid adapter or adapter has invalid magic");
118*5113495bSYour Name 		return -EINVAL;
119*5113495bSYour Name 	}
120*5113495bSYour Name 
121*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
122*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
123*5113495bSYour Name 	if (0 != ret)
124*5113495bSYour Name 		return ret;
125*5113495bSYour Name 
126*5113495bSYour Name 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
127*5113495bSYour Name 		return -EINVAL;
128*5113495bSYour Name 
129*5113495bSYour Name 	if (!sme_is_feature_supported_by_fw(WOW)) {
130*5113495bSYour Name 		hdd_err("Wake-on-Wireless feature is not supported in firmware!");
131*5113495bSYour Name 		return -EINVAL;
132*5113495bSYour Name 	}
133*5113495bSYour Name 
134*5113495bSYour Name 	if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN) {
135*5113495bSYour Name 		hdd_err("Command length is larger than %d bytes",
136*5113495bSYour Name 			MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
137*5113495bSYour Name 		return -EINVAL;
138*5113495bSYour Name 	}
139*5113495bSYour Name 
140*5113495bSYour Name 	/* Get command from user */
141*5113495bSYour Name 	if (copy_from_user(cmd, buf, count))
142*5113495bSYour Name 		return -EFAULT;
143*5113495bSYour Name 	cmd[count] = '\0';
144*5113495bSYour Name 	sptr = cmd;
145*5113495bSYour Name 
146*5113495bSYour Name 	/* Get pattern idx */
147*5113495bSYour Name 	token = strsep(&sptr, " ");
148*5113495bSYour Name 	if (!token)
149*5113495bSYour Name 		return -EINVAL;
150*5113495bSYour Name 
151*5113495bSYour Name 	if (kstrtou8(token, 0, &pattern_idx))
152*5113495bSYour Name 		return -EINVAL;
153*5113495bSYour Name 
154*5113495bSYour Name 	/* Get pattern offset */
155*5113495bSYour Name 	token = strsep(&sptr, " ");
156*5113495bSYour Name 
157*5113495bSYour Name 	/* Delete pattern if no further argument */
158*5113495bSYour Name 	if (!token) {
159*5113495bSYour Name 		hdd_del_wowl_ptrn_debugfs(adapter, pattern_idx);
160*5113495bSYour Name 
161*5113495bSYour Name 		return count;
162*5113495bSYour Name 	}
163*5113495bSYour Name 
164*5113495bSYour Name 	if (kstrtou8(token, 0, &pattern_offset))
165*5113495bSYour Name 		return -EINVAL;
166*5113495bSYour Name 
167*5113495bSYour Name 	/* Get pattern */
168*5113495bSYour Name 	token = strsep(&sptr, " ");
169*5113495bSYour Name 	if (!token)
170*5113495bSYour Name 		return -EINVAL;
171*5113495bSYour Name 
172*5113495bSYour Name 	pattern_buf = token;
173*5113495bSYour Name 
174*5113495bSYour Name 	/* Get pattern mask */
175*5113495bSYour Name 	token = strsep(&sptr, " ");
176*5113495bSYour Name 	if (!token)
177*5113495bSYour Name 		return -EINVAL;
178*5113495bSYour Name 
179*5113495bSYour Name 	pattern_mask = token;
180*5113495bSYour Name 	pattern_mask[strlen(pattern_mask) - 1] = '\0';
181*5113495bSYour Name 
182*5113495bSYour Name 	hdd_add_wowl_ptrn_debugfs(adapter, pattern_idx, pattern_offset,
183*5113495bSYour Name 				  pattern_buf, pattern_mask);
184*5113495bSYour Name 	hdd_exit();
185*5113495bSYour Name 	return count;
186*5113495bSYour Name }
187*5113495bSYour Name 
188*5113495bSYour Name /**
189*5113495bSYour Name  * wcnss_wowpattern_write() - SSR wrapper for __wcnss_wowpattern_write
190*5113495bSYour Name  * @file: file pointer
191*5113495bSYour Name  * @buf: buffer
192*5113495bSYour Name  * @count: count
193*5113495bSYour Name  * @ppos: position pointer
194*5113495bSYour Name  *
195*5113495bSYour Name  * Return: 0 on success, error number otherwise
196*5113495bSYour Name  */
wcnss_wowpattern_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)197*5113495bSYour Name static ssize_t wcnss_wowpattern_write(struct file *file,
198*5113495bSYour Name 				      const char __user *buf,
199*5113495bSYour Name 				      size_t count, loff_t *ppos)
200*5113495bSYour Name {
201*5113495bSYour Name 	struct net_device *net_dev = file_inode(file)->i_private;
202*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
203*5113495bSYour Name 	ssize_t err_size;
204*5113495bSYour Name 
205*5113495bSYour Name 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
206*5113495bSYour Name 	if (err_size)
207*5113495bSYour Name 		return err_size;
208*5113495bSYour Name 
209*5113495bSYour Name 	err_size = __wcnss_wowpattern_write(net_dev, buf, count, ppos);
210*5113495bSYour Name 
211*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
212*5113495bSYour Name 
213*5113495bSYour Name 	return err_size;
214*5113495bSYour Name }
215*5113495bSYour Name 
216*5113495bSYour Name /**
217*5113495bSYour Name  * __wcnss_patterngen_write() - pattern_gen debugfs handler
218*5113495bSYour Name  * @net_dev: net_device context used to register the debugfs file
219*5113495bSYour Name  * @buf: text being written to the debugfs
220*5113495bSYour Name  * @count: size of @buf
221*5113495bSYour Name  * @ppos: (unused) offset into the virtual file system
222*5113495bSYour Name  *
223*5113495bSYour Name  * Return: number of bytes processed
224*5113495bSYour Name  */
__wcnss_patterngen_write(struct net_device * net_dev,const char __user * buf,size_t count,loff_t * ppos)225*5113495bSYour Name static ssize_t __wcnss_patterngen_write(struct net_device *net_dev,
226*5113495bSYour Name 					const char __user *buf, size_t count,
227*5113495bSYour Name 					loff_t *ppos)
228*5113495bSYour Name {
229*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
230*5113495bSYour Name 	struct hdd_context *hdd_ctx;
231*5113495bSYour Name 	tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
232*5113495bSYour Name 	tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
233*5113495bSYour Name 
234*5113495bSYour Name 	char *cmd, *sptr, *token;
235*5113495bSYour Name 	uint8_t pattern_idx = 0;
236*5113495bSYour Name 	uint8_t pattern_duration = 0;
237*5113495bSYour Name 	char *pattern_buf;
238*5113495bSYour Name 	uint16_t pattern_len = 0;
239*5113495bSYour Name 	uint16_t i = 0;
240*5113495bSYour Name 	QDF_STATUS status;
241*5113495bSYour Name 	int ret;
242*5113495bSYour Name 
243*5113495bSYour Name 	hdd_enter();
244*5113495bSYour Name 
245*5113495bSYour Name 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
246*5113495bSYour Name 		hdd_err("Invalid adapter or adapter has invalid magic");
247*5113495bSYour Name 		return -EINVAL;
248*5113495bSYour Name 	}
249*5113495bSYour Name 
250*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
251*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
252*5113495bSYour Name 	if (0 != ret)
253*5113495bSYour Name 		return ret;
254*5113495bSYour Name 
255*5113495bSYour Name 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
256*5113495bSYour Name 		return -EINVAL;
257*5113495bSYour Name 
258*5113495bSYour Name 	if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) {
259*5113495bSYour Name 		hdd_err("Periodic Tx Pattern Offload feature is not supported in firmware!");
260*5113495bSYour Name 		return -EINVAL;
261*5113495bSYour Name 	}
262*5113495bSYour Name 
263*5113495bSYour Name 	/* Get command from user */
264*5113495bSYour Name 	if (count <= MAX_USER_COMMAND_SIZE_FRAME)
265*5113495bSYour Name 		cmd = qdf_mem_malloc(count + 1);
266*5113495bSYour Name 	else {
267*5113495bSYour Name 		hdd_err("Command length is larger than %d bytes",
268*5113495bSYour Name 			MAX_USER_COMMAND_SIZE_FRAME);
269*5113495bSYour Name 
270*5113495bSYour Name 		return -EINVAL;
271*5113495bSYour Name 	}
272*5113495bSYour Name 
273*5113495bSYour Name 	if (!cmd) {
274*5113495bSYour Name 		hdd_err("Memory allocation for cmd failed!");
275*5113495bSYour Name 		return -ENOMEM;
276*5113495bSYour Name 	}
277*5113495bSYour Name 
278*5113495bSYour Name 	if (copy_from_user(cmd, buf, count)) {
279*5113495bSYour Name 		qdf_mem_free(cmd);
280*5113495bSYour Name 		return -EFAULT;
281*5113495bSYour Name 	}
282*5113495bSYour Name 	cmd[count] = '\0';
283*5113495bSYour Name 	sptr = cmd;
284*5113495bSYour Name 
285*5113495bSYour Name 	/* Get pattern idx */
286*5113495bSYour Name 	token = strsep(&sptr, " ");
287*5113495bSYour Name 	if (!token)
288*5113495bSYour Name 		goto failure;
289*5113495bSYour Name 	if (kstrtou8(token, 0, &pattern_idx))
290*5113495bSYour Name 		goto failure;
291*5113495bSYour Name 
292*5113495bSYour Name 	if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1)) {
293*5113495bSYour Name 		hdd_err("Pattern index: %d is not in the range (0 ~ %d)",
294*5113495bSYour Name 			pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
295*5113495bSYour Name 
296*5113495bSYour Name 		goto failure;
297*5113495bSYour Name 	}
298*5113495bSYour Name 
299*5113495bSYour Name 	/* Get pattern duration */
300*5113495bSYour Name 	token = strsep(&sptr, " ");
301*5113495bSYour Name 	if (!token)
302*5113495bSYour Name 		goto failure;
303*5113495bSYour Name 	if (kstrtou8(token, 0, &pattern_duration))
304*5113495bSYour Name 		goto failure;
305*5113495bSYour Name 
306*5113495bSYour Name 	/* Delete pattern using index if duration is 0 */
307*5113495bSYour Name 	if (!pattern_duration) {
308*5113495bSYour Name 		if (!hdd_periodic_pattern_map[pattern_idx]) {
309*5113495bSYour Name 			hdd_debug_rl("WoW pattern %d is not in the table.",
310*5113495bSYour Name 				     pattern_idx);
311*5113495bSYour Name 
312*5113495bSYour Name 			qdf_mem_free(cmd);
313*5113495bSYour Name 			return -EINVAL;
314*5113495bSYour Name 		}
315*5113495bSYour Name 
316*5113495bSYour Name 		delPeriodicTxPtrnParams =
317*5113495bSYour Name 			qdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
318*5113495bSYour Name 		if (!delPeriodicTxPtrnParams) {
319*5113495bSYour Name 			qdf_mem_free(cmd);
320*5113495bSYour Name 			return -ENOMEM;
321*5113495bSYour Name 		}
322*5113495bSYour Name 
323*5113495bSYour Name 		delPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
324*5113495bSYour Name 		qdf_copy_macaddr(&delPeriodicTxPtrnParams->mac_address,
325*5113495bSYour Name 				 &adapter->mac_addr);
326*5113495bSYour Name 
327*5113495bSYour Name 		/* Delete pattern */
328*5113495bSYour Name 		status = sme_del_periodic_tx_ptrn(hdd_ctx->mac_handle,
329*5113495bSYour Name 						  delPeriodicTxPtrnParams);
330*5113495bSYour Name 		if (QDF_STATUS_SUCCESS != status) {
331*5113495bSYour Name 			hdd_err("sme_del_periodic_tx_ptrn() failed!");
332*5113495bSYour Name 
333*5113495bSYour Name 			qdf_mem_free(delPeriodicTxPtrnParams);
334*5113495bSYour Name 			goto failure;
335*5113495bSYour Name 		}
336*5113495bSYour Name 
337*5113495bSYour Name 		hdd_periodic_pattern_map[pattern_idx] = false;
338*5113495bSYour Name 
339*5113495bSYour Name 		qdf_mem_free(cmd);
340*5113495bSYour Name 		qdf_mem_free(delPeriodicTxPtrnParams);
341*5113495bSYour Name 		return count;
342*5113495bSYour Name 	}
343*5113495bSYour Name 
344*5113495bSYour Name 	/*
345*5113495bSYour Name 	 * In SAP mode allow configuration without any connection check
346*5113495bSYour Name 	 * In STA mode check if it's in connected state before adding
347*5113495bSYour Name 	 * patterns
348*5113495bSYour Name 	 */
349*5113495bSYour Name 	hdd_debug("device mode %d", adapter->device_mode);
350*5113495bSYour Name 	if ((QDF_STA_MODE == adapter->device_mode) &&
351*5113495bSYour Name 	    (!hdd_cm_is_vdev_associated(adapter->deflink))) {
352*5113495bSYour Name 		hdd_err("Not in Connected state!");
353*5113495bSYour Name 		goto failure;
354*5113495bSYour Name 	}
355*5113495bSYour Name 
356*5113495bSYour Name 	/* Get pattern */
357*5113495bSYour Name 	token = strsep(&sptr, " ");
358*5113495bSYour Name 	if (!token)
359*5113495bSYour Name 		goto failure;
360*5113495bSYour Name 
361*5113495bSYour Name 	pattern_buf = token;
362*5113495bSYour Name 	pattern_buf[strlen(pattern_buf) - 1] = '\0';
363*5113495bSYour Name 	pattern_len = strlen(pattern_buf);
364*5113495bSYour Name 
365*5113495bSYour Name 	/* Since the pattern is a hex string, 2 characters represent 1 byte. */
366*5113495bSYour Name 	if (pattern_len % 2) {
367*5113495bSYour Name 		hdd_err("Malformed pattern!");
368*5113495bSYour Name 
369*5113495bSYour Name 		goto failure;
370*5113495bSYour Name 	} else
371*5113495bSYour Name 		pattern_len >>= 1;
372*5113495bSYour Name 
373*5113495bSYour Name 	if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE) {
374*5113495bSYour Name 		hdd_err("Not an 802.3 frame!");
375*5113495bSYour Name 
376*5113495bSYour Name 		goto failure;
377*5113495bSYour Name 	}
378*5113495bSYour Name 
379*5113495bSYour Name 	addPeriodicTxPtrnParams = qdf_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
380*5113495bSYour Name 	if (!addPeriodicTxPtrnParams) {
381*5113495bSYour Name 		qdf_mem_free(cmd);
382*5113495bSYour Name 		return -ENOMEM;
383*5113495bSYour Name 	}
384*5113495bSYour Name 
385*5113495bSYour Name 	addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
386*5113495bSYour Name 	addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
387*5113495bSYour Name 	addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
388*5113495bSYour Name 	qdf_copy_macaddr(&addPeriodicTxPtrnParams->mac_address,
389*5113495bSYour Name 			 &adapter->mac_addr);
390*5113495bSYour Name 
391*5113495bSYour Name 	/* Extract the pattern */
392*5113495bSYour Name 	for (i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++) {
393*5113495bSYour Name 		addPeriodicTxPtrnParams->ucPattern[i] =
394*5113495bSYour Name 			(hex_to_bin(pattern_buf[0]) << 4) +
395*5113495bSYour Name 			hex_to_bin(pattern_buf[1]);
396*5113495bSYour Name 
397*5113495bSYour Name 		/* Skip to next byte */
398*5113495bSYour Name 		pattern_buf += 2;
399*5113495bSYour Name 	}
400*5113495bSYour Name 
401*5113495bSYour Name 	/* Add pattern */
402*5113495bSYour Name 	status = sme_add_periodic_tx_ptrn(hdd_ctx->mac_handle,
403*5113495bSYour Name 					  addPeriodicTxPtrnParams);
404*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
405*5113495bSYour Name 		hdd_err("sme_add_periodic_tx_ptrn() failed!");
406*5113495bSYour Name 
407*5113495bSYour Name 		qdf_mem_free(addPeriodicTxPtrnParams);
408*5113495bSYour Name 		goto failure;
409*5113495bSYour Name 	}
410*5113495bSYour Name 
411*5113495bSYour Name 	if (!hdd_periodic_pattern_map[pattern_idx])
412*5113495bSYour Name 		hdd_periodic_pattern_map[pattern_idx] = true;
413*5113495bSYour Name 
414*5113495bSYour Name 	qdf_mem_free(cmd);
415*5113495bSYour Name 	qdf_mem_free(addPeriodicTxPtrnParams);
416*5113495bSYour Name 	hdd_exit();
417*5113495bSYour Name 	return count;
418*5113495bSYour Name 
419*5113495bSYour Name failure:
420*5113495bSYour Name 	hdd_err("Invalid input. Input format is: ptrn_idx duration pattern");
421*5113495bSYour Name 	qdf_mem_free(cmd);
422*5113495bSYour Name 	return -EINVAL;
423*5113495bSYour Name }
424*5113495bSYour Name 
425*5113495bSYour Name /**
426*5113495bSYour Name  * wcnss_patterngen_write() - SSR wrapper for __wcnss_patterngen_write
427*5113495bSYour Name  * @file: file pointer
428*5113495bSYour Name  * @buf: buffer
429*5113495bSYour Name  * @count: count
430*5113495bSYour Name  * @ppos: position pointer
431*5113495bSYour Name  *
432*5113495bSYour Name  * Return: 0 on success, error number otherwise
433*5113495bSYour Name  */
wcnss_patterngen_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)434*5113495bSYour Name static ssize_t wcnss_patterngen_write(struct file *file,
435*5113495bSYour Name 				      const char __user *buf,
436*5113495bSYour Name 				      size_t count, loff_t *ppos)
437*5113495bSYour Name {
438*5113495bSYour Name 	struct net_device *net_dev = file_inode(file)->i_private;
439*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
440*5113495bSYour Name 	ssize_t err_size;
441*5113495bSYour Name 
442*5113495bSYour Name 	err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync);
443*5113495bSYour Name 	if (err_size)
444*5113495bSYour Name 		return err_size;
445*5113495bSYour Name 
446*5113495bSYour Name 	err_size = __wcnss_patterngen_write(net_dev, buf, count, ppos);
447*5113495bSYour Name 
448*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
449*5113495bSYour Name 
450*5113495bSYour Name 	return err_size;
451*5113495bSYour Name }
452*5113495bSYour Name 
453*5113495bSYour Name /**
454*5113495bSYour Name  * __wcnss_debugfs_open() - Generic debugfs open() handler
455*5113495bSYour Name  * @net_dev: net_device context used to register the debugfs file
456*5113495bSYour Name  *
457*5113495bSYour Name  * Return: Errno
458*5113495bSYour Name  */
__wcnss_debugfs_open(struct net_device * net_dev)459*5113495bSYour Name static int __wcnss_debugfs_open(struct net_device *net_dev)
460*5113495bSYour Name {
461*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev);
462*5113495bSYour Name 	struct hdd_context *hdd_ctx;
463*5113495bSYour Name 	int errno;
464*5113495bSYour Name 
465*5113495bSYour Name 	hdd_enter();
466*5113495bSYour Name 
467*5113495bSYour Name 	if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) {
468*5113495bSYour Name 		hdd_err("Invalid adapter or adapter has invalid magic");
469*5113495bSYour Name 		return -EINVAL;
470*5113495bSYour Name 	}
471*5113495bSYour Name 
472*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
473*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
474*5113495bSYour Name 
475*5113495bSYour Name 	hdd_exit();
476*5113495bSYour Name 
477*5113495bSYour Name 	return errno;
478*5113495bSYour Name }
479*5113495bSYour Name 
480*5113495bSYour Name /**
481*5113495bSYour Name  * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open
482*5113495bSYour Name  * @inode: inode pointer
483*5113495bSYour Name  * @file: file pointer
484*5113495bSYour Name  *
485*5113495bSYour Name  * Return: 0 on success, error number otherwise
486*5113495bSYour Name  */
wcnss_debugfs_open(struct inode * inode,struct file * file)487*5113495bSYour Name static int wcnss_debugfs_open(struct inode *inode, struct file *file)
488*5113495bSYour Name {
489*5113495bSYour Name 	struct net_device *net_dev = inode->i_private;
490*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
491*5113495bSYour Name 	int errno;
492*5113495bSYour Name 
493*5113495bSYour Name 	errno = osif_vdev_sync_op_start(net_dev, &vdev_sync);
494*5113495bSYour Name 	if (errno)
495*5113495bSYour Name 		return errno;
496*5113495bSYour Name 
497*5113495bSYour Name 	errno = __wcnss_debugfs_open(net_dev);
498*5113495bSYour Name 
499*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
500*5113495bSYour Name 
501*5113495bSYour Name 	return errno;
502*5113495bSYour Name }
503*5113495bSYour Name 
504*5113495bSYour Name static const struct file_operations fops_wowpattern = {
505*5113495bSYour Name 	.write = wcnss_wowpattern_write,
506*5113495bSYour Name 	.open = wcnss_debugfs_open,
507*5113495bSYour Name 	.owner = THIS_MODULE,
508*5113495bSYour Name 	.llseek = default_llseek,
509*5113495bSYour Name };
510*5113495bSYour Name 
511*5113495bSYour Name static const struct file_operations fops_patterngen = {
512*5113495bSYour Name 	.write = wcnss_patterngen_write,
513*5113495bSYour Name 	.open = wcnss_debugfs_open,
514*5113495bSYour Name 	.owner = THIS_MODULE,
515*5113495bSYour Name 	.llseek = default_llseek,
516*5113495bSYour Name };
517*5113495bSYour Name 
518*5113495bSYour Name /**
519*5113495bSYour Name  * hdd_debugfs_init() - Initialize debugfs interface
520*5113495bSYour Name  * @adapter: interface adapter pointer
521*5113495bSYour Name  *
522*5113495bSYour Name  * Register support for the debugfs files supported by the driver.
523*5113495bSYour Name  *
524*5113495bSYour Name  * NB: The current implementation only supports debugfs operations
525*5113495bSYour Name  * on the primary interface, i.e. wlan0
526*5113495bSYour Name  *
527*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS if all files registered,
528*5113495bSYour Name  *	   QDF_STATUS_E_FAILURE on failure
529*5113495bSYour Name  */
hdd_debugfs_init(struct hdd_adapter * adapter)530*5113495bSYour Name QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter)
531*5113495bSYour Name {
532*5113495bSYour Name 	struct net_device *net_dev = adapter->dev;
533*5113495bSYour Name 
534*5113495bSYour Name 	adapter->debugfs_phy = debugfs_create_dir(net_dev->name, 0);
535*5113495bSYour Name 
536*5113495bSYour Name 	if (!adapter->debugfs_phy) {
537*5113495bSYour Name 		hdd_err("debugfs: create folder %s fail", net_dev->name);
538*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
539*5113495bSYour Name 	}
540*5113495bSYour Name 
541*5113495bSYour Name 	if (!debugfs_create_file("wow_pattern", 00400 | 00200,
542*5113495bSYour Name 					adapter->debugfs_phy, net_dev,
543*5113495bSYour Name 					&fops_wowpattern))
544*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
545*5113495bSYour Name 
546*5113495bSYour Name 	if (!debugfs_create_file("pattern_gen", 00400 | 00200,
547*5113495bSYour Name 					adapter->debugfs_phy, net_dev,
548*5113495bSYour Name 					&fops_patterngen))
549*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
550*5113495bSYour Name 
551*5113495bSYour Name 	if (wlan_hdd_create_mib_stats_file(adapter))
552*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
553*5113495bSYour Name 
554*5113495bSYour Name 	if (wlan_hdd_create_ll_stats_file(adapter))
555*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
556*5113495bSYour Name 
557*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
558*5113495bSYour Name }
559*5113495bSYour Name 
560*5113495bSYour Name /**
561*5113495bSYour Name  * hdd_debugfs_exit() - Shutdown debugfs interface
562*5113495bSYour Name  * @adapter: interface adapter pointer
563*5113495bSYour Name  *
564*5113495bSYour Name  * Unregister support for the debugfs files supported by the driver.
565*5113495bSYour Name  *
566*5113495bSYour Name  * Return: None
567*5113495bSYour Name  */
hdd_debugfs_exit(struct hdd_adapter * adapter)568*5113495bSYour Name void hdd_debugfs_exit(struct hdd_adapter *adapter)
569*5113495bSYour Name {
570*5113495bSYour Name 	debugfs_remove_recursive(adapter->debugfs_phy);
571*5113495bSYour Name }
572