xref: /wlan-driver/qca-wifi-host-cmn/utils/pktlog/linux_ac.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022 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 #ifndef REMOVE_PKT_LOG
21*5113495bSYour Name #ifndef EXPORT_SYMTAB
22*5113495bSYour Name #define EXPORT_SYMTAB
23*5113495bSYour Name #endif
24*5113495bSYour Name #ifndef __KERNEL__
25*5113495bSYour Name #define __KERNEL__
26*5113495bSYour Name #endif
27*5113495bSYour Name /*
28*5113495bSYour Name  * Linux specific implementation of Pktlogs for 802.11ac
29*5113495bSYour Name  */
30*5113495bSYour Name #include <linux/kernel.h>
31*5113495bSYour Name #include <linux/init.h>
32*5113495bSYour Name #include <linux/module.h>
33*5113495bSYour Name #include <linux/vmalloc.h>
34*5113495bSYour Name #include <linux/proc_fs.h>
35*5113495bSYour Name #include <pktlog_ac_i.h>
36*5113495bSYour Name #include <pktlog_ac_fmt.h>
37*5113495bSYour Name #include "i_host_diag_core_log.h"
38*5113495bSYour Name #include "host_diag_core_log.h"
39*5113495bSYour Name #include "ani_global.h"
40*5113495bSYour Name 
41*5113495bSYour Name #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0))
42*5113495bSYour Name /*
43*5113495bSYour Name  * Commit 359745d78351 ("proc: remove PDE_DATA() completely")
44*5113495bSYour Name  * Replaced PDE_DATA() with pde_data()
45*5113495bSYour Name  */
46*5113495bSYour Name #define pde_data(inode) PDE_DATA(inode)
47*5113495bSYour Name #endif
48*5113495bSYour Name 
49*5113495bSYour Name #define PKTLOG_DEVNAME_SIZE     32
50*5113495bSYour Name #define MAX_WLANDEV             1
51*5113495bSYour Name 
52*5113495bSYour Name #ifdef MULTI_IF_NAME
53*5113495bSYour Name #define PKTLOG_PROC_DIR         "ath_pktlog" MULTI_IF_NAME
54*5113495bSYour Name #else
55*5113495bSYour Name #define PKTLOG_PROC_DIR         "ath_pktlog"
56*5113495bSYour Name #endif
57*5113495bSYour Name 
58*5113495bSYour Name /* Permissions for creating proc entries */
59*5113495bSYour Name #define PKTLOG_PROC_PERM        0444
60*5113495bSYour Name #define PKTLOG_PROCSYS_DIR_PERM 0555
61*5113495bSYour Name #define PKTLOG_PROCSYS_PERM     0644
62*5113495bSYour Name 
63*5113495bSYour Name #ifndef __MOD_INC_USE_COUNT
64*5113495bSYour Name #define PKTLOG_MOD_INC_USE_COUNT	do {			\
65*5113495bSYour Name 	if (!try_module_get(THIS_MODULE)) {			\
66*5113495bSYour Name 		qdf_nofl_info("try_module_get failed");	\
67*5113495bSYour Name 	} } while (0)
68*5113495bSYour Name 
69*5113495bSYour Name #define PKTLOG_MOD_DEC_USE_COUNT        module_put(THIS_MODULE)
70*5113495bSYour Name #else
71*5113495bSYour Name #define PKTLOG_MOD_INC_USE_COUNT        MOD_INC_USE_COUNT
72*5113495bSYour Name #define PKTLOG_MOD_DEC_USE_COUNT        MOD_DEC_USE_COUNT
73*5113495bSYour Name #endif
74*5113495bSYour Name 
75*5113495bSYour Name static struct ath_pktlog_info *g_pktlog_info;
76*5113495bSYour Name 
77*5113495bSYour Name static struct proc_dir_entry *g_pktlog_pde;
78*5113495bSYour Name 
79*5113495bSYour Name static DEFINE_MUTEX(proc_mutex);
80*5113495bSYour Name 
81*5113495bSYour Name static int pktlog_attach(struct hif_opaque_softc *scn);
82*5113495bSYour Name static void pktlog_detach(struct hif_opaque_softc *scn);
83*5113495bSYour Name static int pktlog_open(struct inode *i, struct file *f);
84*5113495bSYour Name static int pktlog_release(struct inode *i, struct file *f);
85*5113495bSYour Name static ssize_t pktlog_read(struct file *file, char *buf, size_t nbytes,
86*5113495bSYour Name 			   loff_t *ppos);
87*5113495bSYour Name 
88*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
89*5113495bSYour Name static const struct proc_ops pktlog_fops = {
90*5113495bSYour Name 	.proc_open = pktlog_open,
91*5113495bSYour Name 	.proc_release = pktlog_release,
92*5113495bSYour Name 	.proc_read = pktlog_read,
93*5113495bSYour Name 	.proc_lseek = default_llseek,
94*5113495bSYour Name };
95*5113495bSYour Name #else
96*5113495bSYour Name static struct file_operations pktlog_fops = {
97*5113495bSYour Name 	open:  pktlog_open,
98*5113495bSYour Name 	release:pktlog_release,
99*5113495bSYour Name 	read : pktlog_read,
100*5113495bSYour Name };
101*5113495bSYour Name #endif
102*5113495bSYour Name 
pktlog_disable_adapter_logging(struct hif_opaque_softc * scn)103*5113495bSYour Name void pktlog_disable_adapter_logging(struct hif_opaque_softc *scn)
104*5113495bSYour Name {
105*5113495bSYour Name 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
106*5113495bSYour Name 	if (pl_dev)
107*5113495bSYour Name 		pl_dev->pl_info->log_state = 0;
108*5113495bSYour Name }
109*5113495bSYour Name 
pktlog_alloc_buf(struct hif_opaque_softc * scn)110*5113495bSYour Name int pktlog_alloc_buf(struct hif_opaque_softc *scn)
111*5113495bSYour Name {
112*5113495bSYour Name 	uint32_t page_cnt;
113*5113495bSYour Name 	unsigned long vaddr;
114*5113495bSYour Name 	struct page *vpg;
115*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
116*5113495bSYour Name 	struct ath_pktlog_info *pl_info;
117*5113495bSYour Name 	struct ath_pktlog_buf *buffer;
118*5113495bSYour Name 
119*5113495bSYour Name 	pl_dev = get_pktlog_handle();
120*5113495bSYour Name 
121*5113495bSYour Name 	if (!pl_dev) {
122*5113495bSYour Name 		qdf_info(PKTLOG_TAG "pdev_txrx_handle->pl_dev is null");
123*5113495bSYour Name 		return -EINVAL;
124*5113495bSYour Name 	}
125*5113495bSYour Name 
126*5113495bSYour Name 	pl_info = pl_dev->pl_info;
127*5113495bSYour Name 
128*5113495bSYour Name 	page_cnt = (sizeof(*(pl_info->buf)) + pl_info->buf_size) / PAGE_SIZE;
129*5113495bSYour Name 
130*5113495bSYour Name 	qdf_spin_lock_bh(&pl_info->log_lock);
131*5113495bSYour Name 	if (pl_info->buf) {
132*5113495bSYour Name 		qdf_spin_unlock_bh(&pl_info->log_lock);
133*5113495bSYour Name 		qdf_nofl_info(PKTLOG_TAG "Buffer is already in use");
134*5113495bSYour Name 		return -EINVAL;
135*5113495bSYour Name 	}
136*5113495bSYour Name 	qdf_spin_unlock_bh(&pl_info->log_lock);
137*5113495bSYour Name 
138*5113495bSYour Name 	buffer = qdf_mem_valloc((page_cnt + 2) * PAGE_SIZE);
139*5113495bSYour Name 	if (!buffer) {
140*5113495bSYour Name 		return -ENOMEM;
141*5113495bSYour Name 	}
142*5113495bSYour Name 
143*5113495bSYour Name 	buffer = (struct ath_pktlog_buf *)
144*5113495bSYour Name 		       (((unsigned long)(buffer) + PAGE_SIZE - 1)
145*5113495bSYour Name 			& PAGE_MASK);
146*5113495bSYour Name 
147*5113495bSYour Name 	for (vaddr = (unsigned long)(buffer);
148*5113495bSYour Name 	     vaddr < ((unsigned long)(buffer) + (page_cnt * PAGE_SIZE));
149*5113495bSYour Name 	     vaddr += PAGE_SIZE) {
150*5113495bSYour Name 		vpg = vmalloc_to_page((const void *)vaddr);
151*5113495bSYour Name 		SetPageReserved(vpg);
152*5113495bSYour Name 	}
153*5113495bSYour Name 
154*5113495bSYour Name 	qdf_spin_lock_bh(&pl_info->log_lock);
155*5113495bSYour Name 	if (pl_info->buf)
156*5113495bSYour Name 		pktlog_release_buf(scn);
157*5113495bSYour Name 
158*5113495bSYour Name 	pl_info->buf =  buffer;
159*5113495bSYour Name 	qdf_spin_unlock_bh(&pl_info->log_lock);
160*5113495bSYour Name 	return 0;
161*5113495bSYour Name }
162*5113495bSYour Name 
pktlog_release_buf(struct hif_opaque_softc * scn)163*5113495bSYour Name void pktlog_release_buf(struct hif_opaque_softc *scn)
164*5113495bSYour Name {
165*5113495bSYour Name 	unsigned long page_cnt;
166*5113495bSYour Name 	unsigned long vaddr;
167*5113495bSYour Name 	struct page *vpg;
168*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
169*5113495bSYour Name 	struct ath_pktlog_info *pl_info;
170*5113495bSYour Name 
171*5113495bSYour Name 	pl_dev = get_pktlog_handle();
172*5113495bSYour Name 
173*5113495bSYour Name 	if (!pl_dev) {
174*5113495bSYour Name 		qdf_print("Invalid pl_dev handle");
175*5113495bSYour Name 		return;
176*5113495bSYour Name 	}
177*5113495bSYour Name 
178*5113495bSYour Name 	if (!pl_dev->pl_info) {
179*5113495bSYour Name 		qdf_print("Invalid pl_dev handle");
180*5113495bSYour Name 		return;
181*5113495bSYour Name 	}
182*5113495bSYour Name 
183*5113495bSYour Name 	pl_info = pl_dev->pl_info;
184*5113495bSYour Name 
185*5113495bSYour Name 	page_cnt = ((sizeof(*(pl_info->buf)) + pl_info->buf_size) /
186*5113495bSYour Name 		    PAGE_SIZE) + 1;
187*5113495bSYour Name 
188*5113495bSYour Name 	for (vaddr = (unsigned long)(pl_info->buf);
189*5113495bSYour Name 	     vaddr < (unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE);
190*5113495bSYour Name 	     vaddr += PAGE_SIZE) {
191*5113495bSYour Name 		vpg = vmalloc_to_page((const void *)vaddr);
192*5113495bSYour Name 		ClearPageReserved(vpg);
193*5113495bSYour Name 	}
194*5113495bSYour Name 
195*5113495bSYour Name 	qdf_mem_vfree(pl_info->buf);
196*5113495bSYour Name 	pl_info->buf = NULL;
197*5113495bSYour Name }
198*5113495bSYour Name 
pktlog_cleanup(struct ath_pktlog_info * pl_info)199*5113495bSYour Name static void pktlog_cleanup(struct ath_pktlog_info *pl_info)
200*5113495bSYour Name {
201*5113495bSYour Name 	pl_info->log_state = 0;
202*5113495bSYour Name 	PKTLOG_LOCK_DESTROY(pl_info);
203*5113495bSYour Name 	mutex_destroy(&pl_info->pktlog_mutex);
204*5113495bSYour Name }
205*5113495bSYour Name 
206*5113495bSYour Name /* sysctl procfs handler to enable pktlog */
207*5113495bSYour Name static int
qdf_sysctl_decl(ath_sysctl_pktlog_enable,ctl,write,filp,buffer,lenp,ppos)208*5113495bSYour Name qdf_sysctl_decl(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ppos)
209*5113495bSYour Name {
210*5113495bSYour Name 	int ret, enable;
211*5113495bSYour Name 	ol_ath_generic_softc_handle scn;
212*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
213*5113495bSYour Name 
214*5113495bSYour Name 	mutex_lock(&proc_mutex);
215*5113495bSYour Name 	scn = (ol_ath_generic_softc_handle) ctl->extra1;
216*5113495bSYour Name 
217*5113495bSYour Name 	if (!scn) {
218*5113495bSYour Name 		mutex_unlock(&proc_mutex);
219*5113495bSYour Name 		qdf_info("Invalid scn context");
220*5113495bSYour Name 		ASSERT(0);
221*5113495bSYour Name 		return -EINVAL;
222*5113495bSYour Name 	}
223*5113495bSYour Name 
224*5113495bSYour Name 	pl_dev = get_pktlog_handle();
225*5113495bSYour Name 
226*5113495bSYour Name 	if (!pl_dev) {
227*5113495bSYour Name 		mutex_unlock(&proc_mutex);
228*5113495bSYour Name 		qdf_info("Invalid pktlog context");
229*5113495bSYour Name 		ASSERT(0);
230*5113495bSYour Name 		return -ENODEV;
231*5113495bSYour Name 	}
232*5113495bSYour Name 
233*5113495bSYour Name 	ctl->data = &enable;
234*5113495bSYour Name 	ctl->maxlen = sizeof(enable);
235*5113495bSYour Name 
236*5113495bSYour Name 	if (write) {
237*5113495bSYour Name 		ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
238*5113495bSYour Name 					       lenp, ppos);
239*5113495bSYour Name 		if (ret == 0) {
240*5113495bSYour Name 			ret = pl_dev->pl_funcs->pktlog_enable(
241*5113495bSYour Name 					(struct hif_opaque_softc *)scn, enable,
242*5113495bSYour Name 					cds_is_packet_log_enabled(), 0, 1);
243*5113495bSYour Name 		}
244*5113495bSYour Name 		else
245*5113495bSYour Name 			QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG,
246*5113495bSYour Name 				  "Line:%d %s:proc_dointvec failed reason %d",
247*5113495bSYour Name 				   __LINE__, __func__, ret);
248*5113495bSYour Name 	} else {
249*5113495bSYour Name 		ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
250*5113495bSYour Name 					       lenp, ppos);
251*5113495bSYour Name 		if (ret)
252*5113495bSYour Name 			QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG,
253*5113495bSYour Name 				  "Line:%d %s:proc_dointvec failed reason %d",
254*5113495bSYour Name 				   __LINE__, __func__, ret);
255*5113495bSYour Name 	}
256*5113495bSYour Name 
257*5113495bSYour Name 	ctl->data = NULL;
258*5113495bSYour Name 	ctl->maxlen = 0;
259*5113495bSYour Name 	mutex_unlock(&proc_mutex);
260*5113495bSYour Name 
261*5113495bSYour Name 	return ret;
262*5113495bSYour Name }
263*5113495bSYour Name 
get_pktlog_bufsize(struct pktlog_dev_t * pl_dev)264*5113495bSYour Name static int get_pktlog_bufsize(struct pktlog_dev_t *pl_dev)
265*5113495bSYour Name {
266*5113495bSYour Name 	return pl_dev->pl_info->buf_size;
267*5113495bSYour Name }
268*5113495bSYour Name 
269*5113495bSYour Name /* sysctl procfs handler to set/get pktlog size */
270*5113495bSYour Name static int
qdf_sysctl_decl(ath_sysctl_pktlog_size,ctl,write,filp,buffer,lenp,ppos)271*5113495bSYour Name qdf_sysctl_decl(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ppos)
272*5113495bSYour Name {
273*5113495bSYour Name 	int ret, size;
274*5113495bSYour Name 	ol_ath_generic_softc_handle scn;
275*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
276*5113495bSYour Name 
277*5113495bSYour Name 	mutex_lock(&proc_mutex);
278*5113495bSYour Name 	scn = (ol_ath_generic_softc_handle) ctl->extra1;
279*5113495bSYour Name 
280*5113495bSYour Name 	if (!scn) {
281*5113495bSYour Name 		mutex_unlock(&proc_mutex);
282*5113495bSYour Name 		qdf_info("Invalid scn context");
283*5113495bSYour Name 		ASSERT(0);
284*5113495bSYour Name 		return -EINVAL;
285*5113495bSYour Name 	}
286*5113495bSYour Name 
287*5113495bSYour Name 	pl_dev = get_pktlog_handle();
288*5113495bSYour Name 
289*5113495bSYour Name 	if (!pl_dev) {
290*5113495bSYour Name 		mutex_unlock(&proc_mutex);
291*5113495bSYour Name 		qdf_info("Invalid pktlog handle");
292*5113495bSYour Name 		ASSERT(0);
293*5113495bSYour Name 		return -ENODEV;
294*5113495bSYour Name 	}
295*5113495bSYour Name 
296*5113495bSYour Name 	ctl->data = &size;
297*5113495bSYour Name 	ctl->maxlen = sizeof(size);
298*5113495bSYour Name 
299*5113495bSYour Name 	if (write) {
300*5113495bSYour Name 		ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
301*5113495bSYour Name 					       lenp, ppos);
302*5113495bSYour Name 		if (ret == 0)
303*5113495bSYour Name 			ret = pl_dev->pl_funcs->pktlog_setsize(
304*5113495bSYour Name 					(struct hif_opaque_softc *)scn, size);
305*5113495bSYour Name 	} else {
306*5113495bSYour Name 		size = get_pktlog_bufsize(pl_dev);
307*5113495bSYour Name 		ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
308*5113495bSYour Name 					       lenp, ppos);
309*5113495bSYour Name 	}
310*5113495bSYour Name 
311*5113495bSYour Name 	ctl->data = NULL;
312*5113495bSYour Name 	ctl->maxlen = 0;
313*5113495bSYour Name 	mutex_unlock(&proc_mutex);
314*5113495bSYour Name 
315*5113495bSYour Name 	return ret;
316*5113495bSYour Name }
317*5113495bSYour Name 
318*5113495bSYour Name /* Register sysctl table */
pktlog_sysctl_register(struct hif_opaque_softc * scn)319*5113495bSYour Name static int pktlog_sysctl_register(struct hif_opaque_softc *scn)
320*5113495bSYour Name {
321*5113495bSYour Name 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
322*5113495bSYour Name 	struct ath_pktlog_info_lnx *pl_info_lnx;
323*5113495bSYour Name 	char *proc_name;
324*5113495bSYour Name 
325*5113495bSYour Name 	if (pl_dev) {
326*5113495bSYour Name 		pl_info_lnx = PL_INFO_LNX(pl_dev->pl_info);
327*5113495bSYour Name 		proc_name = pl_dev->name;
328*5113495bSYour Name 	} else {
329*5113495bSYour Name 		pl_info_lnx = PL_INFO_LNX(g_pktlog_info);
330*5113495bSYour Name 		proc_name = PKTLOG_PROC_SYSTEM;
331*5113495bSYour Name 	}
332*5113495bSYour Name 
333*5113495bSYour Name 	/*
334*5113495bSYour Name 	 * Setup the sysctl table for creating the following sysctl entries:
335*5113495bSYour Name 	 * /proc/sys/PKTLOG_PROC_DIR/<adapter>/enable for enabling/disabling
336*5113495bSYour Name 	 * pktlog
337*5113495bSYour Name 	 * /proc/sys/PKTLOG_PROC_DIR/<adapter>/size for changing the buffer size
338*5113495bSYour Name 	 */
339*5113495bSYour Name 	memset(pl_info_lnx->sysctls, 0, sizeof(pl_info_lnx->sysctls));
340*5113495bSYour Name 	pl_info_lnx->sysctls[0].procname = PKTLOG_PROC_DIR;
341*5113495bSYour Name 	pl_info_lnx->sysctls[0].mode = PKTLOG_PROCSYS_DIR_PERM;
342*5113495bSYour Name 	pl_info_lnx->sysctls[0].child = &pl_info_lnx->sysctls[2];
343*5113495bSYour Name 
344*5113495bSYour Name 	/* [1] is NULL terminator */
345*5113495bSYour Name 	pl_info_lnx->sysctls[2].procname = proc_name;
346*5113495bSYour Name 	pl_info_lnx->sysctls[2].mode = PKTLOG_PROCSYS_DIR_PERM;
347*5113495bSYour Name 	pl_info_lnx->sysctls[2].child = &pl_info_lnx->sysctls[4];
348*5113495bSYour Name 
349*5113495bSYour Name 	/* [3] is NULL terminator */
350*5113495bSYour Name 	pl_info_lnx->sysctls[4].procname = "enable";
351*5113495bSYour Name 	pl_info_lnx->sysctls[4].mode = PKTLOG_PROCSYS_PERM;
352*5113495bSYour Name 	pl_info_lnx->sysctls[4].proc_handler = ath_sysctl_pktlog_enable;
353*5113495bSYour Name 	pl_info_lnx->sysctls[4].extra1 = scn;
354*5113495bSYour Name 
355*5113495bSYour Name 	pl_info_lnx->sysctls[5].procname = "size";
356*5113495bSYour Name 	pl_info_lnx->sysctls[5].mode = PKTLOG_PROCSYS_PERM;
357*5113495bSYour Name 	pl_info_lnx->sysctls[5].proc_handler = ath_sysctl_pktlog_size;
358*5113495bSYour Name 	pl_info_lnx->sysctls[5].extra1 = scn;
359*5113495bSYour Name 
360*5113495bSYour Name 	pl_info_lnx->sysctls[6].procname = "options";
361*5113495bSYour Name 	pl_info_lnx->sysctls[6].mode = PKTLOG_PROCSYS_PERM;
362*5113495bSYour Name 	pl_info_lnx->sysctls[6].proc_handler = proc_dointvec;
363*5113495bSYour Name 	pl_info_lnx->sysctls[6].data = &pl_info_lnx->info.options;
364*5113495bSYour Name 	pl_info_lnx->sysctls[6].maxlen = sizeof(pl_info_lnx->info.options);
365*5113495bSYour Name 
366*5113495bSYour Name 	pl_info_lnx->sysctls[7].procname = "sack_thr";
367*5113495bSYour Name 	pl_info_lnx->sysctls[7].mode = PKTLOG_PROCSYS_PERM;
368*5113495bSYour Name 	pl_info_lnx->sysctls[7].proc_handler = proc_dointvec;
369*5113495bSYour Name 	pl_info_lnx->sysctls[7].data = &pl_info_lnx->info.sack_thr;
370*5113495bSYour Name 	pl_info_lnx->sysctls[7].maxlen = sizeof(pl_info_lnx->info.sack_thr);
371*5113495bSYour Name 
372*5113495bSYour Name 	pl_info_lnx->sysctls[8].procname = "tail_length";
373*5113495bSYour Name 	pl_info_lnx->sysctls[8].mode = PKTLOG_PROCSYS_PERM;
374*5113495bSYour Name 	pl_info_lnx->sysctls[8].proc_handler = proc_dointvec;
375*5113495bSYour Name 	pl_info_lnx->sysctls[8].data = &pl_info_lnx->info.tail_length;
376*5113495bSYour Name 	pl_info_lnx->sysctls[8].maxlen = sizeof(pl_info_lnx->info.tail_length);
377*5113495bSYour Name 
378*5113495bSYour Name 	pl_info_lnx->sysctls[9].procname = "thruput_thresh";
379*5113495bSYour Name 	pl_info_lnx->sysctls[9].mode = PKTLOG_PROCSYS_PERM;
380*5113495bSYour Name 	pl_info_lnx->sysctls[9].proc_handler = proc_dointvec;
381*5113495bSYour Name 	pl_info_lnx->sysctls[9].data = &pl_info_lnx->info.thruput_thresh;
382*5113495bSYour Name 	pl_info_lnx->sysctls[9].maxlen =
383*5113495bSYour Name 		sizeof(pl_info_lnx->info.thruput_thresh);
384*5113495bSYour Name 
385*5113495bSYour Name 	pl_info_lnx->sysctls[10].procname = "phyerr_thresh";
386*5113495bSYour Name 	pl_info_lnx->sysctls[10].mode = PKTLOG_PROCSYS_PERM;
387*5113495bSYour Name 	pl_info_lnx->sysctls[10].proc_handler = proc_dointvec;
388*5113495bSYour Name 	pl_info_lnx->sysctls[10].data = &pl_info_lnx->info.phyerr_thresh;
389*5113495bSYour Name 	pl_info_lnx->sysctls[10].maxlen =
390*5113495bSYour Name 		sizeof(pl_info_lnx->info.phyerr_thresh);
391*5113495bSYour Name 
392*5113495bSYour Name 	pl_info_lnx->sysctls[11].procname = "per_thresh";
393*5113495bSYour Name 	pl_info_lnx->sysctls[11].mode = PKTLOG_PROCSYS_PERM;
394*5113495bSYour Name 	pl_info_lnx->sysctls[11].proc_handler = proc_dointvec;
395*5113495bSYour Name 	pl_info_lnx->sysctls[11].data = &pl_info_lnx->info.per_thresh;
396*5113495bSYour Name 	pl_info_lnx->sysctls[11].maxlen = sizeof(pl_info_lnx->info.per_thresh);
397*5113495bSYour Name 
398*5113495bSYour Name 	pl_info_lnx->sysctls[12].procname = "trigger_interval";
399*5113495bSYour Name 	pl_info_lnx->sysctls[12].mode = PKTLOG_PROCSYS_PERM;
400*5113495bSYour Name 	pl_info_lnx->sysctls[12].proc_handler = proc_dointvec;
401*5113495bSYour Name 	pl_info_lnx->sysctls[12].data = &pl_info_lnx->info.trigger_interval;
402*5113495bSYour Name 	pl_info_lnx->sysctls[12].maxlen =
403*5113495bSYour Name 		sizeof(pl_info_lnx->info.trigger_interval);
404*5113495bSYour Name 	/* [13] is NULL terminator */
405*5113495bSYour Name 
406*5113495bSYour Name 	/* and register everything */
407*5113495bSYour Name 	/* register_sysctl_table changed from 2.6.21 onwards */
408*5113495bSYour Name 	pl_info_lnx->sysctl_header =
409*5113495bSYour Name 		register_sysctl_table(pl_info_lnx->sysctls);
410*5113495bSYour Name 
411*5113495bSYour Name 	if (!pl_info_lnx->sysctl_header) {
412*5113495bSYour Name 		qdf_nofl_info("%s: failed to register sysctls!", proc_name);
413*5113495bSYour Name 		return -EINVAL;
414*5113495bSYour Name 	}
415*5113495bSYour Name 
416*5113495bSYour Name 	return 0;
417*5113495bSYour Name }
418*5113495bSYour Name 
419*5113495bSYour Name /*
420*5113495bSYour Name  * Initialize logging for system or adapter
421*5113495bSYour Name  * Parameter scn should be NULL for system wide logging
422*5113495bSYour Name  */
pktlog_attach(struct hif_opaque_softc * scn)423*5113495bSYour Name static int pktlog_attach(struct hif_opaque_softc *scn)
424*5113495bSYour Name {
425*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
426*5113495bSYour Name 	struct ath_pktlog_info_lnx *pl_info_lnx;
427*5113495bSYour Name 	char *proc_name;
428*5113495bSYour Name 	struct proc_dir_entry *proc_entry;
429*5113495bSYour Name 
430*5113495bSYour Name 	qdf_info("attach pktlog resources");
431*5113495bSYour Name 	/* Allocate pktlog dev for later use */
432*5113495bSYour Name 	pl_dev = get_pktlog_handle();
433*5113495bSYour Name 
434*5113495bSYour Name 	if (pl_dev) {
435*5113495bSYour Name 		pl_info_lnx = kmalloc(sizeof(*pl_info_lnx), GFP_KERNEL);
436*5113495bSYour Name 		if (!pl_info_lnx) {
437*5113495bSYour Name 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
438*5113495bSYour Name 				 "%s: Allocation failed for pl_info",
439*5113495bSYour Name 				 __func__);
440*5113495bSYour Name 			goto attach_fail1;
441*5113495bSYour Name 		}
442*5113495bSYour Name 
443*5113495bSYour Name 		pl_dev->pl_info = &pl_info_lnx->info;
444*5113495bSYour Name 		pl_dev->name = WLANDEV_BASENAME;
445*5113495bSYour Name 		proc_name = pl_dev->name;
446*5113495bSYour Name 
447*5113495bSYour Name 		if (!pl_dev->pl_funcs)
448*5113495bSYour Name 			pl_dev->pl_funcs = &ol_pl_funcs;
449*5113495bSYour Name 
450*5113495bSYour Name 		/*
451*5113495bSYour Name 		 * Valid for both direct attach and offload architecture
452*5113495bSYour Name 		 */
453*5113495bSYour Name 		pl_dev->pl_funcs->pktlog_init(scn);
454*5113495bSYour Name 	} else {
455*5113495bSYour Name 		qdf_err("pl_dev is NULL");
456*5113495bSYour Name 		return -EINVAL;
457*5113495bSYour Name 	}
458*5113495bSYour Name 
459*5113495bSYour Name 	/*
460*5113495bSYour Name 	 * initialize log info
461*5113495bSYour Name 	 * might be good to move to pktlog_init
462*5113495bSYour Name 	 */
463*5113495bSYour Name 	/* pl_dev->tgt_pktlog_alloced = false; */
464*5113495bSYour Name 	pl_info_lnx->proc_entry = NULL;
465*5113495bSYour Name 	pl_info_lnx->sysctl_header = NULL;
466*5113495bSYour Name 
467*5113495bSYour Name 	proc_entry = proc_create_data(proc_name, PKTLOG_PROC_PERM,
468*5113495bSYour Name 			g_pktlog_pde, &pktlog_fops,
469*5113495bSYour Name 			&pl_info_lnx->info);
470*5113495bSYour Name 
471*5113495bSYour Name 	if (!proc_entry) {
472*5113495bSYour Name 		qdf_info(PKTLOG_TAG "create_proc_entry failed for %s", proc_name);
473*5113495bSYour Name 		goto attach_fail1;
474*5113495bSYour Name 	}
475*5113495bSYour Name 
476*5113495bSYour Name 	pl_info_lnx->proc_entry = proc_entry;
477*5113495bSYour Name 
478*5113495bSYour Name 	if (pktlog_sysctl_register(scn)) {
479*5113495bSYour Name 		qdf_nofl_info(PKTLOG_TAG "sysctl register failed for %s",
480*5113495bSYour Name 			      proc_name);
481*5113495bSYour Name 		goto attach_fail2;
482*5113495bSYour Name 	}
483*5113495bSYour Name 
484*5113495bSYour Name 	return 0;
485*5113495bSYour Name 
486*5113495bSYour Name attach_fail2:
487*5113495bSYour Name 	remove_proc_entry(proc_name, g_pktlog_pde);
488*5113495bSYour Name 
489*5113495bSYour Name attach_fail1:
490*5113495bSYour Name 	if (pl_dev)
491*5113495bSYour Name 		kfree(pl_dev->pl_info);
492*5113495bSYour Name 
493*5113495bSYour Name 	return -EINVAL;
494*5113495bSYour Name }
495*5113495bSYour Name 
pktlog_sysctl_unregister(struct pktlog_dev_t * pl_dev)496*5113495bSYour Name static void pktlog_sysctl_unregister(struct pktlog_dev_t *pl_dev)
497*5113495bSYour Name {
498*5113495bSYour Name 	struct ath_pktlog_info_lnx *pl_info_lnx;
499*5113495bSYour Name 
500*5113495bSYour Name 	if (!pl_dev) {
501*5113495bSYour Name 		qdf_info("Invalid pktlog context");
502*5113495bSYour Name 		ASSERT(0);
503*5113495bSYour Name 		return;
504*5113495bSYour Name 	}
505*5113495bSYour Name 
506*5113495bSYour Name 	pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
507*5113495bSYour Name 		      PL_INFO_LNX(g_pktlog_info);
508*5113495bSYour Name 
509*5113495bSYour Name 	if (pl_info_lnx->sysctl_header) {
510*5113495bSYour Name 		unregister_sysctl_table(pl_info_lnx->sysctl_header);
511*5113495bSYour Name 		pl_info_lnx->sysctl_header = NULL;
512*5113495bSYour Name 	}
513*5113495bSYour Name }
514*5113495bSYour Name 
pktlog_detach(struct hif_opaque_softc * scn)515*5113495bSYour Name static void pktlog_detach(struct hif_opaque_softc *scn)
516*5113495bSYour Name {
517*5113495bSYour Name 	struct ath_pktlog_info *pl_info;
518*5113495bSYour Name 	struct pktlog_dev_t *pl_dev = get_pktlog_handle();
519*5113495bSYour Name 
520*5113495bSYour Name 	qdf_info("detach pktlog resources");
521*5113495bSYour Name 	if (!pl_dev) {
522*5113495bSYour Name 		qdf_info("Invalid pktlog context");
523*5113495bSYour Name 		ASSERT(0);
524*5113495bSYour Name 		return;
525*5113495bSYour Name 	}
526*5113495bSYour Name 
527*5113495bSYour Name 	pl_info = pl_dev->pl_info;
528*5113495bSYour Name 	if (!pl_info) {
529*5113495bSYour Name 		qdf_print("Invalid pktlog handle");
530*5113495bSYour Name 		ASSERT(0);
531*5113495bSYour Name 		return;
532*5113495bSYour Name 	}
533*5113495bSYour Name 	mutex_lock(&pl_info->pktlog_mutex);
534*5113495bSYour Name 	remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
535*5113495bSYour Name 	pktlog_sysctl_unregister(pl_dev);
536*5113495bSYour Name 
537*5113495bSYour Name 	qdf_spin_lock_bh(&pl_info->log_lock);
538*5113495bSYour Name 
539*5113495bSYour Name 	if (pl_info->buf) {
540*5113495bSYour Name 		pktlog_release_buf(scn);
541*5113495bSYour Name 		pl_dev->tgt_pktlog_alloced = false;
542*5113495bSYour Name 	}
543*5113495bSYour Name 	qdf_spin_unlock_bh(&pl_info->log_lock);
544*5113495bSYour Name 	mutex_unlock(&pl_info->pktlog_mutex);
545*5113495bSYour Name 	pktlog_cleanup(pl_info);
546*5113495bSYour Name 
547*5113495bSYour Name 	if (pl_dev) {
548*5113495bSYour Name 		kfree(pl_info);
549*5113495bSYour Name 		pl_dev->pl_info = NULL;
550*5113495bSYour Name 	}
551*5113495bSYour Name }
552*5113495bSYour Name 
__pktlog_open(struct inode * i,struct file * f)553*5113495bSYour Name static int __pktlog_open(struct inode *i, struct file *f)
554*5113495bSYour Name {
555*5113495bSYour Name 	struct hif_opaque_softc *scn;
556*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
557*5113495bSYour Name 	struct ath_pktlog_info *pl_info;
558*5113495bSYour Name 	struct ath_pktlog_info_lnx *pl_info_lnx;
559*5113495bSYour Name 	int ret = 0;
560*5113495bSYour Name 
561*5113495bSYour Name 	PKTLOG_MOD_INC_USE_COUNT;
562*5113495bSYour Name 	scn = cds_get_context(QDF_MODULE_ID_HIF);
563*5113495bSYour Name 	if (!scn) {
564*5113495bSYour Name 		qdf_print("Invalid scn context");
565*5113495bSYour Name 		ASSERT(0);
566*5113495bSYour Name 		return -EINVAL;
567*5113495bSYour Name 	}
568*5113495bSYour Name 
569*5113495bSYour Name 	pl_dev = get_pktlog_handle();
570*5113495bSYour Name 
571*5113495bSYour Name 	if (!pl_dev) {
572*5113495bSYour Name 		qdf_print("Invalid pktlog handle");
573*5113495bSYour Name 		ASSERT(0);
574*5113495bSYour Name 		return -ENODEV;
575*5113495bSYour Name 	}
576*5113495bSYour Name 
577*5113495bSYour Name 	pl_info = pl_dev->pl_info;
578*5113495bSYour Name 
579*5113495bSYour Name 	if (!pl_info) {
580*5113495bSYour Name 		qdf_err("pl_info NULL");
581*5113495bSYour Name 		return -EINVAL;
582*5113495bSYour Name 	}
583*5113495bSYour Name 
584*5113495bSYour Name 	mutex_lock(&pl_info->pktlog_mutex);
585*5113495bSYour Name 	pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
586*5113495bSYour Name 		PL_INFO_LNX(g_pktlog_info);
587*5113495bSYour Name 
588*5113495bSYour Name 	if (!pl_info_lnx->sysctl_header) {
589*5113495bSYour Name 		mutex_unlock(&pl_info->pktlog_mutex);
590*5113495bSYour Name 		qdf_print("pktlog sysctl is unergistered");
591*5113495bSYour Name 		ASSERT(0);
592*5113495bSYour Name 		return -EINVAL;
593*5113495bSYour Name 	}
594*5113495bSYour Name 
595*5113495bSYour Name 	if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
596*5113495bSYour Name 		mutex_unlock(&pl_info->pktlog_mutex);
597*5113495bSYour Name 		qdf_print("plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
598*5113495bSYour Name 			  pl_info->curr_pkt_state);
599*5113495bSYour Name 		return -EBUSY;
600*5113495bSYour Name 	}
601*5113495bSYour Name 
602*5113495bSYour Name 	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
603*5113495bSYour Name 
604*5113495bSYour Name 	pl_info->init_saved_state = pl_info->log_state;
605*5113495bSYour Name 	if (!pl_info->log_state) {
606*5113495bSYour Name 		/* Pktlog is already disabled.
607*5113495bSYour Name 		 * Proceed to read directly.
608*5113495bSYour Name 		 */
609*5113495bSYour Name 		pl_info->curr_pkt_state =
610*5113495bSYour Name 			PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
611*5113495bSYour Name 		mutex_unlock(&pl_info->pktlog_mutex);
612*5113495bSYour Name 		return ret;
613*5113495bSYour Name 	}
614*5113495bSYour Name 	/* Disbable the pktlog internally. */
615*5113495bSYour Name 	ret = pl_dev->pl_funcs->pktlog_disable(scn);
616*5113495bSYour Name 	pl_info->log_state = 0;
617*5113495bSYour Name 	pl_info->curr_pkt_state =
618*5113495bSYour Name 			PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
619*5113495bSYour Name 	mutex_unlock(&pl_info->pktlog_mutex);
620*5113495bSYour Name 	return ret;
621*5113495bSYour Name }
622*5113495bSYour Name 
pktlog_open(struct inode * i,struct file * f)623*5113495bSYour Name static int pktlog_open(struct inode *i, struct file *f)
624*5113495bSYour Name {
625*5113495bSYour Name 	struct qdf_op_sync *op_sync;
626*5113495bSYour Name 	int errno;
627*5113495bSYour Name 
628*5113495bSYour Name 	errno = qdf_op_protect(&op_sync);
629*5113495bSYour Name 	if (errno)
630*5113495bSYour Name 		return errno;
631*5113495bSYour Name 
632*5113495bSYour Name 	errno = __pktlog_open(i, f);
633*5113495bSYour Name 
634*5113495bSYour Name 	qdf_op_unprotect(op_sync);
635*5113495bSYour Name 
636*5113495bSYour Name 	return errno;
637*5113495bSYour Name }
638*5113495bSYour Name 
__pktlog_release(struct inode * i,struct file * f)639*5113495bSYour Name static int __pktlog_release(struct inode *i, struct file *f)
640*5113495bSYour Name {
641*5113495bSYour Name 	struct hif_opaque_softc *scn;
642*5113495bSYour Name 	struct pktlog_dev_t *pl_dev;
643*5113495bSYour Name 	struct ath_pktlog_info *pl_info;
644*5113495bSYour Name 	struct ath_pktlog_info_lnx *pl_info_lnx;
645*5113495bSYour Name 	int ret = 0;
646*5113495bSYour Name 
647*5113495bSYour Name 	PKTLOG_MOD_DEC_USE_COUNT;
648*5113495bSYour Name 	scn = cds_get_context(QDF_MODULE_ID_HIF);
649*5113495bSYour Name 	if (!scn) {
650*5113495bSYour Name 		qdf_print("Invalid scn context");
651*5113495bSYour Name 		ASSERT(0);
652*5113495bSYour Name 		return -EINVAL;
653*5113495bSYour Name 	}
654*5113495bSYour Name 
655*5113495bSYour Name 	pl_dev = get_pktlog_handle();
656*5113495bSYour Name 
657*5113495bSYour Name 	if (!pl_dev) {
658*5113495bSYour Name 		qdf_print("Invalid pktlog handle");
659*5113495bSYour Name 		ASSERT(0);
660*5113495bSYour Name 		return -ENODEV;
661*5113495bSYour Name 	}
662*5113495bSYour Name 
663*5113495bSYour Name 	pl_info = pl_dev->pl_info;
664*5113495bSYour Name 
665*5113495bSYour Name 	if (!pl_info) {
666*5113495bSYour Name 		qdf_print("Invalid pktlog info");
667*5113495bSYour Name 		ASSERT(0);
668*5113495bSYour Name 		return -EINVAL;
669*5113495bSYour Name 	}
670*5113495bSYour Name 
671*5113495bSYour Name 	mutex_lock(&pl_info->pktlog_mutex);
672*5113495bSYour Name 	pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
673*5113495bSYour Name 		PL_INFO_LNX(g_pktlog_info);
674*5113495bSYour Name 
675*5113495bSYour Name 	if (!pl_info_lnx->sysctl_header) {
676*5113495bSYour Name 		pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
677*5113495bSYour Name 		mutex_unlock(&pl_info->pktlog_mutex);
678*5113495bSYour Name 		qdf_print("pktlog sysctl is unergistered");
679*5113495bSYour Name 		ASSERT(0);
680*5113495bSYour Name 		return -EINVAL;
681*5113495bSYour Name 	}
682*5113495bSYour Name 	pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE;
683*5113495bSYour Name 	/*clear pktlog buffer.*/
684*5113495bSYour Name 	pktlog_clearbuff(scn, true);
685*5113495bSYour Name 	pl_info->log_state = pl_info->init_saved_state;
686*5113495bSYour Name 	pl_info->init_saved_state = 0;
687*5113495bSYour Name 
688*5113495bSYour Name 	/*Enable pktlog again*/
689*5113495bSYour Name 	ret = __pktlog_enable(
690*5113495bSYour Name 			(struct hif_opaque_softc *)scn, pl_info->log_state,
691*5113495bSYour Name 			cds_is_packet_log_enabled(), 0, 1);
692*5113495bSYour Name 
693*5113495bSYour Name 	pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
694*5113495bSYour Name 	mutex_unlock(&pl_info->pktlog_mutex);
695*5113495bSYour Name 	if (ret != 0)
696*5113495bSYour Name 		qdf_print("pktlog cannot be enabled. ret value %d", ret);
697*5113495bSYour Name 
698*5113495bSYour Name 	return ret;
699*5113495bSYour Name }
700*5113495bSYour Name 
pktlog_release(struct inode * i,struct file * f)701*5113495bSYour Name static int pktlog_release(struct inode *i, struct file *f)
702*5113495bSYour Name {
703*5113495bSYour Name 	struct qdf_op_sync *op_sync;
704*5113495bSYour Name 	int errno;
705*5113495bSYour Name 
706*5113495bSYour Name 	errno = qdf_op_protect(&op_sync);
707*5113495bSYour Name 	if (errno)
708*5113495bSYour Name 		return errno;
709*5113495bSYour Name 
710*5113495bSYour Name 	errno = __pktlog_release(i, f);
711*5113495bSYour Name 
712*5113495bSYour Name 	qdf_op_unprotect(op_sync);
713*5113495bSYour Name 
714*5113495bSYour Name 	return errno;
715*5113495bSYour Name }
716*5113495bSYour Name 
717*5113495bSYour Name #ifndef MIN
718*5113495bSYour Name #define MIN(a, b) (((a) < (b)) ? (a) : (b))
719*5113495bSYour Name #endif
720*5113495bSYour Name 
721*5113495bSYour Name /**
722*5113495bSYour Name  * pktlog_read_proc_entry() - This function is used to read data from the
723*5113495bSYour Name  * proc entry into the readers buffer
724*5113495bSYour Name  * @buf:     Readers buffer
725*5113495bSYour Name  * @nbytes:  Number of bytes to read
726*5113495bSYour Name  * @ppos:    Offset within the drivers buffer
727*5113495bSYour Name  * @pl_info: Packet log information pointer
728*5113495bSYour Name  * @read_complete: Boolean value indication whether read is complete
729*5113495bSYour Name  *
730*5113495bSYour Name  * This function is used to read data from the proc entry into the readers
731*5113495bSYour Name  * buffer. Its functionality is similar to 'pktlog_read' which does
732*5113495bSYour Name  * copy to user to the user space buffer
733*5113495bSYour Name  *
734*5113495bSYour Name  * Return: Number of bytes read from the buffer
735*5113495bSYour Name  *
736*5113495bSYour Name  */
737*5113495bSYour Name 	ssize_t
pktlog_read_proc_entry(char * buf,size_t nbytes,loff_t * ppos,struct ath_pktlog_info * pl_info,bool * read_complete)738*5113495bSYour Name pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos,
739*5113495bSYour Name 		struct ath_pktlog_info *pl_info, bool *read_complete)
740*5113495bSYour Name {
741*5113495bSYour Name 	size_t bufhdr_size;
742*5113495bSYour Name 	size_t count = 0, ret_val = 0;
743*5113495bSYour Name 	int rem_len;
744*5113495bSYour Name 	int start_offset, end_offset;
745*5113495bSYour Name 	int fold_offset, ppos_data, cur_rd_offset, cur_wr_offset;
746*5113495bSYour Name 	struct ath_pktlog_buf *log_buf;
747*5113495bSYour Name 
748*5113495bSYour Name 	qdf_spin_lock_bh(&pl_info->log_lock);
749*5113495bSYour Name 	log_buf = pl_info->buf;
750*5113495bSYour Name 
751*5113495bSYour Name 	*read_complete = false;
752*5113495bSYour Name 
753*5113495bSYour Name 	if (!log_buf) {
754*5113495bSYour Name 		*read_complete = true;
755*5113495bSYour Name 		qdf_spin_unlock_bh(&pl_info->log_lock);
756*5113495bSYour Name 		return 0;
757*5113495bSYour Name 	}
758*5113495bSYour Name 
759*5113495bSYour Name 	if (*ppos == 0 && pl_info->log_state) {
760*5113495bSYour Name 		pl_info->saved_state = pl_info->log_state;
761*5113495bSYour Name 		pl_info->log_state = 0;
762*5113495bSYour Name 	}
763*5113495bSYour Name 
764*5113495bSYour Name 	bufhdr_size = sizeof(log_buf->bufhdr);
765*5113495bSYour Name 
766*5113495bSYour Name 	/* copy valid log entries from circular buffer into user space */
767*5113495bSYour Name 	rem_len = nbytes;
768*5113495bSYour Name 	count = 0;
769*5113495bSYour Name 
770*5113495bSYour Name 	if (*ppos < bufhdr_size) {
771*5113495bSYour Name 		count = MIN((bufhdr_size - *ppos), rem_len);
772*5113495bSYour Name 		qdf_mem_copy(buf, ((char *)&log_buf->bufhdr) + *ppos,
773*5113495bSYour Name 				count);
774*5113495bSYour Name 		rem_len -= count;
775*5113495bSYour Name 		ret_val += count;
776*5113495bSYour Name 	}
777*5113495bSYour Name 
778*5113495bSYour Name 	start_offset = log_buf->rd_offset;
779*5113495bSYour Name 	cur_wr_offset = log_buf->wr_offset;
780*5113495bSYour Name 
781*5113495bSYour Name 	if ((rem_len == 0) || (start_offset < 0))
782*5113495bSYour Name 		goto rd_done;
783*5113495bSYour Name 
784*5113495bSYour Name 	fold_offset = -1;
785*5113495bSYour Name 	cur_rd_offset = start_offset;
786*5113495bSYour Name 
787*5113495bSYour Name 	/* Find the last offset and fold-offset if the buffer is folded */
788*5113495bSYour Name 	do {
789*5113495bSYour Name 		struct ath_pktlog_hdr *log_hdr;
790*5113495bSYour Name 		int log_data_offset;
791*5113495bSYour Name 
792*5113495bSYour Name 		log_hdr = (struct ath_pktlog_hdr *) (log_buf->log_data +
793*5113495bSYour Name 				cur_rd_offset);
794*5113495bSYour Name 
795*5113495bSYour Name 		log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
796*5113495bSYour Name 
797*5113495bSYour Name 		if ((fold_offset == -1)
798*5113495bSYour Name 				&& ((pl_info->buf_size - log_data_offset)
799*5113495bSYour Name 					<= log_hdr->size))
800*5113495bSYour Name 			fold_offset = log_data_offset - 1;
801*5113495bSYour Name 
802*5113495bSYour Name 		PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size);
803*5113495bSYour Name 
804*5113495bSYour Name 		if ((fold_offset == -1) && (cur_rd_offset == 0)
805*5113495bSYour Name 				&& (cur_rd_offset != cur_wr_offset))
806*5113495bSYour Name 			fold_offset = log_data_offset + log_hdr->size - 1;
807*5113495bSYour Name 
808*5113495bSYour Name 		end_offset = log_data_offset + log_hdr->size - 1;
809*5113495bSYour Name 	} while (cur_rd_offset != cur_wr_offset);
810*5113495bSYour Name 
811*5113495bSYour Name 	ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
812*5113495bSYour Name 
813*5113495bSYour Name 	if (fold_offset == -1) {
814*5113495bSYour Name 		if (ppos_data > end_offset)
815*5113495bSYour Name 			goto rd_done;
816*5113495bSYour Name 
817*5113495bSYour Name 		count = MIN(rem_len, (end_offset - ppos_data + 1));
818*5113495bSYour Name 		qdf_mem_copy(buf + ret_val,
819*5113495bSYour Name 				log_buf->log_data + ppos_data,
820*5113495bSYour Name 				count);
821*5113495bSYour Name 		ret_val += count;
822*5113495bSYour Name 		rem_len -= count;
823*5113495bSYour Name 	} else {
824*5113495bSYour Name 		if (ppos_data <= fold_offset) {
825*5113495bSYour Name 			count = MIN(rem_len, (fold_offset - ppos_data + 1));
826*5113495bSYour Name 			qdf_mem_copy(buf + ret_val,
827*5113495bSYour Name 					log_buf->log_data + ppos_data,
828*5113495bSYour Name 					count);
829*5113495bSYour Name 			ret_val += count;
830*5113495bSYour Name 			rem_len -= count;
831*5113495bSYour Name 		}
832*5113495bSYour Name 
833*5113495bSYour Name 		if (rem_len == 0)
834*5113495bSYour Name 			goto rd_done;
835*5113495bSYour Name 
836*5113495bSYour Name 		ppos_data =
837*5113495bSYour Name 			*ppos + ret_val - (bufhdr_size +
838*5113495bSYour Name 					(fold_offset - start_offset + 1));
839*5113495bSYour Name 
840*5113495bSYour Name 		if (ppos_data <= end_offset) {
841*5113495bSYour Name 			count = MIN(rem_len, (end_offset - ppos_data + 1));
842*5113495bSYour Name 			qdf_mem_copy(buf + ret_val,
843*5113495bSYour Name 					log_buf->log_data + ppos_data,
844*5113495bSYour Name 					count);
845*5113495bSYour Name 			ret_val += count;
846*5113495bSYour Name 			rem_len -= count;
847*5113495bSYour Name 		}
848*5113495bSYour Name 	}
849*5113495bSYour Name 
850*5113495bSYour Name rd_done:
851*5113495bSYour Name 	if ((ret_val < nbytes) && pl_info->saved_state) {
852*5113495bSYour Name 		pl_info->log_state = pl_info->saved_state;
853*5113495bSYour Name 		pl_info->saved_state = 0;
854*5113495bSYour Name 	}
855*5113495bSYour Name 	*ppos += ret_val;
856*5113495bSYour Name 
857*5113495bSYour Name 	if (ret_val == 0) {
858*5113495bSYour Name 		/* Write pointer might have been updated during the read.
859*5113495bSYour Name 		 * So, if some data is written into, lets not reset the pointers
860*5113495bSYour Name 		 * We can continue to read from the offset position
861*5113495bSYour Name 		 */
862*5113495bSYour Name 		if (cur_wr_offset != log_buf->wr_offset) {
863*5113495bSYour Name 			*read_complete = false;
864*5113495bSYour Name 		} else {
865*5113495bSYour Name 			pl_info->buf->rd_offset = -1;
866*5113495bSYour Name 			pl_info->buf->wr_offset = 0;
867*5113495bSYour Name 			pl_info->buf->bytes_written = 0;
868*5113495bSYour Name 			pl_info->buf->offset = PKTLOG_READ_OFFSET;
869*5113495bSYour Name 			*read_complete = true;
870*5113495bSYour Name 		}
871*5113495bSYour Name 	}
872*5113495bSYour Name 	qdf_spin_unlock_bh(&pl_info->log_lock);
873*5113495bSYour Name 	return ret_val;
874*5113495bSYour Name }
875*5113495bSYour Name 
876*5113495bSYour Name static ssize_t
__pktlog_read(struct file * file,char * buf,size_t nbytes,loff_t * ppos)877*5113495bSYour Name __pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
878*5113495bSYour Name {
879*5113495bSYour Name 	size_t bufhdr_size;
880*5113495bSYour Name 	size_t count = 0, ret_val = 0;
881*5113495bSYour Name 	int rem_len;
882*5113495bSYour Name 	int start_offset, end_offset;
883*5113495bSYour Name 	int fold_offset, ppos_data, cur_rd_offset;
884*5113495bSYour Name 	struct ath_pktlog_info *pl_info;
885*5113495bSYour Name 	struct ath_pktlog_buf *log_buf;
886*5113495bSYour Name 
887*5113495bSYour Name 	pl_info = pde_data(file->f_path.dentry->d_inode);
888*5113495bSYour Name 	if (!pl_info)
889*5113495bSYour Name 		return 0;
890*5113495bSYour Name 
891*5113495bSYour Name 	qdf_spin_lock_bh(&pl_info->log_lock);
892*5113495bSYour Name 	log_buf = pl_info->buf;
893*5113495bSYour Name 
894*5113495bSYour Name 	if (!log_buf) {
895*5113495bSYour Name 		qdf_spin_unlock_bh(&pl_info->log_lock);
896*5113495bSYour Name 		return 0;
897*5113495bSYour Name 	}
898*5113495bSYour Name 
899*5113495bSYour Name 	if (pl_info->log_state) {
900*5113495bSYour Name 		/* Read is not allowed when write is going on
901*5113495bSYour Name 		 * When issuing cat command, ensure to send
902*5113495bSYour Name 		 * pktlog disable command first.
903*5113495bSYour Name 		 */
904*5113495bSYour Name 		qdf_spin_unlock_bh(&pl_info->log_lock);
905*5113495bSYour Name 		return -EINVAL;
906*5113495bSYour Name 	}
907*5113495bSYour Name 
908*5113495bSYour Name 	if (*ppos == 0 && pl_info->log_state) {
909*5113495bSYour Name 		pl_info->saved_state = pl_info->log_state;
910*5113495bSYour Name 		pl_info->log_state = 0;
911*5113495bSYour Name 	}
912*5113495bSYour Name 
913*5113495bSYour Name 	bufhdr_size = sizeof(log_buf->bufhdr);
914*5113495bSYour Name 
915*5113495bSYour Name 	/* copy valid log entries from circular buffer into user space */
916*5113495bSYour Name 
917*5113495bSYour Name 	rem_len = nbytes;
918*5113495bSYour Name 	count = 0;
919*5113495bSYour Name 
920*5113495bSYour Name 	if (*ppos < bufhdr_size) {
921*5113495bSYour Name 		count = QDF_MIN((bufhdr_size - *ppos), rem_len);
922*5113495bSYour Name 		qdf_spin_unlock_bh(&pl_info->log_lock);
923*5113495bSYour Name 		if (copy_to_user(buf, ((char *)&log_buf->bufhdr) + *ppos,
924*5113495bSYour Name 				 count)) {
925*5113495bSYour Name 			return -EFAULT;
926*5113495bSYour Name 		}
927*5113495bSYour Name 		rem_len -= count;
928*5113495bSYour Name 		ret_val += count;
929*5113495bSYour Name 		qdf_spin_lock_bh(&pl_info->log_lock);
930*5113495bSYour Name 	}
931*5113495bSYour Name 
932*5113495bSYour Name 	start_offset = log_buf->rd_offset;
933*5113495bSYour Name 
934*5113495bSYour Name 	if ((rem_len == 0) || (start_offset < 0))
935*5113495bSYour Name 		goto rd_done;
936*5113495bSYour Name 
937*5113495bSYour Name 	fold_offset = -1;
938*5113495bSYour Name 	cur_rd_offset = start_offset;
939*5113495bSYour Name 
940*5113495bSYour Name 	/* Find the last offset and fold-offset if the buffer is folded */
941*5113495bSYour Name 	do {
942*5113495bSYour Name 		struct ath_pktlog_hdr *log_hdr;
943*5113495bSYour Name 		int log_data_offset;
944*5113495bSYour Name 
945*5113495bSYour Name 		log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data +
946*5113495bSYour Name 						    cur_rd_offset);
947*5113495bSYour Name 
948*5113495bSYour Name 		log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr);
949*5113495bSYour Name 
950*5113495bSYour Name 		if ((fold_offset == -1)
951*5113495bSYour Name 		    && ((pl_info->buf_size - log_data_offset)
952*5113495bSYour Name 			<= log_hdr->size))
953*5113495bSYour Name 			fold_offset = log_data_offset - 1;
954*5113495bSYour Name 
955*5113495bSYour Name 		PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size);
956*5113495bSYour Name 
957*5113495bSYour Name 		if ((fold_offset == -1) && (cur_rd_offset == 0)
958*5113495bSYour Name 		    && (cur_rd_offset != log_buf->wr_offset))
959*5113495bSYour Name 			fold_offset = log_data_offset + log_hdr->size - 1;
960*5113495bSYour Name 
961*5113495bSYour Name 		end_offset = log_data_offset + log_hdr->size - 1;
962*5113495bSYour Name 	} while (cur_rd_offset != log_buf->wr_offset);
963*5113495bSYour Name 
964*5113495bSYour Name 	ppos_data = *ppos + ret_val - bufhdr_size + start_offset;
965*5113495bSYour Name 
966*5113495bSYour Name 	if (fold_offset == -1) {
967*5113495bSYour Name 		if (ppos_data > end_offset)
968*5113495bSYour Name 			goto rd_done;
969*5113495bSYour Name 
970*5113495bSYour Name 		count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
971*5113495bSYour Name 		qdf_spin_unlock_bh(&pl_info->log_lock);
972*5113495bSYour Name 
973*5113495bSYour Name 		if (copy_to_user(buf + ret_val,
974*5113495bSYour Name 				 log_buf->log_data + ppos_data, count)) {
975*5113495bSYour Name 			return -EFAULT;
976*5113495bSYour Name 		}
977*5113495bSYour Name 
978*5113495bSYour Name 		ret_val += count;
979*5113495bSYour Name 		rem_len -= count;
980*5113495bSYour Name 		qdf_spin_lock_bh(&pl_info->log_lock);
981*5113495bSYour Name 	} else {
982*5113495bSYour Name 		if (ppos_data <= fold_offset) {
983*5113495bSYour Name 			count = QDF_MIN(rem_len, (fold_offset - ppos_data + 1));
984*5113495bSYour Name 			qdf_spin_unlock_bh(&pl_info->log_lock);
985*5113495bSYour Name 			if (copy_to_user(buf + ret_val,
986*5113495bSYour Name 					 log_buf->log_data + ppos_data,
987*5113495bSYour Name 					 count)) {
988*5113495bSYour Name 				return -EFAULT;
989*5113495bSYour Name 			}
990*5113495bSYour Name 			ret_val += count;
991*5113495bSYour Name 			rem_len -= count;
992*5113495bSYour Name 			qdf_spin_lock_bh(&pl_info->log_lock);
993*5113495bSYour Name 		}
994*5113495bSYour Name 
995*5113495bSYour Name 		if (rem_len == 0)
996*5113495bSYour Name 			goto rd_done;
997*5113495bSYour Name 
998*5113495bSYour Name 		ppos_data =
999*5113495bSYour Name 			*ppos + ret_val - (bufhdr_size +
1000*5113495bSYour Name 					   (fold_offset - start_offset + 1));
1001*5113495bSYour Name 
1002*5113495bSYour Name 		if (ppos_data <= end_offset) {
1003*5113495bSYour Name 			count = QDF_MIN(rem_len, (end_offset - ppos_data + 1));
1004*5113495bSYour Name 			qdf_spin_unlock_bh(&pl_info->log_lock);
1005*5113495bSYour Name 			if (copy_to_user(buf + ret_val,
1006*5113495bSYour Name 					 log_buf->log_data + ppos_data,
1007*5113495bSYour Name 					 count)) {
1008*5113495bSYour Name 				return -EFAULT;
1009*5113495bSYour Name 			}
1010*5113495bSYour Name 			ret_val += count;
1011*5113495bSYour Name 			rem_len -= count;
1012*5113495bSYour Name 			qdf_spin_lock_bh(&pl_info->log_lock);
1013*5113495bSYour Name 		}
1014*5113495bSYour Name 	}
1015*5113495bSYour Name 
1016*5113495bSYour Name rd_done:
1017*5113495bSYour Name 	if ((ret_val < nbytes) && pl_info->saved_state) {
1018*5113495bSYour Name 		pl_info->log_state = pl_info->saved_state;
1019*5113495bSYour Name 		pl_info->saved_state = 0;
1020*5113495bSYour Name 	}
1021*5113495bSYour Name 	*ppos += ret_val;
1022*5113495bSYour Name 
1023*5113495bSYour Name 	qdf_spin_unlock_bh(&pl_info->log_lock);
1024*5113495bSYour Name 	return ret_val;
1025*5113495bSYour Name }
1026*5113495bSYour Name 
1027*5113495bSYour Name static ssize_t
pktlog_read(struct file * file,char * buf,size_t nbytes,loff_t * ppos)1028*5113495bSYour Name pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
1029*5113495bSYour Name {
1030*5113495bSYour Name 	struct ath_pktlog_info *info = pde_data(file->f_path.dentry->d_inode);
1031*5113495bSYour Name 	struct qdf_op_sync *op_sync;
1032*5113495bSYour Name 	ssize_t err_size;
1033*5113495bSYour Name 
1034*5113495bSYour Name 	if (!info)
1035*5113495bSYour Name 		return 0;
1036*5113495bSYour Name 
1037*5113495bSYour Name 	err_size = qdf_op_protect(&op_sync);
1038*5113495bSYour Name 	if (err_size)
1039*5113495bSYour Name 		return err_size;
1040*5113495bSYour Name 
1041*5113495bSYour Name 	mutex_lock(&info->pktlog_mutex);
1042*5113495bSYour Name 	err_size = __pktlog_read(file, buf, nbytes, ppos);
1043*5113495bSYour Name 	mutex_unlock(&info->pktlog_mutex);
1044*5113495bSYour Name 
1045*5113495bSYour Name 	qdf_op_unprotect(op_sync);
1046*5113495bSYour Name 
1047*5113495bSYour Name 	return err_size;
1048*5113495bSYour Name }
1049*5113495bSYour Name 
pktlogmod_init(void * context)1050*5113495bSYour Name int pktlogmod_init(void *context)
1051*5113495bSYour Name {
1052*5113495bSYour Name 	int ret;
1053*5113495bSYour Name 
1054*5113495bSYour Name 	qdf_info("Initialize pkt_log module");
1055*5113495bSYour Name 	/* create the proc directory entry */
1056*5113495bSYour Name 	g_pktlog_pde = proc_mkdir(PKTLOG_PROC_DIR, NULL);
1057*5113495bSYour Name 
1058*5113495bSYour Name 	if (!g_pktlog_pde) {
1059*5113495bSYour Name 		qdf_info(PKTLOG_TAG "proc_mkdir failed");
1060*5113495bSYour Name 		return -EPERM;
1061*5113495bSYour Name 	}
1062*5113495bSYour Name 
1063*5113495bSYour Name 	/* Attach packet log */
1064*5113495bSYour Name 	ret = pktlog_attach((struct hif_opaque_softc *)context);
1065*5113495bSYour Name 
1066*5113495bSYour Name 	/* If packet log init failed */
1067*5113495bSYour Name 	if (ret) {
1068*5113495bSYour Name 		qdf_err("pktlog_attach failed");
1069*5113495bSYour Name 		goto attach_fail;
1070*5113495bSYour Name 	}
1071*5113495bSYour Name 
1072*5113495bSYour Name 	return ret;
1073*5113495bSYour Name 
1074*5113495bSYour Name attach_fail:
1075*5113495bSYour Name 	remove_proc_entry(PKTLOG_PROC_DIR, NULL);
1076*5113495bSYour Name 	g_pktlog_pde = NULL;
1077*5113495bSYour Name 
1078*5113495bSYour Name 	return ret;
1079*5113495bSYour Name }
1080*5113495bSYour Name 
pktlogmod_exit(void * context)1081*5113495bSYour Name void pktlogmod_exit(void *context)
1082*5113495bSYour Name {
1083*5113495bSYour Name 	qdf_info("pkt_log module cleanup");
1084*5113495bSYour Name 	if (!g_pktlog_pde) {
1085*5113495bSYour Name 		qdf_err("g_pktlog_pde is NULL");
1086*5113495bSYour Name 		return;
1087*5113495bSYour Name 	}
1088*5113495bSYour Name 
1089*5113495bSYour Name 	pktlog_detach((struct hif_opaque_softc *)context);
1090*5113495bSYour Name 
1091*5113495bSYour Name 	/*
1092*5113495bSYour Name 	 *  pdev kill needs to be implemented
1093*5113495bSYour Name 	 */
1094*5113495bSYour Name 	remove_proc_entry(PKTLOG_PROC_DIR, NULL);
1095*5113495bSYour Name 	g_pktlog_pde = NULL;
1096*5113495bSYour Name }
1097*5113495bSYour Name #endif
1098