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