1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2004-2011 Atheros Communications Inc.
3*4882a593Smuzhiyun * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
6*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
7*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*4882a593Smuzhiyun * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*4882a593Smuzhiyun * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*4882a593Smuzhiyun * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "core.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/skbuff.h>
21*4882a593Smuzhiyun #include <linux/fs.h>
22*4882a593Smuzhiyun #include <linux/vmalloc.h>
23*4882a593Smuzhiyun #include <linux/export.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "debug.h"
26*4882a593Smuzhiyun #include "target.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct ath6kl_fwlog_slot {
29*4882a593Smuzhiyun __le32 timestamp;
30*4882a593Smuzhiyun __le32 length;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
33*4882a593Smuzhiyun u8 payload[];
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define ATH6KL_FWLOG_MAX_ENTRIES 20
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define ATH6KL_FWLOG_VALID_MASK 0x1ffff
39*4882a593Smuzhiyun
ath6kl_printk(const char * level,const char * fmt,...)40*4882a593Smuzhiyun void ath6kl_printk(const char *level, const char *fmt, ...)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun struct va_format vaf;
43*4882a593Smuzhiyun va_list args;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun va_start(args, fmt);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun vaf.fmt = fmt;
48*4882a593Smuzhiyun vaf.va = &args;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun printk("%sath6kl: %pV", level, &vaf);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun va_end(args);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_printk);
55*4882a593Smuzhiyun
ath6kl_info(const char * fmt,...)56*4882a593Smuzhiyun void ath6kl_info(const char *fmt, ...)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun struct va_format vaf = {
59*4882a593Smuzhiyun .fmt = fmt,
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun va_list args;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun va_start(args, fmt);
64*4882a593Smuzhiyun vaf.va = &args;
65*4882a593Smuzhiyun ath6kl_printk(KERN_INFO, "%pV", &vaf);
66*4882a593Smuzhiyun trace_ath6kl_log_info(&vaf);
67*4882a593Smuzhiyun va_end(args);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_info);
70*4882a593Smuzhiyun
ath6kl_err(const char * fmt,...)71*4882a593Smuzhiyun void ath6kl_err(const char *fmt, ...)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun struct va_format vaf = {
74*4882a593Smuzhiyun .fmt = fmt,
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun va_list args;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun va_start(args, fmt);
79*4882a593Smuzhiyun vaf.va = &args;
80*4882a593Smuzhiyun ath6kl_printk(KERN_ERR, "%pV", &vaf);
81*4882a593Smuzhiyun trace_ath6kl_log_err(&vaf);
82*4882a593Smuzhiyun va_end(args);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_err);
85*4882a593Smuzhiyun
ath6kl_warn(const char * fmt,...)86*4882a593Smuzhiyun void ath6kl_warn(const char *fmt, ...)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct va_format vaf = {
89*4882a593Smuzhiyun .fmt = fmt,
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun va_list args;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun va_start(args, fmt);
94*4882a593Smuzhiyun vaf.va = &args;
95*4882a593Smuzhiyun ath6kl_printk(KERN_WARNING, "%pV", &vaf);
96*4882a593Smuzhiyun trace_ath6kl_log_warn(&vaf);
97*4882a593Smuzhiyun va_end(args);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_warn);
100*4882a593Smuzhiyun
ath6kl_read_tgt_stats(struct ath6kl * ar,struct ath6kl_vif * vif)101*4882a593Smuzhiyun int ath6kl_read_tgt_stats(struct ath6kl *ar, struct ath6kl_vif *vif)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun long left;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun if (down_interruptible(&ar->sem))
106*4882a593Smuzhiyun return -EBUSY;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun set_bit(STATS_UPDATE_PEND, &vif->flags);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
111*4882a593Smuzhiyun up(&ar->sem);
112*4882a593Smuzhiyun return -EIO;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun left = wait_event_interruptible_timeout(ar->event_wq,
116*4882a593Smuzhiyun !test_bit(STATS_UPDATE_PEND,
117*4882a593Smuzhiyun &vif->flags), WMI_TIMEOUT);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun up(&ar->sem);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (left <= 0)
122*4882a593Smuzhiyun return -ETIMEDOUT;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun return 0;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_read_tgt_stats);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun #ifdef CONFIG_ATH6KL_DEBUG
129*4882a593Smuzhiyun
ath6kl_dbg(enum ATH6K_DEBUG_MASK mask,const char * fmt,...)130*4882a593Smuzhiyun void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct va_format vaf;
133*4882a593Smuzhiyun va_list args;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun va_start(args, fmt);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun vaf.fmt = fmt;
138*4882a593Smuzhiyun vaf.va = &args;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (debug_mask & mask)
141*4882a593Smuzhiyun ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun trace_ath6kl_log_dbg(mask, &vaf);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun va_end(args);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_dbg);
148*4882a593Smuzhiyun
ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,const char * msg,const char * prefix,const void * buf,size_t len)149*4882a593Smuzhiyun void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
150*4882a593Smuzhiyun const char *msg, const char *prefix,
151*4882a593Smuzhiyun const void *buf, size_t len)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun if (debug_mask & mask) {
154*4882a593Smuzhiyun if (msg)
155*4882a593Smuzhiyun ath6kl_dbg(mask, "%s\n", msg);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* tracing code doesn't like null strings :/ */
161*4882a593Smuzhiyun trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
162*4882a593Smuzhiyun buf, len);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun EXPORT_SYMBOL(ath6kl_dbg_dump);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun #define REG_OUTPUT_LEN_PER_LINE 25
167*4882a593Smuzhiyun #define REGTYPE_STR_LEN 100
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun struct ath6kl_diag_reg_info {
170*4882a593Smuzhiyun u32 reg_start;
171*4882a593Smuzhiyun u32 reg_end;
172*4882a593Smuzhiyun const char *reg_info;
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun static const struct ath6kl_diag_reg_info diag_reg[] = {
176*4882a593Smuzhiyun { 0x20000, 0x200fc, "General DMA and Rx registers" },
177*4882a593Smuzhiyun { 0x28000, 0x28900, "MAC PCU register & keycache" },
178*4882a593Smuzhiyun { 0x20800, 0x20a40, "QCU" },
179*4882a593Smuzhiyun { 0x21000, 0x212f0, "DCU" },
180*4882a593Smuzhiyun { 0x4000, 0x42e4, "RTC" },
181*4882a593Smuzhiyun { 0x540000, 0x540000 + (256 * 1024), "RAM" },
182*4882a593Smuzhiyun { 0x29800, 0x2B210, "Base Band" },
183*4882a593Smuzhiyun { 0x1C000, 0x1C748, "Analog" },
184*4882a593Smuzhiyun };
185*4882a593Smuzhiyun
ath6kl_dump_registers(struct ath6kl_device * dev,struct ath6kl_irq_proc_registers * irq_proc_reg,struct ath6kl_irq_enable_reg * irq_enable_reg)186*4882a593Smuzhiyun void ath6kl_dump_registers(struct ath6kl_device *dev,
187*4882a593Smuzhiyun struct ath6kl_irq_proc_registers *irq_proc_reg,
188*4882a593Smuzhiyun struct ath6kl_irq_enable_reg *irq_enable_reg)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n"));
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun if (irq_proc_reg != NULL) {
193*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
194*4882a593Smuzhiyun "Host Int status: 0x%x\n",
195*4882a593Smuzhiyun irq_proc_reg->host_int_status);
196*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
197*4882a593Smuzhiyun "CPU Int status: 0x%x\n",
198*4882a593Smuzhiyun irq_proc_reg->cpu_int_status);
199*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
200*4882a593Smuzhiyun "Error Int status: 0x%x\n",
201*4882a593Smuzhiyun irq_proc_reg->error_int_status);
202*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
203*4882a593Smuzhiyun "Counter Int status: 0x%x\n",
204*4882a593Smuzhiyun irq_proc_reg->counter_int_status);
205*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
206*4882a593Smuzhiyun "Mbox Frame: 0x%x\n",
207*4882a593Smuzhiyun irq_proc_reg->mbox_frame);
208*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
209*4882a593Smuzhiyun "Rx Lookahead Valid: 0x%x\n",
210*4882a593Smuzhiyun irq_proc_reg->rx_lkahd_valid);
211*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
212*4882a593Smuzhiyun "Rx Lookahead 0: 0x%x\n",
213*4882a593Smuzhiyun irq_proc_reg->rx_lkahd[0]);
214*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
215*4882a593Smuzhiyun "Rx Lookahead 1: 0x%x\n",
216*4882a593Smuzhiyun irq_proc_reg->rx_lkahd[1]);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (dev->ar->mbox_info.gmbox_addr != 0) {
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun * If the target supports GMBOX hardware, dump some
221*4882a593Smuzhiyun * additional state.
222*4882a593Smuzhiyun */
223*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
224*4882a593Smuzhiyun "GMBOX Host Int status 2: 0x%x\n",
225*4882a593Smuzhiyun irq_proc_reg->host_int_status2);
226*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
227*4882a593Smuzhiyun "GMBOX RX Avail: 0x%x\n",
228*4882a593Smuzhiyun irq_proc_reg->gmbox_rx_avail);
229*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
230*4882a593Smuzhiyun "GMBOX lookahead alias 0: 0x%x\n",
231*4882a593Smuzhiyun irq_proc_reg->rx_gmbox_lkahd_alias[0]);
232*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
233*4882a593Smuzhiyun "GMBOX lookahead alias 1: 0x%x\n",
234*4882a593Smuzhiyun irq_proc_reg->rx_gmbox_lkahd_alias[1]);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (irq_enable_reg != NULL) {
239*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ,
240*4882a593Smuzhiyun "Int status Enable: 0x%x\n",
241*4882a593Smuzhiyun irq_enable_reg->int_status_en);
242*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n",
243*4882a593Smuzhiyun irq_enable_reg->cntr_int_status_en);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n");
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
dump_cred_dist(struct htc_endpoint_credit_dist * ep_dist)248*4882a593Smuzhiyun static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT,
251*4882a593Smuzhiyun "--- endpoint: %d svc_id: 0x%X ---\n",
252*4882a593Smuzhiyun ep_dist->endpoint, ep_dist->svc_id);
253*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags : 0x%X\n",
254*4882a593Smuzhiyun ep_dist->dist_flags);
255*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm : %d\n",
256*4882a593Smuzhiyun ep_dist->cred_norm);
257*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min : %d\n",
258*4882a593Smuzhiyun ep_dist->cred_min);
259*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits : %d\n",
260*4882a593Smuzhiyun ep_dist->credits);
261*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd : %d\n",
262*4882a593Smuzhiyun ep_dist->cred_assngd);
263*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred : %d\n",
264*4882a593Smuzhiyun ep_dist->seek_cred);
265*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz : %d\n",
266*4882a593Smuzhiyun ep_dist->cred_sz);
267*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg : %d\n",
268*4882a593Smuzhiyun ep_dist->cred_per_msg);
269*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist : %d\n",
270*4882a593Smuzhiyun ep_dist->cred_to_dist);
271*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth : %d\n",
272*4882a593Smuzhiyun get_queue_depth(&ep_dist->htc_ep->txq));
273*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT,
274*4882a593Smuzhiyun "----------------------------------\n");
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* FIXME: move to htc.c */
dump_cred_dist_stats(struct htc_target * target)278*4882a593Smuzhiyun void dump_cred_dist_stats(struct htc_target *target)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun struct htc_endpoint_credit_dist *ep_list;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun list_for_each_entry(ep_list, &target->cred_dist_list, list)
283*4882a593Smuzhiyun dump_cred_dist(ep_list);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun ath6kl_dbg(ATH6KL_DBG_CREDIT,
286*4882a593Smuzhiyun "credit distribution total %d free %d\n",
287*4882a593Smuzhiyun target->credit_info->total_avail_credits,
288*4882a593Smuzhiyun target->credit_info->cur_free_credits);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
ath6kl_debug_war(struct ath6kl * ar,enum ath6kl_war war)291*4882a593Smuzhiyun void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun switch (war) {
294*4882a593Smuzhiyun case ATH6KL_WAR_INVALID_RATE:
295*4882a593Smuzhiyun ar->debug.war_stats.invalid_rate++;
296*4882a593Smuzhiyun break;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
read_file_war_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)300*4882a593Smuzhiyun static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
301*4882a593Smuzhiyun size_t count, loff_t *ppos)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
304*4882a593Smuzhiyun char *buf;
305*4882a593Smuzhiyun unsigned int len = 0, buf_len = 1500;
306*4882a593Smuzhiyun ssize_t ret_cnt;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun buf = kzalloc(buf_len, GFP_KERNEL);
309*4882a593Smuzhiyun if (!buf)
310*4882a593Smuzhiyun return -ENOMEM;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "\n");
313*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n",
314*4882a593Smuzhiyun "Workaround stats");
315*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
316*4882a593Smuzhiyun "=================");
317*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
318*4882a593Smuzhiyun "Invalid rates", ar->debug.war_stats.invalid_rate);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (WARN_ON(len > buf_len))
321*4882a593Smuzhiyun len = buf_len;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun kfree(buf);
326*4882a593Smuzhiyun return ret_cnt;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun static const struct file_operations fops_war_stats = {
330*4882a593Smuzhiyun .read = read_file_war_stats,
331*4882a593Smuzhiyun .open = simple_open,
332*4882a593Smuzhiyun .owner = THIS_MODULE,
333*4882a593Smuzhiyun .llseek = default_llseek,
334*4882a593Smuzhiyun };
335*4882a593Smuzhiyun
ath6kl_debug_fwlog_event(struct ath6kl * ar,const void * buf,size_t len)336*4882a593Smuzhiyun void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun struct ath6kl_fwlog_slot *slot;
339*4882a593Smuzhiyun struct sk_buff *skb;
340*4882a593Smuzhiyun size_t slot_len;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
343*4882a593Smuzhiyun return;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun skb = alloc_skb(slot_len, GFP_KERNEL);
348*4882a593Smuzhiyun if (!skb)
349*4882a593Smuzhiyun return;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun slot = skb_put(skb, slot_len);
352*4882a593Smuzhiyun slot->timestamp = cpu_to_le32(jiffies);
353*4882a593Smuzhiyun slot->length = cpu_to_le32(len);
354*4882a593Smuzhiyun memcpy(slot->payload, buf, len);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */
357*4882a593Smuzhiyun memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun spin_lock(&ar->debug.fwlog_queue.lock);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun __skb_queue_tail(&ar->debug.fwlog_queue, skb);
362*4882a593Smuzhiyun complete(&ar->debug.fwlog_completion);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* drop oldest entries */
365*4882a593Smuzhiyun while (skb_queue_len(&ar->debug.fwlog_queue) >
366*4882a593Smuzhiyun ATH6KL_FWLOG_MAX_ENTRIES) {
367*4882a593Smuzhiyun skb = __skb_dequeue(&ar->debug.fwlog_queue);
368*4882a593Smuzhiyun kfree_skb(skb);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun spin_unlock(&ar->debug.fwlog_queue.lock);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun return;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
ath6kl_fwlog_open(struct inode * inode,struct file * file)376*4882a593Smuzhiyun static int ath6kl_fwlog_open(struct inode *inode, struct file *file)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun struct ath6kl *ar = inode->i_private;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (ar->debug.fwlog_open)
381*4882a593Smuzhiyun return -EBUSY;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun ar->debug.fwlog_open = true;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun file->private_data = inode->i_private;
386*4882a593Smuzhiyun return 0;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
ath6kl_fwlog_release(struct inode * inode,struct file * file)389*4882a593Smuzhiyun static int ath6kl_fwlog_release(struct inode *inode, struct file *file)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun struct ath6kl *ar = inode->i_private;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun ar->debug.fwlog_open = false;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
ath6kl_fwlog_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)398*4882a593Smuzhiyun static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
399*4882a593Smuzhiyun size_t count, loff_t *ppos)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
402*4882a593Smuzhiyun struct sk_buff *skb;
403*4882a593Smuzhiyun ssize_t ret_cnt;
404*4882a593Smuzhiyun size_t len = 0;
405*4882a593Smuzhiyun char *buf;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun buf = vmalloc(count);
408*4882a593Smuzhiyun if (!buf)
409*4882a593Smuzhiyun return -ENOMEM;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun /* read undelivered logs from firmware */
412*4882a593Smuzhiyun ath6kl_read_fwlogs(ar);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun spin_lock(&ar->debug.fwlog_queue.lock);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
417*4882a593Smuzhiyun if (skb->len > count - len) {
418*4882a593Smuzhiyun /* not enough space, put skb back and leave */
419*4882a593Smuzhiyun __skb_queue_head(&ar->debug.fwlog_queue, skb);
420*4882a593Smuzhiyun break;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun memcpy(buf + len, skb->data, skb->len);
425*4882a593Smuzhiyun len += skb->len;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun kfree_skb(skb);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun spin_unlock(&ar->debug.fwlog_queue.lock);
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun /* FIXME: what to do if len == 0? */
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun vfree(buf);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun return ret_cnt;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun static const struct file_operations fops_fwlog = {
442*4882a593Smuzhiyun .open = ath6kl_fwlog_open,
443*4882a593Smuzhiyun .release = ath6kl_fwlog_release,
444*4882a593Smuzhiyun .read = ath6kl_fwlog_read,
445*4882a593Smuzhiyun .owner = THIS_MODULE,
446*4882a593Smuzhiyun .llseek = default_llseek,
447*4882a593Smuzhiyun };
448*4882a593Smuzhiyun
ath6kl_fwlog_block_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)449*4882a593Smuzhiyun static ssize_t ath6kl_fwlog_block_read(struct file *file,
450*4882a593Smuzhiyun char __user *user_buf,
451*4882a593Smuzhiyun size_t count,
452*4882a593Smuzhiyun loff_t *ppos)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
455*4882a593Smuzhiyun struct sk_buff *skb;
456*4882a593Smuzhiyun ssize_t ret_cnt;
457*4882a593Smuzhiyun size_t len = 0, not_copied;
458*4882a593Smuzhiyun char *buf;
459*4882a593Smuzhiyun int ret;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun buf = vmalloc(count);
462*4882a593Smuzhiyun if (!buf)
463*4882a593Smuzhiyun return -ENOMEM;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun spin_lock(&ar->debug.fwlog_queue.lock);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (skb_queue_len(&ar->debug.fwlog_queue) == 0) {
468*4882a593Smuzhiyun /* we must init under queue lock */
469*4882a593Smuzhiyun init_completion(&ar->debug.fwlog_completion);
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun spin_unlock(&ar->debug.fwlog_queue.lock);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun ret = wait_for_completion_interruptible(
474*4882a593Smuzhiyun &ar->debug.fwlog_completion);
475*4882a593Smuzhiyun if (ret == -ERESTARTSYS) {
476*4882a593Smuzhiyun vfree(buf);
477*4882a593Smuzhiyun return ret;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun spin_lock(&ar->debug.fwlog_queue.lock);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) {
484*4882a593Smuzhiyun if (skb->len > count - len) {
485*4882a593Smuzhiyun /* not enough space, put skb back and leave */
486*4882a593Smuzhiyun __skb_queue_head(&ar->debug.fwlog_queue, skb);
487*4882a593Smuzhiyun break;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun memcpy(buf + len, skb->data, skb->len);
492*4882a593Smuzhiyun len += skb->len;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun kfree_skb(skb);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun spin_unlock(&ar->debug.fwlog_queue.lock);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /* FIXME: what to do if len == 0? */
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun not_copied = copy_to_user(user_buf, buf, len);
502*4882a593Smuzhiyun if (not_copied != 0) {
503*4882a593Smuzhiyun ret_cnt = -EFAULT;
504*4882a593Smuzhiyun goto out;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun *ppos = *ppos + len;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun ret_cnt = len;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun out:
512*4882a593Smuzhiyun vfree(buf);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun return ret_cnt;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun static const struct file_operations fops_fwlog_block = {
518*4882a593Smuzhiyun .open = ath6kl_fwlog_open,
519*4882a593Smuzhiyun .release = ath6kl_fwlog_release,
520*4882a593Smuzhiyun .read = ath6kl_fwlog_block_read,
521*4882a593Smuzhiyun .owner = THIS_MODULE,
522*4882a593Smuzhiyun .llseek = default_llseek,
523*4882a593Smuzhiyun };
524*4882a593Smuzhiyun
ath6kl_fwlog_mask_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)525*4882a593Smuzhiyun static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
526*4882a593Smuzhiyun size_t count, loff_t *ppos)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
529*4882a593Smuzhiyun char buf[16];
530*4882a593Smuzhiyun int len;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
ath6kl_fwlog_mask_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)537*4882a593Smuzhiyun static ssize_t ath6kl_fwlog_mask_write(struct file *file,
538*4882a593Smuzhiyun const char __user *user_buf,
539*4882a593Smuzhiyun size_t count, loff_t *ppos)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
542*4882a593Smuzhiyun int ret;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
545*4882a593Smuzhiyun if (ret)
546*4882a593Smuzhiyun return ret;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
549*4882a593Smuzhiyun ATH6KL_FWLOG_VALID_MASK,
550*4882a593Smuzhiyun ar->debug.fwlog_mask);
551*4882a593Smuzhiyun if (ret)
552*4882a593Smuzhiyun return ret;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun return count;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun static const struct file_operations fops_fwlog_mask = {
558*4882a593Smuzhiyun .open = simple_open,
559*4882a593Smuzhiyun .read = ath6kl_fwlog_mask_read,
560*4882a593Smuzhiyun .write = ath6kl_fwlog_mask_write,
561*4882a593Smuzhiyun .owner = THIS_MODULE,
562*4882a593Smuzhiyun .llseek = default_llseek,
563*4882a593Smuzhiyun };
564*4882a593Smuzhiyun
read_file_tgt_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)565*4882a593Smuzhiyun static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
566*4882a593Smuzhiyun size_t count, loff_t *ppos)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
569*4882a593Smuzhiyun struct ath6kl_vif *vif;
570*4882a593Smuzhiyun struct target_stats *tgt_stats;
571*4882a593Smuzhiyun char *buf;
572*4882a593Smuzhiyun unsigned int len = 0, buf_len = 1500;
573*4882a593Smuzhiyun int i;
574*4882a593Smuzhiyun ssize_t ret_cnt;
575*4882a593Smuzhiyun int rv;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun vif = ath6kl_vif_first(ar);
578*4882a593Smuzhiyun if (!vif)
579*4882a593Smuzhiyun return -EIO;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun buf = kzalloc(buf_len, GFP_KERNEL);
582*4882a593Smuzhiyun if (!buf)
583*4882a593Smuzhiyun return -ENOMEM;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun rv = ath6kl_read_tgt_stats(ar, vif);
586*4882a593Smuzhiyun if (rv < 0) {
587*4882a593Smuzhiyun kfree(buf);
588*4882a593Smuzhiyun return rv;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun tgt_stats = &vif->target_stats;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "\n");
594*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n",
595*4882a593Smuzhiyun "Target Tx stats");
596*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
597*4882a593Smuzhiyun "=================");
598*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
599*4882a593Smuzhiyun "Ucast packets", tgt_stats->tx_ucast_pkt);
600*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
601*4882a593Smuzhiyun "Bcast packets", tgt_stats->tx_bcast_pkt);
602*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
603*4882a593Smuzhiyun "Ucast byte", tgt_stats->tx_ucast_byte);
604*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
605*4882a593Smuzhiyun "Bcast byte", tgt_stats->tx_bcast_byte);
606*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
607*4882a593Smuzhiyun "Rts success cnt", tgt_stats->tx_rts_success_cnt);
608*4882a593Smuzhiyun for (i = 0; i < 4; i++)
609*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len,
610*4882a593Smuzhiyun "%18s %d %10llu\n", "PER on ac",
611*4882a593Smuzhiyun i, tgt_stats->tx_pkt_per_ac[i]);
612*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
613*4882a593Smuzhiyun "Error", tgt_stats->tx_err);
614*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
615*4882a593Smuzhiyun "Fail count", tgt_stats->tx_fail_cnt);
616*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
617*4882a593Smuzhiyun "Retry count", tgt_stats->tx_retry_cnt);
618*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
619*4882a593Smuzhiyun "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
620*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
621*4882a593Smuzhiyun "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
622*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
623*4882a593Smuzhiyun "TKIP counter measure used",
624*4882a593Smuzhiyun tgt_stats->tkip_cnter_measures_invoked);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n",
627*4882a593Smuzhiyun "Target Rx stats");
628*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n",
629*4882a593Smuzhiyun "=================");
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
632*4882a593Smuzhiyun "Ucast packets", tgt_stats->rx_ucast_pkt);
633*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
634*4882a593Smuzhiyun "Ucast Rate", tgt_stats->rx_ucast_rate);
635*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
636*4882a593Smuzhiyun "Bcast packets", tgt_stats->rx_bcast_pkt);
637*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
638*4882a593Smuzhiyun "Ucast byte", tgt_stats->rx_ucast_byte);
639*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
640*4882a593Smuzhiyun "Bcast byte", tgt_stats->rx_bcast_byte);
641*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
642*4882a593Smuzhiyun "Fragmented pkt", tgt_stats->rx_frgment_pkt);
643*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
644*4882a593Smuzhiyun "Error", tgt_stats->rx_err);
645*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
646*4882a593Smuzhiyun "CRC Err", tgt_stats->rx_crc_err);
647*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
648*4882a593Smuzhiyun "Key cache miss", tgt_stats->rx_key_cache_miss);
649*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
650*4882a593Smuzhiyun "Decrypt Err", tgt_stats->rx_decrypt_err);
651*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
652*4882a593Smuzhiyun "Duplicate frame", tgt_stats->rx_dupl_frame);
653*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
654*4882a593Smuzhiyun "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
655*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
656*4882a593Smuzhiyun "TKIP format err", tgt_stats->tkip_fmt_err);
657*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
658*4882a593Smuzhiyun "CCMP format Err", tgt_stats->ccmp_fmt_err);
659*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
660*4882a593Smuzhiyun "CCMP Replay Err", tgt_stats->ccmp_replays);
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n",
663*4882a593Smuzhiyun "Misc Target stats");
664*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s\n",
665*4882a593Smuzhiyun "=================");
666*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
667*4882a593Smuzhiyun "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
668*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
669*4882a593Smuzhiyun "Num Connects", tgt_stats->cs_connect_cnt);
670*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
671*4882a593Smuzhiyun "Num disconnects", tgt_stats->cs_discon_cnt);
672*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
673*4882a593Smuzhiyun "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
674*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
675*4882a593Smuzhiyun "ARP pkt received", tgt_stats->arp_received);
676*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
677*4882a593Smuzhiyun "ARP pkt matched", tgt_stats->arp_matched);
678*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
679*4882a593Smuzhiyun "ARP pkt replied", tgt_stats->arp_replied);
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun if (len > buf_len)
682*4882a593Smuzhiyun len = buf_len;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun kfree(buf);
687*4882a593Smuzhiyun return ret_cnt;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun static const struct file_operations fops_tgt_stats = {
691*4882a593Smuzhiyun .read = read_file_tgt_stats,
692*4882a593Smuzhiyun .open = simple_open,
693*4882a593Smuzhiyun .owner = THIS_MODULE,
694*4882a593Smuzhiyun .llseek = default_llseek,
695*4882a593Smuzhiyun };
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun #define print_credit_info(fmt_str, ep_list_field) \
698*4882a593Smuzhiyun (len += scnprintf(buf + len, buf_len - len, fmt_str, \
699*4882a593Smuzhiyun ep_list->ep_list_field))
700*4882a593Smuzhiyun #define CREDIT_INFO_DISPLAY_STRING_LEN 200
701*4882a593Smuzhiyun #define CREDIT_INFO_LEN 128
702*4882a593Smuzhiyun
read_file_credit_dist_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)703*4882a593Smuzhiyun static ssize_t read_file_credit_dist_stats(struct file *file,
704*4882a593Smuzhiyun char __user *user_buf,
705*4882a593Smuzhiyun size_t count, loff_t *ppos)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
708*4882a593Smuzhiyun struct htc_target *target = ar->htc_target;
709*4882a593Smuzhiyun struct htc_endpoint_credit_dist *ep_list;
710*4882a593Smuzhiyun char *buf;
711*4882a593Smuzhiyun unsigned int buf_len, len = 0;
712*4882a593Smuzhiyun ssize_t ret_cnt;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
715*4882a593Smuzhiyun get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
716*4882a593Smuzhiyun buf = kzalloc(buf_len, GFP_KERNEL);
717*4882a593Smuzhiyun if (!buf)
718*4882a593Smuzhiyun return -ENOMEM;
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
721*4882a593Smuzhiyun "Total Avail Credits: ",
722*4882a593Smuzhiyun target->credit_info->total_avail_credits);
723*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
724*4882a593Smuzhiyun "Free credits :",
725*4882a593Smuzhiyun target->credit_info->cur_free_credits);
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len,
728*4882a593Smuzhiyun " Epid Flags Cred_norm Cred_min Credits Cred_assngd"
729*4882a593Smuzhiyun " Seek_cred Cred_sz Cred_per_msg Cred_to_dist"
730*4882a593Smuzhiyun " qdepth\n");
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun list_for_each_entry(ep_list, &target->cred_dist_list, list) {
733*4882a593Smuzhiyun print_credit_info(" %2d", endpoint);
734*4882a593Smuzhiyun print_credit_info("%10x", dist_flags);
735*4882a593Smuzhiyun print_credit_info("%8d", cred_norm);
736*4882a593Smuzhiyun print_credit_info("%9d", cred_min);
737*4882a593Smuzhiyun print_credit_info("%9d", credits);
738*4882a593Smuzhiyun print_credit_info("%10d", cred_assngd);
739*4882a593Smuzhiyun print_credit_info("%13d", seek_cred);
740*4882a593Smuzhiyun print_credit_info("%12d", cred_sz);
741*4882a593Smuzhiyun print_credit_info("%9d", cred_per_msg);
742*4882a593Smuzhiyun print_credit_info("%14d", cred_to_dist);
743*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%12d\n",
744*4882a593Smuzhiyun get_queue_depth(&ep_list->htc_ep->txq));
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun if (len > buf_len)
748*4882a593Smuzhiyun len = buf_len;
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
751*4882a593Smuzhiyun kfree(buf);
752*4882a593Smuzhiyun return ret_cnt;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun static const struct file_operations fops_credit_dist_stats = {
756*4882a593Smuzhiyun .read = read_file_credit_dist_stats,
757*4882a593Smuzhiyun .open = simple_open,
758*4882a593Smuzhiyun .owner = THIS_MODULE,
759*4882a593Smuzhiyun .llseek = default_llseek,
760*4882a593Smuzhiyun };
761*4882a593Smuzhiyun
print_endpoint_stat(struct htc_target * target,char * buf,unsigned int buf_len,unsigned int len,int offset,const char * name)762*4882a593Smuzhiyun static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
763*4882a593Smuzhiyun unsigned int buf_len, unsigned int len,
764*4882a593Smuzhiyun int offset, const char *name)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun int i;
767*4882a593Smuzhiyun struct htc_endpoint_stats *ep_st;
768*4882a593Smuzhiyun u32 *counter;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "%s:", name);
771*4882a593Smuzhiyun for (i = 0; i < ENDPOINT_MAX; i++) {
772*4882a593Smuzhiyun ep_st = &target->endpoint[i].ep_st;
773*4882a593Smuzhiyun counter = ((u32 *) ep_st) + (offset / 4);
774*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, " %u", *counter);
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len, "\n");
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun return len;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
ath6kl_endpoint_stats_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)781*4882a593Smuzhiyun static ssize_t ath6kl_endpoint_stats_read(struct file *file,
782*4882a593Smuzhiyun char __user *user_buf,
783*4882a593Smuzhiyun size_t count, loff_t *ppos)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
786*4882a593Smuzhiyun struct htc_target *target = ar->htc_target;
787*4882a593Smuzhiyun char *buf;
788*4882a593Smuzhiyun unsigned int buf_len, len = 0;
789*4882a593Smuzhiyun ssize_t ret_cnt;
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
792*4882a593Smuzhiyun (25 + ENDPOINT_MAX * 11);
793*4882a593Smuzhiyun buf = kmalloc(buf_len, GFP_KERNEL);
794*4882a593Smuzhiyun if (!buf)
795*4882a593Smuzhiyun return -ENOMEM;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun #define EPSTAT(name) \
798*4882a593Smuzhiyun do { \
799*4882a593Smuzhiyun len = print_endpoint_stat(target, buf, buf_len, len, \
800*4882a593Smuzhiyun offsetof(struct htc_endpoint_stats, \
801*4882a593Smuzhiyun name), \
802*4882a593Smuzhiyun #name); \
803*4882a593Smuzhiyun } while (0)
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun EPSTAT(cred_low_indicate);
806*4882a593Smuzhiyun EPSTAT(tx_issued);
807*4882a593Smuzhiyun EPSTAT(tx_pkt_bundled);
808*4882a593Smuzhiyun EPSTAT(tx_bundles);
809*4882a593Smuzhiyun EPSTAT(tx_dropped);
810*4882a593Smuzhiyun EPSTAT(tx_cred_rpt);
811*4882a593Smuzhiyun EPSTAT(cred_rpt_from_rx);
812*4882a593Smuzhiyun EPSTAT(cred_rpt_from_other);
813*4882a593Smuzhiyun EPSTAT(cred_rpt_ep0);
814*4882a593Smuzhiyun EPSTAT(cred_from_rx);
815*4882a593Smuzhiyun EPSTAT(cred_from_other);
816*4882a593Smuzhiyun EPSTAT(cred_from_ep0);
817*4882a593Smuzhiyun EPSTAT(cred_cosumd);
818*4882a593Smuzhiyun EPSTAT(cred_retnd);
819*4882a593Smuzhiyun EPSTAT(rx_pkts);
820*4882a593Smuzhiyun EPSTAT(rx_lkahds);
821*4882a593Smuzhiyun EPSTAT(rx_bundl);
822*4882a593Smuzhiyun EPSTAT(rx_bundle_lkahd);
823*4882a593Smuzhiyun EPSTAT(rx_bundle_from_hdr);
824*4882a593Smuzhiyun EPSTAT(rx_alloc_thresh_hit);
825*4882a593Smuzhiyun EPSTAT(rxalloc_thresh_byte);
826*4882a593Smuzhiyun #undef EPSTAT
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (len > buf_len)
829*4882a593Smuzhiyun len = buf_len;
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
832*4882a593Smuzhiyun kfree(buf);
833*4882a593Smuzhiyun return ret_cnt;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
ath6kl_endpoint_stats_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)836*4882a593Smuzhiyun static ssize_t ath6kl_endpoint_stats_write(struct file *file,
837*4882a593Smuzhiyun const char __user *user_buf,
838*4882a593Smuzhiyun size_t count, loff_t *ppos)
839*4882a593Smuzhiyun {
840*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
841*4882a593Smuzhiyun struct htc_target *target = ar->htc_target;
842*4882a593Smuzhiyun int ret, i;
843*4882a593Smuzhiyun u32 val;
844*4882a593Smuzhiyun struct htc_endpoint_stats *ep_st;
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun ret = kstrtou32_from_user(user_buf, count, 0, &val);
847*4882a593Smuzhiyun if (ret)
848*4882a593Smuzhiyun return ret;
849*4882a593Smuzhiyun if (val == 0) {
850*4882a593Smuzhiyun for (i = 0; i < ENDPOINT_MAX; i++) {
851*4882a593Smuzhiyun ep_st = &target->endpoint[i].ep_st;
852*4882a593Smuzhiyun memset(ep_st, 0, sizeof(*ep_st));
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun return count;
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun static const struct file_operations fops_endpoint_stats = {
860*4882a593Smuzhiyun .open = simple_open,
861*4882a593Smuzhiyun .read = ath6kl_endpoint_stats_read,
862*4882a593Smuzhiyun .write = ath6kl_endpoint_stats_write,
863*4882a593Smuzhiyun .owner = THIS_MODULE,
864*4882a593Smuzhiyun .llseek = default_llseek,
865*4882a593Smuzhiyun };
866*4882a593Smuzhiyun
ath6kl_get_num_reg(void)867*4882a593Smuzhiyun static unsigned long ath6kl_get_num_reg(void)
868*4882a593Smuzhiyun {
869*4882a593Smuzhiyun int i;
870*4882a593Smuzhiyun unsigned long n_reg = 0;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
873*4882a593Smuzhiyun n_reg = n_reg +
874*4882a593Smuzhiyun (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun return n_reg;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)879*4882a593Smuzhiyun static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun int i;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
884*4882a593Smuzhiyun if (reg_addr >= diag_reg[i].reg_start &&
885*4882a593Smuzhiyun reg_addr <= diag_reg[i].reg_end)
886*4882a593Smuzhiyun return true;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun return false;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun
ath6kl_regread_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)892*4882a593Smuzhiyun static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
893*4882a593Smuzhiyun size_t count, loff_t *ppos)
894*4882a593Smuzhiyun {
895*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
896*4882a593Smuzhiyun u8 buf[50];
897*4882a593Smuzhiyun unsigned int len = 0;
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun if (ar->debug.dbgfs_diag_reg)
900*4882a593Smuzhiyun len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
901*4882a593Smuzhiyun ar->debug.dbgfs_diag_reg);
902*4882a593Smuzhiyun else
903*4882a593Smuzhiyun len += scnprintf(buf + len, sizeof(buf) - len,
904*4882a593Smuzhiyun "All diag registers\n");
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
ath6kl_regread_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)909*4882a593Smuzhiyun static ssize_t ath6kl_regread_write(struct file *file,
910*4882a593Smuzhiyun const char __user *user_buf,
911*4882a593Smuzhiyun size_t count, loff_t *ppos)
912*4882a593Smuzhiyun {
913*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
914*4882a593Smuzhiyun unsigned long reg_addr;
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun if (kstrtoul_from_user(user_buf, count, 0, ®_addr))
917*4882a593Smuzhiyun return -EINVAL;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun if ((reg_addr % 4) != 0)
920*4882a593Smuzhiyun return -EINVAL;
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
923*4882a593Smuzhiyun return -EINVAL;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun ar->debug.dbgfs_diag_reg = reg_addr;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun return count;
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun static const struct file_operations fops_diag_reg_read = {
931*4882a593Smuzhiyun .read = ath6kl_regread_read,
932*4882a593Smuzhiyun .write = ath6kl_regread_write,
933*4882a593Smuzhiyun .open = simple_open,
934*4882a593Smuzhiyun .owner = THIS_MODULE,
935*4882a593Smuzhiyun .llseek = default_llseek,
936*4882a593Smuzhiyun };
937*4882a593Smuzhiyun
ath6kl_regdump_open(struct inode * inode,struct file * file)938*4882a593Smuzhiyun static int ath6kl_regdump_open(struct inode *inode, struct file *file)
939*4882a593Smuzhiyun {
940*4882a593Smuzhiyun struct ath6kl *ar = inode->i_private;
941*4882a593Smuzhiyun u8 *buf;
942*4882a593Smuzhiyun unsigned long int reg_len;
943*4882a593Smuzhiyun unsigned int len = 0, n_reg;
944*4882a593Smuzhiyun u32 addr;
945*4882a593Smuzhiyun __le32 reg_val;
946*4882a593Smuzhiyun int i, status;
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun /* Dump all the registers if no register is specified */
949*4882a593Smuzhiyun if (!ar->debug.dbgfs_diag_reg)
950*4882a593Smuzhiyun n_reg = ath6kl_get_num_reg();
951*4882a593Smuzhiyun else
952*4882a593Smuzhiyun n_reg = 1;
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
955*4882a593Smuzhiyun if (n_reg > 1)
956*4882a593Smuzhiyun reg_len += REGTYPE_STR_LEN;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun buf = vmalloc(reg_len);
959*4882a593Smuzhiyun if (!buf)
960*4882a593Smuzhiyun return -ENOMEM;
961*4882a593Smuzhiyun
962*4882a593Smuzhiyun if (n_reg == 1) {
963*4882a593Smuzhiyun addr = ar->debug.dbgfs_diag_reg;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun status = ath6kl_diag_read32(ar,
966*4882a593Smuzhiyun TARG_VTOP(ar->target_type, addr),
967*4882a593Smuzhiyun (u32 *)®_val);
968*4882a593Smuzhiyun if (status)
969*4882a593Smuzhiyun goto fail_reg_read;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun len += scnprintf(buf + len, reg_len - len,
972*4882a593Smuzhiyun "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
973*4882a593Smuzhiyun goto done;
974*4882a593Smuzhiyun }
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
977*4882a593Smuzhiyun len += scnprintf(buf + len, reg_len - len,
978*4882a593Smuzhiyun "%s\n", diag_reg[i].reg_info);
979*4882a593Smuzhiyun for (addr = diag_reg[i].reg_start;
980*4882a593Smuzhiyun addr <= diag_reg[i].reg_end; addr += 4) {
981*4882a593Smuzhiyun status = ath6kl_diag_read32(ar,
982*4882a593Smuzhiyun TARG_VTOP(ar->target_type, addr),
983*4882a593Smuzhiyun (u32 *)®_val);
984*4882a593Smuzhiyun if (status)
985*4882a593Smuzhiyun goto fail_reg_read;
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun len += scnprintf(buf + len, reg_len - len,
988*4882a593Smuzhiyun "0x%06x 0x%08x\n",
989*4882a593Smuzhiyun addr, le32_to_cpu(reg_val));
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun done:
994*4882a593Smuzhiyun file->private_data = buf;
995*4882a593Smuzhiyun return 0;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun fail_reg_read:
998*4882a593Smuzhiyun ath6kl_warn("Unable to read memory:%u\n", addr);
999*4882a593Smuzhiyun vfree(buf);
1000*4882a593Smuzhiyun return -EIO;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun
ath6kl_regdump_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1003*4882a593Smuzhiyun static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
1004*4882a593Smuzhiyun size_t count, loff_t *ppos)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun u8 *buf = file->private_data;
1007*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun
ath6kl_regdump_release(struct inode * inode,struct file * file)1010*4882a593Smuzhiyun static int ath6kl_regdump_release(struct inode *inode, struct file *file)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun vfree(file->private_data);
1013*4882a593Smuzhiyun return 0;
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun static const struct file_operations fops_reg_dump = {
1017*4882a593Smuzhiyun .open = ath6kl_regdump_open,
1018*4882a593Smuzhiyun .read = ath6kl_regdump_read,
1019*4882a593Smuzhiyun .release = ath6kl_regdump_release,
1020*4882a593Smuzhiyun .owner = THIS_MODULE,
1021*4882a593Smuzhiyun .llseek = default_llseek,
1022*4882a593Smuzhiyun };
1023*4882a593Smuzhiyun
ath6kl_lrssi_roam_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1024*4882a593Smuzhiyun static ssize_t ath6kl_lrssi_roam_write(struct file *file,
1025*4882a593Smuzhiyun const char __user *user_buf,
1026*4882a593Smuzhiyun size_t count, loff_t *ppos)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1029*4882a593Smuzhiyun unsigned long lrssi_roam_threshold;
1030*4882a593Smuzhiyun int ret;
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold))
1033*4882a593Smuzhiyun return -EINVAL;
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun ar->lrssi_roam_threshold = lrssi_roam_threshold;
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun ret = ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun if (ret)
1040*4882a593Smuzhiyun return ret;
1041*4882a593Smuzhiyun return count;
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun
ath6kl_lrssi_roam_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1044*4882a593Smuzhiyun static ssize_t ath6kl_lrssi_roam_read(struct file *file,
1045*4882a593Smuzhiyun char __user *user_buf,
1046*4882a593Smuzhiyun size_t count, loff_t *ppos)
1047*4882a593Smuzhiyun {
1048*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1049*4882a593Smuzhiyun char buf[32];
1050*4882a593Smuzhiyun unsigned int len;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun static const struct file_operations fops_lrssi_roam_threshold = {
1058*4882a593Smuzhiyun .read = ath6kl_lrssi_roam_read,
1059*4882a593Smuzhiyun .write = ath6kl_lrssi_roam_write,
1060*4882a593Smuzhiyun .open = simple_open,
1061*4882a593Smuzhiyun .owner = THIS_MODULE,
1062*4882a593Smuzhiyun .llseek = default_llseek,
1063*4882a593Smuzhiyun };
1064*4882a593Smuzhiyun
ath6kl_regwrite_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1065*4882a593Smuzhiyun static ssize_t ath6kl_regwrite_read(struct file *file,
1066*4882a593Smuzhiyun char __user *user_buf,
1067*4882a593Smuzhiyun size_t count, loff_t *ppos)
1068*4882a593Smuzhiyun {
1069*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1070*4882a593Smuzhiyun u8 buf[32];
1071*4882a593Smuzhiyun unsigned int len = 0;
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
1074*4882a593Smuzhiyun ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun
ath6kl_regwrite_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1079*4882a593Smuzhiyun static ssize_t ath6kl_regwrite_write(struct file *file,
1080*4882a593Smuzhiyun const char __user *user_buf,
1081*4882a593Smuzhiyun size_t count, loff_t *ppos)
1082*4882a593Smuzhiyun {
1083*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1084*4882a593Smuzhiyun char buf[32];
1085*4882a593Smuzhiyun char *sptr, *token;
1086*4882a593Smuzhiyun unsigned int len = 0;
1087*4882a593Smuzhiyun u32 reg_addr, reg_val;
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1090*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1091*4882a593Smuzhiyun return -EFAULT;
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun buf[len] = '\0';
1094*4882a593Smuzhiyun sptr = buf;
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun token = strsep(&sptr, "=");
1097*4882a593Smuzhiyun if (!token)
1098*4882a593Smuzhiyun return -EINVAL;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun if (kstrtou32(token, 0, ®_addr))
1101*4882a593Smuzhiyun return -EINVAL;
1102*4882a593Smuzhiyun
1103*4882a593Smuzhiyun if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
1104*4882a593Smuzhiyun return -EINVAL;
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun if (kstrtou32(sptr, 0, ®_val))
1107*4882a593Smuzhiyun return -EINVAL;
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun ar->debug.diag_reg_addr_wr = reg_addr;
1110*4882a593Smuzhiyun ar->debug.diag_reg_val_wr = reg_val;
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
1113*4882a593Smuzhiyun cpu_to_le32(ar->debug.diag_reg_val_wr)))
1114*4882a593Smuzhiyun return -EIO;
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun return count;
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun static const struct file_operations fops_diag_reg_write = {
1120*4882a593Smuzhiyun .read = ath6kl_regwrite_read,
1121*4882a593Smuzhiyun .write = ath6kl_regwrite_write,
1122*4882a593Smuzhiyun .open = simple_open,
1123*4882a593Smuzhiyun .owner = THIS_MODULE,
1124*4882a593Smuzhiyun .llseek = default_llseek,
1125*4882a593Smuzhiyun };
1126*4882a593Smuzhiyun
ath6kl_debug_roam_tbl_event(struct ath6kl * ar,const void * buf,size_t len)1127*4882a593Smuzhiyun int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
1128*4882a593Smuzhiyun size_t len)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun const struct wmi_target_roam_tbl *tbl;
1131*4882a593Smuzhiyun u16 num_entries;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun if (len < sizeof(*tbl))
1134*4882a593Smuzhiyun return -EINVAL;
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun tbl = (const struct wmi_target_roam_tbl *) buf;
1137*4882a593Smuzhiyun num_entries = le16_to_cpu(tbl->num_entries);
1138*4882a593Smuzhiyun if (struct_size(tbl, info, num_entries) > len)
1139*4882a593Smuzhiyun return -EINVAL;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun if (ar->debug.roam_tbl == NULL ||
1142*4882a593Smuzhiyun ar->debug.roam_tbl_len < (unsigned int) len) {
1143*4882a593Smuzhiyun kfree(ar->debug.roam_tbl);
1144*4882a593Smuzhiyun ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
1145*4882a593Smuzhiyun if (ar->debug.roam_tbl == NULL)
1146*4882a593Smuzhiyun return -ENOMEM;
1147*4882a593Smuzhiyun }
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun memcpy(ar->debug.roam_tbl, buf, len);
1150*4882a593Smuzhiyun ar->debug.roam_tbl_len = len;
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
1153*4882a593Smuzhiyun clear_bit(ROAM_TBL_PEND, &ar->flag);
1154*4882a593Smuzhiyun wake_up(&ar->event_wq);
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun return 0;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
ath6kl_roam_table_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1160*4882a593Smuzhiyun static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf,
1161*4882a593Smuzhiyun size_t count, loff_t *ppos)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1164*4882a593Smuzhiyun int ret;
1165*4882a593Smuzhiyun long left;
1166*4882a593Smuzhiyun struct wmi_target_roam_tbl *tbl;
1167*4882a593Smuzhiyun u16 num_entries, i;
1168*4882a593Smuzhiyun char *buf;
1169*4882a593Smuzhiyun unsigned int len, buf_len;
1170*4882a593Smuzhiyun ssize_t ret_cnt;
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun if (down_interruptible(&ar->sem))
1173*4882a593Smuzhiyun return -EBUSY;
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun set_bit(ROAM_TBL_PEND, &ar->flag);
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi);
1178*4882a593Smuzhiyun if (ret) {
1179*4882a593Smuzhiyun up(&ar->sem);
1180*4882a593Smuzhiyun return ret;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun left = wait_event_interruptible_timeout(
1184*4882a593Smuzhiyun ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT);
1185*4882a593Smuzhiyun up(&ar->sem);
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun if (left <= 0)
1188*4882a593Smuzhiyun return -ETIMEDOUT;
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun if (ar->debug.roam_tbl == NULL)
1191*4882a593Smuzhiyun return -ENOMEM;
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl;
1194*4882a593Smuzhiyun num_entries = le16_to_cpu(tbl->num_entries);
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun buf_len = 100 + num_entries * 100;
1197*4882a593Smuzhiyun buf = kzalloc(buf_len, GFP_KERNEL);
1198*4882a593Smuzhiyun if (buf == NULL)
1199*4882a593Smuzhiyun return -ENOMEM;
1200*4882a593Smuzhiyun len = 0;
1201*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len,
1202*4882a593Smuzhiyun "roam_mode=%u\n\n"
1203*4882a593Smuzhiyun "# roam_util bssid rssi rssidt last_rssi util bias\n",
1204*4882a593Smuzhiyun le16_to_cpu(tbl->roam_mode));
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun for (i = 0; i < num_entries; i++) {
1207*4882a593Smuzhiyun struct wmi_bss_roam_info *info = &tbl->info[i];
1208*4882a593Smuzhiyun len += scnprintf(buf + len, buf_len - len,
1209*4882a593Smuzhiyun "%d %pM %d %d %d %d %d\n",
1210*4882a593Smuzhiyun a_sle32_to_cpu(info->roam_util), info->bssid,
1211*4882a593Smuzhiyun info->rssi, info->rssidt, info->last_rssi,
1212*4882a593Smuzhiyun info->util, info->bias);
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun if (len > buf_len)
1216*4882a593Smuzhiyun len = buf_len;
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun kfree(buf);
1221*4882a593Smuzhiyun return ret_cnt;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun static const struct file_operations fops_roam_table = {
1225*4882a593Smuzhiyun .read = ath6kl_roam_table_read,
1226*4882a593Smuzhiyun .open = simple_open,
1227*4882a593Smuzhiyun .owner = THIS_MODULE,
1228*4882a593Smuzhiyun .llseek = default_llseek,
1229*4882a593Smuzhiyun };
1230*4882a593Smuzhiyun
ath6kl_force_roam_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1231*4882a593Smuzhiyun static ssize_t ath6kl_force_roam_write(struct file *file,
1232*4882a593Smuzhiyun const char __user *user_buf,
1233*4882a593Smuzhiyun size_t count, loff_t *ppos)
1234*4882a593Smuzhiyun {
1235*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1236*4882a593Smuzhiyun int ret;
1237*4882a593Smuzhiyun char buf[20];
1238*4882a593Smuzhiyun size_t len;
1239*4882a593Smuzhiyun u8 bssid[ETH_ALEN];
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1242*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1243*4882a593Smuzhiyun return -EFAULT;
1244*4882a593Smuzhiyun buf[len] = '\0';
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun if (!mac_pton(buf, bssid))
1247*4882a593Smuzhiyun return -EINVAL;
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid);
1250*4882a593Smuzhiyun if (ret)
1251*4882a593Smuzhiyun return ret;
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun return count;
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun static const struct file_operations fops_force_roam = {
1257*4882a593Smuzhiyun .write = ath6kl_force_roam_write,
1258*4882a593Smuzhiyun .open = simple_open,
1259*4882a593Smuzhiyun .owner = THIS_MODULE,
1260*4882a593Smuzhiyun .llseek = default_llseek,
1261*4882a593Smuzhiyun };
1262*4882a593Smuzhiyun
ath6kl_roam_mode_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1263*4882a593Smuzhiyun static ssize_t ath6kl_roam_mode_write(struct file *file,
1264*4882a593Smuzhiyun const char __user *user_buf,
1265*4882a593Smuzhiyun size_t count, loff_t *ppos)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1268*4882a593Smuzhiyun int ret;
1269*4882a593Smuzhiyun char buf[20];
1270*4882a593Smuzhiyun size_t len;
1271*4882a593Smuzhiyun enum wmi_roam_mode mode;
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1274*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1275*4882a593Smuzhiyun return -EFAULT;
1276*4882a593Smuzhiyun buf[len] = '\0';
1277*4882a593Smuzhiyun if (len > 0 && buf[len - 1] == '\n')
1278*4882a593Smuzhiyun buf[len - 1] = '\0';
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun if (strcasecmp(buf, "default") == 0)
1281*4882a593Smuzhiyun mode = WMI_DEFAULT_ROAM_MODE;
1282*4882a593Smuzhiyun else if (strcasecmp(buf, "bssbias") == 0)
1283*4882a593Smuzhiyun mode = WMI_HOST_BIAS_ROAM_MODE;
1284*4882a593Smuzhiyun else if (strcasecmp(buf, "lock") == 0)
1285*4882a593Smuzhiyun mode = WMI_LOCK_BSS_MODE;
1286*4882a593Smuzhiyun else
1287*4882a593Smuzhiyun return -EINVAL;
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode);
1290*4882a593Smuzhiyun if (ret)
1291*4882a593Smuzhiyun return ret;
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun return count;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
1296*4882a593Smuzhiyun static const struct file_operations fops_roam_mode = {
1297*4882a593Smuzhiyun .write = ath6kl_roam_mode_write,
1298*4882a593Smuzhiyun .open = simple_open,
1299*4882a593Smuzhiyun .owner = THIS_MODULE,
1300*4882a593Smuzhiyun .llseek = default_llseek,
1301*4882a593Smuzhiyun };
1302*4882a593Smuzhiyun
ath6kl_debug_set_keepalive(struct ath6kl * ar,u8 keepalive)1303*4882a593Smuzhiyun void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive)
1304*4882a593Smuzhiyun {
1305*4882a593Smuzhiyun ar->debug.keepalive = keepalive;
1306*4882a593Smuzhiyun }
1307*4882a593Smuzhiyun
ath6kl_keepalive_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1308*4882a593Smuzhiyun static ssize_t ath6kl_keepalive_read(struct file *file, char __user *user_buf,
1309*4882a593Smuzhiyun size_t count, loff_t *ppos)
1310*4882a593Smuzhiyun {
1311*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1312*4882a593Smuzhiyun char buf[16];
1313*4882a593Smuzhiyun int len;
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.keepalive);
1316*4882a593Smuzhiyun
1317*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun
ath6kl_keepalive_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1320*4882a593Smuzhiyun static ssize_t ath6kl_keepalive_write(struct file *file,
1321*4882a593Smuzhiyun const char __user *user_buf,
1322*4882a593Smuzhiyun size_t count, loff_t *ppos)
1323*4882a593Smuzhiyun {
1324*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1325*4882a593Smuzhiyun int ret;
1326*4882a593Smuzhiyun u8 val;
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun ret = kstrtou8_from_user(user_buf, count, 0, &val);
1329*4882a593Smuzhiyun if (ret)
1330*4882a593Smuzhiyun return ret;
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, 0, val);
1333*4882a593Smuzhiyun if (ret)
1334*4882a593Smuzhiyun return ret;
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun return count;
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun static const struct file_operations fops_keepalive = {
1340*4882a593Smuzhiyun .open = simple_open,
1341*4882a593Smuzhiyun .read = ath6kl_keepalive_read,
1342*4882a593Smuzhiyun .write = ath6kl_keepalive_write,
1343*4882a593Smuzhiyun .owner = THIS_MODULE,
1344*4882a593Smuzhiyun .llseek = default_llseek,
1345*4882a593Smuzhiyun };
1346*4882a593Smuzhiyun
ath6kl_debug_set_disconnect_timeout(struct ath6kl * ar,u8 timeout)1347*4882a593Smuzhiyun void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout)
1348*4882a593Smuzhiyun {
1349*4882a593Smuzhiyun ar->debug.disc_timeout = timeout;
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun
ath6kl_disconnect_timeout_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1352*4882a593Smuzhiyun static ssize_t ath6kl_disconnect_timeout_read(struct file *file,
1353*4882a593Smuzhiyun char __user *user_buf,
1354*4882a593Smuzhiyun size_t count, loff_t *ppos)
1355*4882a593Smuzhiyun {
1356*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1357*4882a593Smuzhiyun char buf[16];
1358*4882a593Smuzhiyun int len;
1359*4882a593Smuzhiyun
1360*4882a593Smuzhiyun len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.disc_timeout);
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun
ath6kl_disconnect_timeout_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1365*4882a593Smuzhiyun static ssize_t ath6kl_disconnect_timeout_write(struct file *file,
1366*4882a593Smuzhiyun const char __user *user_buf,
1367*4882a593Smuzhiyun size_t count, loff_t *ppos)
1368*4882a593Smuzhiyun {
1369*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1370*4882a593Smuzhiyun int ret;
1371*4882a593Smuzhiyun u8 val;
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun ret = kstrtou8_from_user(user_buf, count, 0, &val);
1374*4882a593Smuzhiyun if (ret)
1375*4882a593Smuzhiyun return ret;
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, 0, val);
1378*4882a593Smuzhiyun if (ret)
1379*4882a593Smuzhiyun return ret;
1380*4882a593Smuzhiyun
1381*4882a593Smuzhiyun return count;
1382*4882a593Smuzhiyun }
1383*4882a593Smuzhiyun
1384*4882a593Smuzhiyun static const struct file_operations fops_disconnect_timeout = {
1385*4882a593Smuzhiyun .open = simple_open,
1386*4882a593Smuzhiyun .read = ath6kl_disconnect_timeout_read,
1387*4882a593Smuzhiyun .write = ath6kl_disconnect_timeout_write,
1388*4882a593Smuzhiyun .owner = THIS_MODULE,
1389*4882a593Smuzhiyun .llseek = default_llseek,
1390*4882a593Smuzhiyun };
1391*4882a593Smuzhiyun
ath6kl_create_qos_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1392*4882a593Smuzhiyun static ssize_t ath6kl_create_qos_write(struct file *file,
1393*4882a593Smuzhiyun const char __user *user_buf,
1394*4882a593Smuzhiyun size_t count, loff_t *ppos)
1395*4882a593Smuzhiyun {
1396*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1397*4882a593Smuzhiyun struct ath6kl_vif *vif;
1398*4882a593Smuzhiyun char buf[200];
1399*4882a593Smuzhiyun ssize_t len;
1400*4882a593Smuzhiyun char *sptr, *token;
1401*4882a593Smuzhiyun struct wmi_create_pstream_cmd pstream;
1402*4882a593Smuzhiyun u32 val32;
1403*4882a593Smuzhiyun u16 val16;
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun vif = ath6kl_vif_first(ar);
1406*4882a593Smuzhiyun if (!vif)
1407*4882a593Smuzhiyun return -EIO;
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1410*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1411*4882a593Smuzhiyun return -EFAULT;
1412*4882a593Smuzhiyun buf[len] = '\0';
1413*4882a593Smuzhiyun sptr = buf;
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun token = strsep(&sptr, " ");
1416*4882a593Smuzhiyun if (!token)
1417*4882a593Smuzhiyun return -EINVAL;
1418*4882a593Smuzhiyun if (kstrtou8(token, 0, &pstream.user_pri))
1419*4882a593Smuzhiyun return -EINVAL;
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun token = strsep(&sptr, " ");
1422*4882a593Smuzhiyun if (!token)
1423*4882a593Smuzhiyun return -EINVAL;
1424*4882a593Smuzhiyun if (kstrtou8(token, 0, &pstream.traffic_direc))
1425*4882a593Smuzhiyun return -EINVAL;
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun token = strsep(&sptr, " ");
1428*4882a593Smuzhiyun if (!token)
1429*4882a593Smuzhiyun return -EINVAL;
1430*4882a593Smuzhiyun if (kstrtou8(token, 0, &pstream.traffic_class))
1431*4882a593Smuzhiyun return -EINVAL;
1432*4882a593Smuzhiyun
1433*4882a593Smuzhiyun token = strsep(&sptr, " ");
1434*4882a593Smuzhiyun if (!token)
1435*4882a593Smuzhiyun return -EINVAL;
1436*4882a593Smuzhiyun if (kstrtou8(token, 0, &pstream.traffic_type))
1437*4882a593Smuzhiyun return -EINVAL;
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun token = strsep(&sptr, " ");
1440*4882a593Smuzhiyun if (!token)
1441*4882a593Smuzhiyun return -EINVAL;
1442*4882a593Smuzhiyun if (kstrtou8(token, 0, &pstream.voice_psc_cap))
1443*4882a593Smuzhiyun return -EINVAL;
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun token = strsep(&sptr, " ");
1446*4882a593Smuzhiyun if (!token)
1447*4882a593Smuzhiyun return -EINVAL;
1448*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1449*4882a593Smuzhiyun return -EINVAL;
1450*4882a593Smuzhiyun pstream.min_service_int = cpu_to_le32(val32);
1451*4882a593Smuzhiyun
1452*4882a593Smuzhiyun token = strsep(&sptr, " ");
1453*4882a593Smuzhiyun if (!token)
1454*4882a593Smuzhiyun return -EINVAL;
1455*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1456*4882a593Smuzhiyun return -EINVAL;
1457*4882a593Smuzhiyun pstream.max_service_int = cpu_to_le32(val32);
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun token = strsep(&sptr, " ");
1460*4882a593Smuzhiyun if (!token)
1461*4882a593Smuzhiyun return -EINVAL;
1462*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1463*4882a593Smuzhiyun return -EINVAL;
1464*4882a593Smuzhiyun pstream.inactivity_int = cpu_to_le32(val32);
1465*4882a593Smuzhiyun
1466*4882a593Smuzhiyun token = strsep(&sptr, " ");
1467*4882a593Smuzhiyun if (!token)
1468*4882a593Smuzhiyun return -EINVAL;
1469*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1470*4882a593Smuzhiyun return -EINVAL;
1471*4882a593Smuzhiyun pstream.suspension_int = cpu_to_le32(val32);
1472*4882a593Smuzhiyun
1473*4882a593Smuzhiyun token = strsep(&sptr, " ");
1474*4882a593Smuzhiyun if (!token)
1475*4882a593Smuzhiyun return -EINVAL;
1476*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1477*4882a593Smuzhiyun return -EINVAL;
1478*4882a593Smuzhiyun pstream.service_start_time = cpu_to_le32(val32);
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun token = strsep(&sptr, " ");
1481*4882a593Smuzhiyun if (!token)
1482*4882a593Smuzhiyun return -EINVAL;
1483*4882a593Smuzhiyun if (kstrtou8(token, 0, &pstream.tsid))
1484*4882a593Smuzhiyun return -EINVAL;
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun token = strsep(&sptr, " ");
1487*4882a593Smuzhiyun if (!token)
1488*4882a593Smuzhiyun return -EINVAL;
1489*4882a593Smuzhiyun if (kstrtou16(token, 0, &val16))
1490*4882a593Smuzhiyun return -EINVAL;
1491*4882a593Smuzhiyun pstream.nominal_msdu = cpu_to_le16(val16);
1492*4882a593Smuzhiyun
1493*4882a593Smuzhiyun token = strsep(&sptr, " ");
1494*4882a593Smuzhiyun if (!token)
1495*4882a593Smuzhiyun return -EINVAL;
1496*4882a593Smuzhiyun if (kstrtou16(token, 0, &val16))
1497*4882a593Smuzhiyun return -EINVAL;
1498*4882a593Smuzhiyun pstream.max_msdu = cpu_to_le16(val16);
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun token = strsep(&sptr, " ");
1501*4882a593Smuzhiyun if (!token)
1502*4882a593Smuzhiyun return -EINVAL;
1503*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1504*4882a593Smuzhiyun return -EINVAL;
1505*4882a593Smuzhiyun pstream.min_data_rate = cpu_to_le32(val32);
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun token = strsep(&sptr, " ");
1508*4882a593Smuzhiyun if (!token)
1509*4882a593Smuzhiyun return -EINVAL;
1510*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1511*4882a593Smuzhiyun return -EINVAL;
1512*4882a593Smuzhiyun pstream.mean_data_rate = cpu_to_le32(val32);
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun token = strsep(&sptr, " ");
1515*4882a593Smuzhiyun if (!token)
1516*4882a593Smuzhiyun return -EINVAL;
1517*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1518*4882a593Smuzhiyun return -EINVAL;
1519*4882a593Smuzhiyun pstream.peak_data_rate = cpu_to_le32(val32);
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun token = strsep(&sptr, " ");
1522*4882a593Smuzhiyun if (!token)
1523*4882a593Smuzhiyun return -EINVAL;
1524*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1525*4882a593Smuzhiyun return -EINVAL;
1526*4882a593Smuzhiyun pstream.max_burst_size = cpu_to_le32(val32);
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun token = strsep(&sptr, " ");
1529*4882a593Smuzhiyun if (!token)
1530*4882a593Smuzhiyun return -EINVAL;
1531*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1532*4882a593Smuzhiyun return -EINVAL;
1533*4882a593Smuzhiyun pstream.delay_bound = cpu_to_le32(val32);
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun token = strsep(&sptr, " ");
1536*4882a593Smuzhiyun if (!token)
1537*4882a593Smuzhiyun return -EINVAL;
1538*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1539*4882a593Smuzhiyun return -EINVAL;
1540*4882a593Smuzhiyun pstream.min_phy_rate = cpu_to_le32(val32);
1541*4882a593Smuzhiyun
1542*4882a593Smuzhiyun token = strsep(&sptr, " ");
1543*4882a593Smuzhiyun if (!token)
1544*4882a593Smuzhiyun return -EINVAL;
1545*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1546*4882a593Smuzhiyun return -EINVAL;
1547*4882a593Smuzhiyun pstream.sba = cpu_to_le32(val32);
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun token = strsep(&sptr, " ");
1550*4882a593Smuzhiyun if (!token)
1551*4882a593Smuzhiyun return -EINVAL;
1552*4882a593Smuzhiyun if (kstrtou32(token, 0, &val32))
1553*4882a593Smuzhiyun return -EINVAL;
1554*4882a593Smuzhiyun pstream.medium_time = cpu_to_le32(val32);
1555*4882a593Smuzhiyun
1556*4882a593Smuzhiyun pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000;
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream);
1559*4882a593Smuzhiyun
1560*4882a593Smuzhiyun return count;
1561*4882a593Smuzhiyun }
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun static const struct file_operations fops_create_qos = {
1564*4882a593Smuzhiyun .write = ath6kl_create_qos_write,
1565*4882a593Smuzhiyun .open = simple_open,
1566*4882a593Smuzhiyun .owner = THIS_MODULE,
1567*4882a593Smuzhiyun .llseek = default_llseek,
1568*4882a593Smuzhiyun };
1569*4882a593Smuzhiyun
ath6kl_delete_qos_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1570*4882a593Smuzhiyun static ssize_t ath6kl_delete_qos_write(struct file *file,
1571*4882a593Smuzhiyun const char __user *user_buf,
1572*4882a593Smuzhiyun size_t count, loff_t *ppos)
1573*4882a593Smuzhiyun {
1574*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1575*4882a593Smuzhiyun struct ath6kl_vif *vif;
1576*4882a593Smuzhiyun char buf[100];
1577*4882a593Smuzhiyun ssize_t len;
1578*4882a593Smuzhiyun char *sptr, *token;
1579*4882a593Smuzhiyun u8 traffic_class;
1580*4882a593Smuzhiyun u8 tsid;
1581*4882a593Smuzhiyun
1582*4882a593Smuzhiyun vif = ath6kl_vif_first(ar);
1583*4882a593Smuzhiyun if (!vif)
1584*4882a593Smuzhiyun return -EIO;
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1587*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1588*4882a593Smuzhiyun return -EFAULT;
1589*4882a593Smuzhiyun buf[len] = '\0';
1590*4882a593Smuzhiyun sptr = buf;
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyun token = strsep(&sptr, " ");
1593*4882a593Smuzhiyun if (!token)
1594*4882a593Smuzhiyun return -EINVAL;
1595*4882a593Smuzhiyun if (kstrtou8(token, 0, &traffic_class))
1596*4882a593Smuzhiyun return -EINVAL;
1597*4882a593Smuzhiyun
1598*4882a593Smuzhiyun token = strsep(&sptr, " ");
1599*4882a593Smuzhiyun if (!token)
1600*4882a593Smuzhiyun return -EINVAL;
1601*4882a593Smuzhiyun if (kstrtou8(token, 0, &tsid))
1602*4882a593Smuzhiyun return -EINVAL;
1603*4882a593Smuzhiyun
1604*4882a593Smuzhiyun ath6kl_wmi_delete_pstream_cmd(ar->wmi, vif->fw_vif_idx,
1605*4882a593Smuzhiyun traffic_class, tsid);
1606*4882a593Smuzhiyun
1607*4882a593Smuzhiyun return count;
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun static const struct file_operations fops_delete_qos = {
1611*4882a593Smuzhiyun .write = ath6kl_delete_qos_write,
1612*4882a593Smuzhiyun .open = simple_open,
1613*4882a593Smuzhiyun .owner = THIS_MODULE,
1614*4882a593Smuzhiyun .llseek = default_llseek,
1615*4882a593Smuzhiyun };
1616*4882a593Smuzhiyun
ath6kl_bgscan_int_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1617*4882a593Smuzhiyun static ssize_t ath6kl_bgscan_int_write(struct file *file,
1618*4882a593Smuzhiyun const char __user *user_buf,
1619*4882a593Smuzhiyun size_t count, loff_t *ppos)
1620*4882a593Smuzhiyun {
1621*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1622*4882a593Smuzhiyun struct ath6kl_vif *vif;
1623*4882a593Smuzhiyun u16 bgscan_int;
1624*4882a593Smuzhiyun char buf[32];
1625*4882a593Smuzhiyun ssize_t len;
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun vif = ath6kl_vif_first(ar);
1628*4882a593Smuzhiyun if (!vif)
1629*4882a593Smuzhiyun return -EIO;
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1632*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1633*4882a593Smuzhiyun return -EFAULT;
1634*4882a593Smuzhiyun
1635*4882a593Smuzhiyun buf[len] = '\0';
1636*4882a593Smuzhiyun if (kstrtou16(buf, 0, &bgscan_int))
1637*4882a593Smuzhiyun return -EINVAL;
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun if (bgscan_int == 0)
1640*4882a593Smuzhiyun bgscan_int = 0xffff;
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun vif->bg_scan_period = bgscan_int;
1643*4882a593Smuzhiyun
1644*4882a593Smuzhiyun ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
1645*4882a593Smuzhiyun 0, 0, 0);
1646*4882a593Smuzhiyun
1647*4882a593Smuzhiyun return count;
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun static const struct file_operations fops_bgscan_int = {
1651*4882a593Smuzhiyun .write = ath6kl_bgscan_int_write,
1652*4882a593Smuzhiyun .open = simple_open,
1653*4882a593Smuzhiyun .owner = THIS_MODULE,
1654*4882a593Smuzhiyun .llseek = default_llseek,
1655*4882a593Smuzhiyun };
1656*4882a593Smuzhiyun
ath6kl_listen_int_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1657*4882a593Smuzhiyun static ssize_t ath6kl_listen_int_write(struct file *file,
1658*4882a593Smuzhiyun const char __user *user_buf,
1659*4882a593Smuzhiyun size_t count, loff_t *ppos)
1660*4882a593Smuzhiyun {
1661*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1662*4882a593Smuzhiyun struct ath6kl_vif *vif;
1663*4882a593Smuzhiyun u16 listen_interval;
1664*4882a593Smuzhiyun char buf[32];
1665*4882a593Smuzhiyun ssize_t len;
1666*4882a593Smuzhiyun
1667*4882a593Smuzhiyun vif = ath6kl_vif_first(ar);
1668*4882a593Smuzhiyun if (!vif)
1669*4882a593Smuzhiyun return -EIO;
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1672*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1673*4882a593Smuzhiyun return -EFAULT;
1674*4882a593Smuzhiyun
1675*4882a593Smuzhiyun buf[len] = '\0';
1676*4882a593Smuzhiyun if (kstrtou16(buf, 0, &listen_interval))
1677*4882a593Smuzhiyun return -EINVAL;
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun if ((listen_interval < 15) || (listen_interval > 3000))
1680*4882a593Smuzhiyun return -EINVAL;
1681*4882a593Smuzhiyun
1682*4882a593Smuzhiyun vif->listen_intvl_t = listen_interval;
1683*4882a593Smuzhiyun ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
1684*4882a593Smuzhiyun vif->listen_intvl_t, 0);
1685*4882a593Smuzhiyun
1686*4882a593Smuzhiyun return count;
1687*4882a593Smuzhiyun }
1688*4882a593Smuzhiyun
ath6kl_listen_int_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1689*4882a593Smuzhiyun static ssize_t ath6kl_listen_int_read(struct file *file,
1690*4882a593Smuzhiyun char __user *user_buf,
1691*4882a593Smuzhiyun size_t count, loff_t *ppos)
1692*4882a593Smuzhiyun {
1693*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1694*4882a593Smuzhiyun struct ath6kl_vif *vif;
1695*4882a593Smuzhiyun char buf[32];
1696*4882a593Smuzhiyun int len;
1697*4882a593Smuzhiyun
1698*4882a593Smuzhiyun vif = ath6kl_vif_first(ar);
1699*4882a593Smuzhiyun if (!vif)
1700*4882a593Smuzhiyun return -EIO;
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t);
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun static const struct file_operations fops_listen_int = {
1708*4882a593Smuzhiyun .read = ath6kl_listen_int_read,
1709*4882a593Smuzhiyun .write = ath6kl_listen_int_write,
1710*4882a593Smuzhiyun .open = simple_open,
1711*4882a593Smuzhiyun .owner = THIS_MODULE,
1712*4882a593Smuzhiyun .llseek = default_llseek,
1713*4882a593Smuzhiyun };
1714*4882a593Smuzhiyun
ath6kl_power_params_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1715*4882a593Smuzhiyun static ssize_t ath6kl_power_params_write(struct file *file,
1716*4882a593Smuzhiyun const char __user *user_buf,
1717*4882a593Smuzhiyun size_t count, loff_t *ppos)
1718*4882a593Smuzhiyun {
1719*4882a593Smuzhiyun struct ath6kl *ar = file->private_data;
1720*4882a593Smuzhiyun u8 buf[100];
1721*4882a593Smuzhiyun unsigned int len = 0;
1722*4882a593Smuzhiyun char *sptr, *token;
1723*4882a593Smuzhiyun u16 idle_period, ps_poll_num, dtim,
1724*4882a593Smuzhiyun tx_wakeup, num_tx;
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun len = min(count, sizeof(buf) - 1);
1727*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, len))
1728*4882a593Smuzhiyun return -EFAULT;
1729*4882a593Smuzhiyun buf[len] = '\0';
1730*4882a593Smuzhiyun sptr = buf;
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun token = strsep(&sptr, " ");
1733*4882a593Smuzhiyun if (!token)
1734*4882a593Smuzhiyun return -EINVAL;
1735*4882a593Smuzhiyun if (kstrtou16(token, 0, &idle_period))
1736*4882a593Smuzhiyun return -EINVAL;
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun token = strsep(&sptr, " ");
1739*4882a593Smuzhiyun if (!token)
1740*4882a593Smuzhiyun return -EINVAL;
1741*4882a593Smuzhiyun if (kstrtou16(token, 0, &ps_poll_num))
1742*4882a593Smuzhiyun return -EINVAL;
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun token = strsep(&sptr, " ");
1745*4882a593Smuzhiyun if (!token)
1746*4882a593Smuzhiyun return -EINVAL;
1747*4882a593Smuzhiyun if (kstrtou16(token, 0, &dtim))
1748*4882a593Smuzhiyun return -EINVAL;
1749*4882a593Smuzhiyun
1750*4882a593Smuzhiyun token = strsep(&sptr, " ");
1751*4882a593Smuzhiyun if (!token)
1752*4882a593Smuzhiyun return -EINVAL;
1753*4882a593Smuzhiyun if (kstrtou16(token, 0, &tx_wakeup))
1754*4882a593Smuzhiyun return -EINVAL;
1755*4882a593Smuzhiyun
1756*4882a593Smuzhiyun token = strsep(&sptr, " ");
1757*4882a593Smuzhiyun if (!token)
1758*4882a593Smuzhiyun return -EINVAL;
1759*4882a593Smuzhiyun if (kstrtou16(token, 0, &num_tx))
1760*4882a593Smuzhiyun return -EINVAL;
1761*4882a593Smuzhiyun
1762*4882a593Smuzhiyun ath6kl_wmi_pmparams_cmd(ar->wmi, 0, idle_period, ps_poll_num,
1763*4882a593Smuzhiyun dtim, tx_wakeup, num_tx, 0);
1764*4882a593Smuzhiyun
1765*4882a593Smuzhiyun return count;
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun
1768*4882a593Smuzhiyun static const struct file_operations fops_power_params = {
1769*4882a593Smuzhiyun .write = ath6kl_power_params_write,
1770*4882a593Smuzhiyun .open = simple_open,
1771*4882a593Smuzhiyun .owner = THIS_MODULE,
1772*4882a593Smuzhiyun .llseek = default_llseek,
1773*4882a593Smuzhiyun };
1774*4882a593Smuzhiyun
ath6kl_debug_init(struct ath6kl * ar)1775*4882a593Smuzhiyun void ath6kl_debug_init(struct ath6kl *ar)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun skb_queue_head_init(&ar->debug.fwlog_queue);
1778*4882a593Smuzhiyun init_completion(&ar->debug.fwlog_completion);
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun /*
1781*4882a593Smuzhiyun * Actually we are lying here but don't know how to read the mask
1782*4882a593Smuzhiyun * value from the firmware.
1783*4882a593Smuzhiyun */
1784*4882a593Smuzhiyun ar->debug.fwlog_mask = 0;
1785*4882a593Smuzhiyun }
1786*4882a593Smuzhiyun
1787*4882a593Smuzhiyun /*
1788*4882a593Smuzhiyun * Initialisation needs to happen in two stages as fwlog events can come
1789*4882a593Smuzhiyun * before cfg80211 is initialised, and debugfs depends on cfg80211
1790*4882a593Smuzhiyun * initialisation.
1791*4882a593Smuzhiyun */
ath6kl_debug_init_fs(struct ath6kl * ar)1792*4882a593Smuzhiyun int ath6kl_debug_init_fs(struct ath6kl *ar)
1793*4882a593Smuzhiyun {
1794*4882a593Smuzhiyun ar->debugfs_phy = debugfs_create_dir("ath6kl",
1795*4882a593Smuzhiyun ar->wiphy->debugfsdir);
1796*4882a593Smuzhiyun if (!ar->debugfs_phy)
1797*4882a593Smuzhiyun return -ENOMEM;
1798*4882a593Smuzhiyun
1799*4882a593Smuzhiyun debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar,
1800*4882a593Smuzhiyun &fops_tgt_stats);
1801*4882a593Smuzhiyun
1802*4882a593Smuzhiyun if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)
1803*4882a593Smuzhiyun debugfs_create_file("credit_dist_stats", 0400,
1804*4882a593Smuzhiyun ar->debugfs_phy, ar,
1805*4882a593Smuzhiyun &fops_credit_dist_stats);
1806*4882a593Smuzhiyun
1807*4882a593Smuzhiyun debugfs_create_file("endpoint_stats", 0600,
1808*4882a593Smuzhiyun ar->debugfs_phy, ar, &fops_endpoint_stats);
1809*4882a593Smuzhiyun
1810*4882a593Smuzhiyun debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog);
1811*4882a593Smuzhiyun
1812*4882a593Smuzhiyun debugfs_create_file("fwlog_block", 0400, ar->debugfs_phy, ar,
1813*4882a593Smuzhiyun &fops_fwlog_block);
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun debugfs_create_file("fwlog_mask", 0600, ar->debugfs_phy,
1816*4882a593Smuzhiyun ar, &fops_fwlog_mask);
1817*4882a593Smuzhiyun
1818*4882a593Smuzhiyun debugfs_create_file("reg_addr", 0600, ar->debugfs_phy, ar,
1819*4882a593Smuzhiyun &fops_diag_reg_read);
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun debugfs_create_file("reg_dump", 0400, ar->debugfs_phy, ar,
1822*4882a593Smuzhiyun &fops_reg_dump);
1823*4882a593Smuzhiyun
1824*4882a593Smuzhiyun debugfs_create_file("lrssi_roam_threshold", 0600,
1825*4882a593Smuzhiyun ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
1826*4882a593Smuzhiyun
1827*4882a593Smuzhiyun debugfs_create_file("reg_write", 0600,
1828*4882a593Smuzhiyun ar->debugfs_phy, ar, &fops_diag_reg_write);
1829*4882a593Smuzhiyun
1830*4882a593Smuzhiyun debugfs_create_file("war_stats", 0400, ar->debugfs_phy, ar,
1831*4882a593Smuzhiyun &fops_war_stats);
1832*4882a593Smuzhiyun
1833*4882a593Smuzhiyun debugfs_create_file("roam_table", 0400, ar->debugfs_phy, ar,
1834*4882a593Smuzhiyun &fops_roam_table);
1835*4882a593Smuzhiyun
1836*4882a593Smuzhiyun debugfs_create_file("force_roam", 0200, ar->debugfs_phy, ar,
1837*4882a593Smuzhiyun &fops_force_roam);
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun debugfs_create_file("roam_mode", 0200, ar->debugfs_phy, ar,
1840*4882a593Smuzhiyun &fops_roam_mode);
1841*4882a593Smuzhiyun
1842*4882a593Smuzhiyun debugfs_create_file("keepalive", 0600, ar->debugfs_phy, ar,
1843*4882a593Smuzhiyun &fops_keepalive);
1844*4882a593Smuzhiyun
1845*4882a593Smuzhiyun debugfs_create_file("disconnect_timeout", 0600,
1846*4882a593Smuzhiyun ar->debugfs_phy, ar, &fops_disconnect_timeout);
1847*4882a593Smuzhiyun
1848*4882a593Smuzhiyun debugfs_create_file("create_qos", 0200, ar->debugfs_phy, ar,
1849*4882a593Smuzhiyun &fops_create_qos);
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun debugfs_create_file("delete_qos", 0200, ar->debugfs_phy, ar,
1852*4882a593Smuzhiyun &fops_delete_qos);
1853*4882a593Smuzhiyun
1854*4882a593Smuzhiyun debugfs_create_file("bgscan_interval", 0200,
1855*4882a593Smuzhiyun ar->debugfs_phy, ar, &fops_bgscan_int);
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun debugfs_create_file("listen_interval", 0600,
1858*4882a593Smuzhiyun ar->debugfs_phy, ar, &fops_listen_int);
1859*4882a593Smuzhiyun
1860*4882a593Smuzhiyun debugfs_create_file("power_params", 0200, ar->debugfs_phy, ar,
1861*4882a593Smuzhiyun &fops_power_params);
1862*4882a593Smuzhiyun
1863*4882a593Smuzhiyun return 0;
1864*4882a593Smuzhiyun }
1865*4882a593Smuzhiyun
ath6kl_debug_cleanup(struct ath6kl * ar)1866*4882a593Smuzhiyun void ath6kl_debug_cleanup(struct ath6kl *ar)
1867*4882a593Smuzhiyun {
1868*4882a593Smuzhiyun skb_queue_purge(&ar->debug.fwlog_queue);
1869*4882a593Smuzhiyun complete(&ar->debug.fwlog_completion);
1870*4882a593Smuzhiyun kfree(ar->debug.roam_tbl);
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun
1873*4882a593Smuzhiyun #endif
1874