blob: 370664a7a37bea53f41cb2b8b3b75410a0331542 [file] [log] [blame]
Kalle Valobdcd8172011-07-18 00:22:30 +03001/*
2 * Copyright (c) 2004-2011 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
Kalle Valobdf53962011-09-02 10:32:04 +030018
19#include <linux/circ_buf.h>
Kalle Valo939f1cc2011-09-02 10:32:04 +030020#include <linux/fs.h>
Kalle Valo62c83ac2011-10-03 13:44:40 +030021#include <linux/vmalloc.h>
Kalle Valobdf53962011-09-02 10:32:04 +030022
Kalle Valobdcd8172011-07-18 00:22:30 +030023#include "debug.h"
Kalle Valobdf53962011-09-02 10:32:04 +030024#include "target.h"
25
26struct ath6kl_fwlog_slot {
27 __le32 timestamp;
28 __le32 length;
29
30 /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
31 u8 payload[0];
32};
33
34#define ATH6KL_FWLOG_SIZE 32768
35#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
36 ATH6KL_FWLOG_PAYLOAD_SIZE)
Kalle Valo939f1cc2011-09-02 10:32:04 +030037#define ATH6KL_FWLOG_VALID_MASK 0x1ffff
Kalle Valobdcd8172011-07-18 00:22:30 +030038
39int ath6kl_printk(const char *level, const char *fmt, ...)
40{
41 struct va_format vaf;
42 va_list args;
43 int rtn;
44
45 va_start(args, fmt);
46
47 vaf.fmt = fmt;
48 vaf.va = &args;
49
50 rtn = printk("%sath6kl: %pV", level, &vaf);
51
52 va_end(args);
53
54 return rtn;
55}
56
57#ifdef CONFIG_ATH6KL_DEBUG
Vasanthakumar Thiagarajan91d57de2011-09-02 10:40:06 +030058
59#define REG_OUTPUT_LEN_PER_LINE 25
60#define REGTYPE_STR_LEN 100
61
62struct ath6kl_diag_reg_info {
63 u32 reg_start;
64 u32 reg_end;
65 const char *reg_info;
66};
67
68static const struct ath6kl_diag_reg_info diag_reg[] = {
69 { 0x20000, 0x200fc, "General DMA and Rx registers" },
70 { 0x28000, 0x28900, "MAC PCU register & keycache" },
71 { 0x20800, 0x20a40, "QCU" },
72 { 0x21000, 0x212f0, "DCU" },
73 { 0x4000, 0x42e4, "RTC" },
74 { 0x540000, 0x540000 + (256 * 1024), "RAM" },
75 { 0x29800, 0x2B210, "Base Band" },
76 { 0x1C000, 0x1C748, "Analog" },
77};
78
Kalle Valobdcd8172011-07-18 00:22:30 +030079void ath6kl_dump_registers(struct ath6kl_device *dev,
80 struct ath6kl_irq_proc_registers *irq_proc_reg,
81 struct ath6kl_irq_enable_reg *irq_enable_reg)
82{
83
84 ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
85
86 if (irq_proc_reg != NULL) {
87 ath6kl_dbg(ATH6KL_DBG_ANY,
88 "Host Int status: 0x%x\n",
89 irq_proc_reg->host_int_status);
90 ath6kl_dbg(ATH6KL_DBG_ANY,
91 "CPU Int status: 0x%x\n",
92 irq_proc_reg->cpu_int_status);
93 ath6kl_dbg(ATH6KL_DBG_ANY,
94 "Error Int status: 0x%x\n",
95 irq_proc_reg->error_int_status);
96 ath6kl_dbg(ATH6KL_DBG_ANY,
97 "Counter Int status: 0x%x\n",
98 irq_proc_reg->counter_int_status);
99 ath6kl_dbg(ATH6KL_DBG_ANY,
100 "Mbox Frame: 0x%x\n",
101 irq_proc_reg->mbox_frame);
102 ath6kl_dbg(ATH6KL_DBG_ANY,
103 "Rx Lookahead Valid: 0x%x\n",
104 irq_proc_reg->rx_lkahd_valid);
105 ath6kl_dbg(ATH6KL_DBG_ANY,
106 "Rx Lookahead 0: 0x%x\n",
107 irq_proc_reg->rx_lkahd[0]);
108 ath6kl_dbg(ATH6KL_DBG_ANY,
109 "Rx Lookahead 1: 0x%x\n",
110 irq_proc_reg->rx_lkahd[1]);
111
112 if (dev->ar->mbox_info.gmbox_addr != 0) {
113 /*
114 * If the target supports GMBOX hardware, dump some
115 * additional state.
116 */
117 ath6kl_dbg(ATH6KL_DBG_ANY,
118 "GMBOX Host Int status 2: 0x%x\n",
119 irq_proc_reg->host_int_status2);
120 ath6kl_dbg(ATH6KL_DBG_ANY,
121 "GMBOX RX Avail: 0x%x\n",
122 irq_proc_reg->gmbox_rx_avail);
123 ath6kl_dbg(ATH6KL_DBG_ANY,
124 "GMBOX lookahead alias 0: 0x%x\n",
125 irq_proc_reg->rx_gmbox_lkahd_alias[0]);
126 ath6kl_dbg(ATH6KL_DBG_ANY,
127 "GMBOX lookahead alias 1: 0x%x\n",
128 irq_proc_reg->rx_gmbox_lkahd_alias[1]);
129 }
130
131 }
132
133 if (irq_enable_reg != NULL) {
134 ath6kl_dbg(ATH6KL_DBG_ANY,
135 "Int status Enable: 0x%x\n",
136 irq_enable_reg->int_status_en);
137 ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
138 irq_enable_reg->cntr_int_status_en);
139 }
140 ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
141}
142
143static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
144{
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300145 ath6kl_dbg(ATH6KL_DBG_CREDIT,
Kalle Valobdcd8172011-07-18 00:22:30 +0300146 "--- endpoint: %d svc_id: 0x%X ---\n",
147 ep_dist->endpoint, ep_dist->svc_id);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300148 ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags : 0x%X\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300149 ep_dist->dist_flags);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300150 ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300151 ep_dist->cred_norm);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300152 ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300153 ep_dist->cred_min);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300154 ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300155 ep_dist->credits);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300156 ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300157 ep_dist->cred_assngd);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300158 ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300159 ep_dist->seek_cred);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300160 ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300161 ep_dist->cred_sz);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300162 ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300163 ep_dist->cred_per_msg);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300164 ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist : %d\n",
Kalle Valobdcd8172011-07-18 00:22:30 +0300165 ep_dist->cred_to_dist);
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300166 ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth : %d\n",
Kalle Valoe8c39792011-10-24 12:17:04 +0300167 get_queue_depth(&ep_dist->htc_ep->txq));
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300168 ath6kl_dbg(ATH6KL_DBG_CREDIT,
Kalle Valobdcd8172011-07-18 00:22:30 +0300169 "----------------------------------\n");
170}
171
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300172/* FIXME: move to htc.c */
Kalle Valobdcd8172011-07-18 00:22:30 +0300173void dump_cred_dist_stats(struct htc_target *target)
174{
175 struct htc_endpoint_credit_dist *ep_list;
176
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300177 if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_CREDIT))
Kalle Valobdcd8172011-07-18 00:22:30 +0300178 return;
179
180 list_for_each_entry(ep_list, &target->cred_dist_list, list)
181 dump_cred_dist(ep_list);
182
Kalle Valo02f0d6f2011-10-24 12:17:59 +0300183 ath6kl_dbg(ATH6KL_DBG_CREDIT,
184 "credit distribution total %d free %d\n",
Kalle Valo3c370392011-10-24 12:17:12 +0300185 target->credit_info->total_avail_credits,
186 target->credit_info->cur_free_credits);
Kalle Valobdcd8172011-07-18 00:22:30 +0300187}
188
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530189static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
190{
191 file->private_data = inode->i_private;
192 return 0;
193}
194
Kalle Valo9a730832011-09-27 23:33:28 +0300195void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war)
196{
197 switch (war) {
198 case ATH6KL_WAR_INVALID_RATE:
199 ar->debug.war_stats.invalid_rate++;
200 break;
201 }
202}
203
204static ssize_t read_file_war_stats(struct file *file, char __user *user_buf,
205 size_t count, loff_t *ppos)
206{
207 struct ath6kl *ar = file->private_data;
208 char *buf;
209 unsigned int len = 0, buf_len = 1500;
210 ssize_t ret_cnt;
211
212 buf = kzalloc(buf_len, GFP_KERNEL);
213 if (!buf)
214 return -ENOMEM;
215
216 len += scnprintf(buf + len, buf_len - len, "\n");
217 len += scnprintf(buf + len, buf_len - len, "%25s\n",
218 "Workaround stats");
219 len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
220 "=================");
221 len += scnprintf(buf + len, buf_len - len, "%20s %10u\n",
222 "Invalid rates", ar->debug.war_stats.invalid_rate);
223
224 if (WARN_ON(len > buf_len))
225 len = buf_len;
226
227 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
228
229 kfree(buf);
230 return ret_cnt;
231}
232
233static const struct file_operations fops_war_stats = {
234 .read = read_file_war_stats,
235 .open = ath6kl_debugfs_open,
236 .owner = THIS_MODULE,
237 .llseek = default_llseek,
238};
239
Kalle Valobdf53962011-09-02 10:32:04 +0300240static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf,
241 size_t buf_len)
242{
243 struct circ_buf *fwlog = &ar->debug.fwlog_buf;
244 size_t space;
245 int i;
246
247 /* entries must all be equal size */
248 if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
249 return;
250
251 space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE);
252 if (space < buf_len)
253 /* discard oldest slot */
254 fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
255 (ATH6KL_FWLOG_SIZE - 1);
256
257 for (i = 0; i < buf_len; i += space) {
258 space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail,
259 ATH6KL_FWLOG_SIZE);
260
261 if ((size_t) space > buf_len - i)
262 space = buf_len - i;
263
264 memcpy(&fwlog->buf[fwlog->head], buf, space);
265 fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1);
266 }
267
268}
269
270void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
271{
272 struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
273 size_t slot_len;
274
275 if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
276 return;
277
278 spin_lock_bh(&ar->debug.fwlog_lock);
279
280 slot->timestamp = cpu_to_le32(jiffies);
281 slot->length = cpu_to_le32(len);
282 memcpy(slot->payload, buf, len);
283
284 slot_len = sizeof(*slot) + len;
285
286 if (slot_len < ATH6KL_FWLOG_SLOT_SIZE)
287 memset(slot->payload + len, 0,
288 ATH6KL_FWLOG_SLOT_SIZE - slot_len);
289
290 ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE);
291
292 spin_unlock_bh(&ar->debug.fwlog_lock);
293}
294
295static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar)
296{
297 return CIRC_CNT(ar->debug.fwlog_buf.head,
298 ar->debug.fwlog_buf.tail,
299 ATH6KL_FWLOG_SLOT_SIZE) == 0;
300}
301
302static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
303 size_t count, loff_t *ppos)
304{
305 struct ath6kl *ar = file->private_data;
306 struct circ_buf *fwlog = &ar->debug.fwlog_buf;
307 size_t len = 0, buf_len = count;
308 ssize_t ret_cnt;
309 char *buf;
310 int ccnt;
311
312 buf = vmalloc(buf_len);
313 if (!buf)
314 return -ENOMEM;
315
Kalle Valobc07ddb2011-09-02 10:32:05 +0300316 /* read undelivered logs from firmware */
317 ath6kl_read_fwlogs(ar);
318
Kalle Valobdf53962011-09-02 10:32:04 +0300319 spin_lock_bh(&ar->debug.fwlog_lock);
320
321 while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
322 ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail,
323 ATH6KL_FWLOG_SIZE);
324
325 if ((size_t) ccnt > buf_len - len)
326 ccnt = buf_len - len;
327
328 memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt);
329 len += ccnt;
330
331 fwlog->tail = (fwlog->tail + ccnt) &
332 (ATH6KL_FWLOG_SIZE - 1);
333 }
334
335 spin_unlock_bh(&ar->debug.fwlog_lock);
336
337 if (WARN_ON(len > buf_len))
338 len = buf_len;
339
340 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
341
342 vfree(buf);
343
344 return ret_cnt;
345}
346
347static const struct file_operations fops_fwlog = {
348 .open = ath6kl_debugfs_open,
349 .read = ath6kl_fwlog_read,
350 .owner = THIS_MODULE,
351 .llseek = default_llseek,
352};
353
Kalle Valo939f1cc2011-09-02 10:32:04 +0300354static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf,
355 size_t count, loff_t *ppos)
356{
357 struct ath6kl *ar = file->private_data;
358 char buf[16];
359 int len;
360
361 len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask);
362
363 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
364}
365
366static ssize_t ath6kl_fwlog_mask_write(struct file *file,
367 const char __user *user_buf,
368 size_t count, loff_t *ppos)
369{
370 struct ath6kl *ar = file->private_data;
371 int ret;
372
373 ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask);
374 if (ret)
375 return ret;
376
377 ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi,
378 ATH6KL_FWLOG_VALID_MASK,
379 ar->debug.fwlog_mask);
380 if (ret)
381 return ret;
382
383 return count;
384}
385
386static const struct file_operations fops_fwlog_mask = {
387 .open = ath6kl_debugfs_open,
388 .read = ath6kl_fwlog_mask_read,
389 .write = ath6kl_fwlog_mask_write,
390 .owner = THIS_MODULE,
391 .llseek = default_llseek,
392};
393
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530394static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
395 size_t count, loff_t *ppos)
396{
397 struct ath6kl *ar = file->private_data;
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530398 struct ath6kl_vif *vif;
399 struct target_stats *tgt_stats;
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530400 char *buf;
401 unsigned int len = 0, buf_len = 1500;
402 int i;
403 long left;
404 ssize_t ret_cnt;
405
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +0530406 vif = ath6kl_vif_first(ar);
407 if (!vif)
408 return -EIO;
409
410 tgt_stats = &vif->target_stats;
411
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530412 buf = kzalloc(buf_len, GFP_KERNEL);
413 if (!buf)
414 return -ENOMEM;
415
416 if (down_interruptible(&ar->sem)) {
417 kfree(buf);
418 return -EBUSY;
419 }
420
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +0530421 set_bit(STATS_UPDATE_PEND, &vif->flags);
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530422
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +0530423 if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) {
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530424 up(&ar->sem);
425 kfree(buf);
426 return -EIO;
427 }
428
429 left = wait_event_interruptible_timeout(ar->event_wq,
430 !test_bit(STATS_UPDATE_PEND,
Vasanthakumar Thiagarajanb95907a2011-10-25 19:34:11 +0530431 &vif->flags), WMI_TIMEOUT);
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530432
433 up(&ar->sem);
434
435 if (left <= 0) {
436 kfree(buf);
437 return -ETIMEDOUT;
438 }
439
440 len += scnprintf(buf + len, buf_len - len, "\n");
441 len += scnprintf(buf + len, buf_len - len, "%25s\n",
442 "Target Tx stats");
443 len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
444 "=================");
445 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
446 "Ucast packets", tgt_stats->tx_ucast_pkt);
447 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
448 "Bcast packets", tgt_stats->tx_bcast_pkt);
449 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
450 "Ucast byte", tgt_stats->tx_ucast_byte);
451 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
452 "Bcast byte", tgt_stats->tx_bcast_byte);
453 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
454 "Rts success cnt", tgt_stats->tx_rts_success_cnt);
455 for (i = 0; i < 4; i++)
456 len += scnprintf(buf + len, buf_len - len,
457 "%18s %d %10llu\n", "PER on ac",
458 i, tgt_stats->tx_pkt_per_ac[i]);
459 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
460 "Error", tgt_stats->tx_err);
461 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
462 "Fail count", tgt_stats->tx_fail_cnt);
463 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
464 "Retry count", tgt_stats->tx_retry_cnt);
465 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
466 "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
467 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
468 "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
469 len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
470 "TKIP counter measure used",
471 tgt_stats->tkip_cnter_measures_invoked);
472
473 len += scnprintf(buf + len, buf_len - len, "%25s\n",
474 "Target Rx stats");
475 len += scnprintf(buf + len, buf_len - len, "%25s\n",
476 "=================");
477
478 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
479 "Ucast packets", tgt_stats->rx_ucast_pkt);
480 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
481 "Ucast Rate", tgt_stats->rx_ucast_rate);
482 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
483 "Bcast packets", tgt_stats->rx_bcast_pkt);
484 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
485 "Ucast byte", tgt_stats->rx_ucast_byte);
486 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
487 "Bcast byte", tgt_stats->rx_bcast_byte);
488 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
489 "Fragmented pkt", tgt_stats->rx_frgment_pkt);
490 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
491 "Error", tgt_stats->rx_err);
492 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
493 "CRC Err", tgt_stats->rx_crc_err);
494 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
495 "Key chache miss", tgt_stats->rx_key_cache_miss);
496 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
497 "Decrypt Err", tgt_stats->rx_decrypt_err);
498 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
499 "Duplicate frame", tgt_stats->rx_dupl_frame);
500 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
501 "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
502 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
503 "TKIP format err", tgt_stats->tkip_fmt_err);
504 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
505 "CCMP format Err", tgt_stats->ccmp_fmt_err);
506 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
507 "CCMP Replay Err", tgt_stats->ccmp_replays);
508
509 len += scnprintf(buf + len, buf_len - len, "%25s\n",
510 "Misc Target stats");
511 len += scnprintf(buf + len, buf_len - len, "%25s\n",
512 "=================");
513 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
514 "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
515 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
516 "Num Connects", tgt_stats->cs_connect_cnt);
517 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
518 "Num disconnects", tgt_stats->cs_discon_cnt);
519 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
520 "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
521
522 if (len > buf_len)
523 len = buf_len;
524
525 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
526
527 kfree(buf);
528 return ret_cnt;
529}
530
531static const struct file_operations fops_tgt_stats = {
532 .read = read_file_tgt_stats,
533 .open = ath6kl_debugfs_open,
534 .owner = THIS_MODULE,
535 .llseek = default_llseek,
536};
537
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +0530538#define print_credit_info(fmt_str, ep_list_field) \
539 (len += scnprintf(buf + len, buf_len - len, fmt_str, \
540 ep_list->ep_list_field))
541#define CREDIT_INFO_DISPLAY_STRING_LEN 200
542#define CREDIT_INFO_LEN 128
543
544static ssize_t read_file_credit_dist_stats(struct file *file,
545 char __user *user_buf,
546 size_t count, loff_t *ppos)
547{
548 struct ath6kl *ar = file->private_data;
549 struct htc_target *target = ar->htc_target;
550 struct htc_endpoint_credit_dist *ep_list;
551 char *buf;
552 unsigned int buf_len, len = 0;
553 ssize_t ret_cnt;
554
555 buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
556 get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
557 buf = kzalloc(buf_len, GFP_KERNEL);
558 if (!buf)
559 return -ENOMEM;
560
561 len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
562 "Total Avail Credits: ",
Kalle Valo3c370392011-10-24 12:17:12 +0300563 target->credit_info->total_avail_credits);
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +0530564 len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
565 "Free credits :",
Kalle Valo3c370392011-10-24 12:17:12 +0300566 target->credit_info->cur_free_credits);
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +0530567
568 len += scnprintf(buf + len, buf_len - len,
569 " Epid Flags Cred_norm Cred_min Credits Cred_assngd"
570 " Seek_cred Cred_sz Cred_per_msg Cred_to_dist"
571 " qdepth\n");
572
573 list_for_each_entry(ep_list, &target->cred_dist_list, list) {
574 print_credit_info(" %2d", endpoint);
575 print_credit_info("%10x", dist_flags);
576 print_credit_info("%8d", cred_norm);
577 print_credit_info("%9d", cred_min);
578 print_credit_info("%9d", credits);
579 print_credit_info("%10d", cred_assngd);
580 print_credit_info("%13d", seek_cred);
581 print_credit_info("%12d", cred_sz);
582 print_credit_info("%9d", cred_per_msg);
583 print_credit_info("%14d", cred_to_dist);
584 len += scnprintf(buf + len, buf_len - len, "%12d\n",
Kalle Valoe8c39792011-10-24 12:17:04 +0300585 get_queue_depth(&ep_list->htc_ep->txq));
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +0530586 }
587
588 if (len > buf_len)
589 len = buf_len;
590
591 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
592 kfree(buf);
593 return ret_cnt;
594}
595
596static const struct file_operations fops_credit_dist_stats = {
597 .read = read_file_credit_dist_stats,
598 .open = ath6kl_debugfs_open,
599 .owner = THIS_MODULE,
600 .llseek = default_llseek,
601};
602
Jouni Malinene8091282011-10-11 17:31:53 +0300603static unsigned int print_endpoint_stat(struct htc_target *target, char *buf,
604 unsigned int buf_len, unsigned int len,
605 int offset, const char *name)
606{
607 int i;
608 struct htc_endpoint_stats *ep_st;
609 u32 *counter;
610
611 len += scnprintf(buf + len, buf_len - len, "%s:", name);
612 for (i = 0; i < ENDPOINT_MAX; i++) {
613 ep_st = &target->endpoint[i].ep_st;
614 counter = ((u32 *) ep_st) + (offset / 4);
615 len += scnprintf(buf + len, buf_len - len, " %u", *counter);
616 }
617 len += scnprintf(buf + len, buf_len - len, "\n");
618
619 return len;
620}
621
622static ssize_t ath6kl_endpoint_stats_read(struct file *file,
623 char __user *user_buf,
624 size_t count, loff_t *ppos)
625{
626 struct ath6kl *ar = file->private_data;
627 struct htc_target *target = ar->htc_target;
628 char *buf;
629 unsigned int buf_len, len = 0;
630 ssize_t ret_cnt;
631
Jouni Malinen17169322011-10-11 22:08:21 +0300632 buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) *
633 (25 + ENDPOINT_MAX * 11);
634 buf = kmalloc(buf_len, GFP_KERNEL);
Jouni Malinene8091282011-10-11 17:31:53 +0300635 if (!buf)
636 return -ENOMEM;
637
638#define EPSTAT(name) \
639 len = print_endpoint_stat(target, buf, buf_len, len, \
640 offsetof(struct htc_endpoint_stats, name), \
641 #name)
642 EPSTAT(cred_low_indicate);
643 EPSTAT(tx_issued);
644 EPSTAT(tx_pkt_bundled);
645 EPSTAT(tx_bundles);
646 EPSTAT(tx_dropped);
647 EPSTAT(tx_cred_rpt);
648 EPSTAT(cred_rpt_from_rx);
Jouni Malinen17169322011-10-11 22:08:21 +0300649 EPSTAT(cred_rpt_from_other);
Jouni Malinene8091282011-10-11 17:31:53 +0300650 EPSTAT(cred_rpt_ep0);
651 EPSTAT(cred_from_rx);
652 EPSTAT(cred_from_other);
653 EPSTAT(cred_from_ep0);
654 EPSTAT(cred_cosumd);
655 EPSTAT(cred_retnd);
656 EPSTAT(rx_pkts);
657 EPSTAT(rx_lkahds);
658 EPSTAT(rx_bundl);
659 EPSTAT(rx_bundle_lkahd);
660 EPSTAT(rx_bundle_from_hdr);
661 EPSTAT(rx_alloc_thresh_hit);
662 EPSTAT(rxalloc_thresh_byte);
663#undef EPSTAT
664
665 if (len > buf_len)
666 len = buf_len;
667
668 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
669 kfree(buf);
670 return ret_cnt;
671}
672
673static ssize_t ath6kl_endpoint_stats_write(struct file *file,
674 const char __user *user_buf,
675 size_t count, loff_t *ppos)
676{
677 struct ath6kl *ar = file->private_data;
678 struct htc_target *target = ar->htc_target;
679 int ret, i;
680 u32 val;
681 struct htc_endpoint_stats *ep_st;
682
683 ret = kstrtou32_from_user(user_buf, count, 0, &val);
684 if (ret)
685 return ret;
686 if (val == 0) {
687 for (i = 0; i < ENDPOINT_MAX; i++) {
688 ep_st = &target->endpoint[i].ep_st;
689 memset(ep_st, 0, sizeof(*ep_st));
690 }
691 }
692
693 return count;
694}
695
696static const struct file_operations fops_endpoint_stats = {
697 .open = ath6kl_debugfs_open,
698 .read = ath6kl_endpoint_stats_read,
699 .write = ath6kl_endpoint_stats_write,
700 .owner = THIS_MODULE,
701 .llseek = default_llseek,
702};
703
Vasanthakumar Thiagarajan91d57de2011-09-02 10:40:06 +0300704static unsigned long ath6kl_get_num_reg(void)
705{
706 int i;
707 unsigned long n_reg = 0;
708
709 for (i = 0; i < ARRAY_SIZE(diag_reg); i++)
710 n_reg = n_reg +
711 (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1;
712
713 return n_reg;
714}
715
716static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr)
717{
718 int i;
719
720 for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
721 if (reg_addr >= diag_reg[i].reg_start &&
722 reg_addr <= diag_reg[i].reg_end)
723 return true;
724 }
725
726 return false;
727}
728
729static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf,
730 size_t count, loff_t *ppos)
731{
732 struct ath6kl *ar = file->private_data;
733 u8 buf[50];
734 unsigned int len = 0;
735
736 if (ar->debug.dbgfs_diag_reg)
737 len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n",
738 ar->debug.dbgfs_diag_reg);
739 else
740 len += scnprintf(buf + len, sizeof(buf) - len,
741 "All diag registers\n");
742
743 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
744}
745
746static ssize_t ath6kl_regread_write(struct file *file,
747 const char __user *user_buf,
748 size_t count, loff_t *ppos)
749{
750 struct ath6kl *ar = file->private_data;
751 u8 buf[50];
752 unsigned int len;
753 unsigned long reg_addr;
754
755 len = min(count, sizeof(buf) - 1);
756 if (copy_from_user(buf, user_buf, len))
757 return -EFAULT;
758
759 buf[len] = '\0';
760
761 if (strict_strtoul(buf, 0, &reg_addr))
762 return -EINVAL;
763
764 if ((reg_addr % 4) != 0)
765 return -EINVAL;
766
767 if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr))
768 return -EINVAL;
769
770 ar->debug.dbgfs_diag_reg = reg_addr;
771
772 return count;
773}
774
775static const struct file_operations fops_diag_reg_read = {
776 .read = ath6kl_regread_read,
777 .write = ath6kl_regread_write,
778 .open = ath6kl_debugfs_open,
779 .owner = THIS_MODULE,
780 .llseek = default_llseek,
781};
782
783static int ath6kl_regdump_open(struct inode *inode, struct file *file)
784{
785 struct ath6kl *ar = inode->i_private;
786 u8 *buf;
787 unsigned long int reg_len;
788 unsigned int len = 0, n_reg;
789 u32 addr;
790 __le32 reg_val;
791 int i, status;
792
793 /* Dump all the registers if no register is specified */
794 if (!ar->debug.dbgfs_diag_reg)
795 n_reg = ath6kl_get_num_reg();
796 else
797 n_reg = 1;
798
799 reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE;
800 if (n_reg > 1)
801 reg_len += REGTYPE_STR_LEN;
802
803 buf = vmalloc(reg_len);
804 if (!buf)
805 return -ENOMEM;
806
807 if (n_reg == 1) {
808 addr = ar->debug.dbgfs_diag_reg;
809
810 status = ath6kl_diag_read32(ar,
811 TARG_VTOP(ar->target_type, addr),
812 (u32 *)&reg_val);
813 if (status)
814 goto fail_reg_read;
815
816 len += scnprintf(buf + len, reg_len - len,
817 "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val));
818 goto done;
819 }
820
821 for (i = 0; i < ARRAY_SIZE(diag_reg); i++) {
822 len += scnprintf(buf + len, reg_len - len,
823 "%s\n", diag_reg[i].reg_info);
824 for (addr = diag_reg[i].reg_start;
825 addr <= diag_reg[i].reg_end; addr += 4) {
826 status = ath6kl_diag_read32(ar,
827 TARG_VTOP(ar->target_type, addr),
828 (u32 *)&reg_val);
829 if (status)
830 goto fail_reg_read;
831
832 len += scnprintf(buf + len, reg_len - len,
833 "0x%06x 0x%08x\n",
834 addr, le32_to_cpu(reg_val));
835 }
836 }
837
838done:
839 file->private_data = buf;
840 return 0;
841
842fail_reg_read:
843 ath6kl_warn("Unable to read memory:%u\n", addr);
844 vfree(buf);
845 return -EIO;
846}
847
848static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf,
849 size_t count, loff_t *ppos)
850{
851 u8 *buf = file->private_data;
852 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
853}
854
855static int ath6kl_regdump_release(struct inode *inode, struct file *file)
856{
857 vfree(file->private_data);
858 return 0;
859}
860
861static const struct file_operations fops_reg_dump = {
862 .open = ath6kl_regdump_open,
863 .read = ath6kl_regdump_read,
864 .release = ath6kl_regdump_release,
865 .owner = THIS_MODULE,
866 .llseek = default_llseek,
867};
868
Vivek Natarajane5090442011-08-31 15:02:19 +0530869static ssize_t ath6kl_lrssi_roam_write(struct file *file,
870 const char __user *user_buf,
871 size_t count, loff_t *ppos)
872{
873 struct ath6kl *ar = file->private_data;
874 unsigned long lrssi_roam_threshold;
875 char buf[32];
876 ssize_t len;
877
878 len = min(count, sizeof(buf) - 1);
879 if (copy_from_user(buf, user_buf, len))
880 return -EFAULT;
881
882 buf[len] = '\0';
883 if (strict_strtoul(buf, 0, &lrssi_roam_threshold))
884 return -EINVAL;
885
886 ar->lrssi_roam_threshold = lrssi_roam_threshold;
887
888 ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold);
889
890 return count;
891}
892
893static ssize_t ath6kl_lrssi_roam_read(struct file *file,
894 char __user *user_buf,
895 size_t count, loff_t *ppos)
896{
897 struct ath6kl *ar = file->private_data;
898 char buf[32];
899 unsigned int len;
900
901 len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold);
902
903 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
904}
905
906static const struct file_operations fops_lrssi_roam_threshold = {
907 .read = ath6kl_lrssi_roam_read,
908 .write = ath6kl_lrssi_roam_write,
909 .open = ath6kl_debugfs_open,
910 .owner = THIS_MODULE,
911 .llseek = default_llseek,
912};
913
Vasanthakumar Thiagarajan252c0682011-09-05 11:19:46 +0300914static ssize_t ath6kl_regwrite_read(struct file *file,
915 char __user *user_buf,
916 size_t count, loff_t *ppos)
917{
918 struct ath6kl *ar = file->private_data;
919 u8 buf[32];
920 unsigned int len = 0;
921
922 len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n",
923 ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr);
924
925 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
926}
927
928static ssize_t ath6kl_regwrite_write(struct file *file,
929 const char __user *user_buf,
930 size_t count, loff_t *ppos)
931{
932 struct ath6kl *ar = file->private_data;
933 char buf[32];
934 char *sptr, *token;
935 unsigned int len = 0;
936 u32 reg_addr, reg_val;
937
938 len = min(count, sizeof(buf) - 1);
939 if (copy_from_user(buf, user_buf, len))
940 return -EFAULT;
941
942 buf[len] = '\0';
943 sptr = buf;
944
945 token = strsep(&sptr, "=");
946 if (!token)
947 return -EINVAL;
948
949 if (kstrtou32(token, 0, &reg_addr))
950 return -EINVAL;
951
952 if (!ath6kl_dbg_is_diag_reg_valid(reg_addr))
953 return -EINVAL;
954
955 if (kstrtou32(sptr, 0, &reg_val))
956 return -EINVAL;
957
958 ar->debug.diag_reg_addr_wr = reg_addr;
959 ar->debug.diag_reg_val_wr = reg_val;
960
961 if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr,
962 cpu_to_le32(ar->debug.diag_reg_val_wr)))
963 return -EIO;
964
965 return count;
966}
967
968static const struct file_operations fops_diag_reg_write = {
969 .read = ath6kl_regwrite_read,
970 .write = ath6kl_regwrite_write,
971 .open = ath6kl_debugfs_open,
972 .owner = THIS_MODULE,
973 .llseek = default_llseek,
974};
975
Jouni Malinen4b28a802011-10-11 17:31:54 +0300976int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf,
977 size_t len)
978{
979 const struct wmi_target_roam_tbl *tbl;
980 u16 num_entries;
981
982 if (len < sizeof(*tbl))
983 return -EINVAL;
984
985 tbl = (const struct wmi_target_roam_tbl *) buf;
986 num_entries = le16_to_cpu(tbl->num_entries);
987 if (sizeof(*tbl) + num_entries * sizeof(struct wmi_bss_roam_info) >
988 len)
989 return -EINVAL;
990
991 if (ar->debug.roam_tbl == NULL ||
992 ar->debug.roam_tbl_len < (unsigned int) len) {
993 kfree(ar->debug.roam_tbl);
994 ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC);
995 if (ar->debug.roam_tbl == NULL)
996 return -ENOMEM;
997 }
998
999 memcpy(ar->debug.roam_tbl, buf, len);
1000 ar->debug.roam_tbl_len = len;
1001
1002 if (test_bit(ROAM_TBL_PEND, &ar->flag)) {
1003 clear_bit(ROAM_TBL_PEND, &ar->flag);
1004 wake_up(&ar->event_wq);
1005 }
1006
1007 return 0;
1008}
1009
1010static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf,
1011 size_t count, loff_t *ppos)
1012{
1013 struct ath6kl *ar = file->private_data;
1014 int ret;
1015 long left;
1016 struct wmi_target_roam_tbl *tbl;
1017 u16 num_entries, i;
1018 char *buf;
1019 unsigned int len, buf_len;
1020 ssize_t ret_cnt;
1021
1022 if (down_interruptible(&ar->sem))
1023 return -EBUSY;
1024
1025 set_bit(ROAM_TBL_PEND, &ar->flag);
1026
1027 ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi);
1028 if (ret) {
1029 up(&ar->sem);
1030 return ret;
1031 }
1032
1033 left = wait_event_interruptible_timeout(
1034 ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT);
1035 up(&ar->sem);
1036
1037 if (left <= 0)
1038 return -ETIMEDOUT;
1039
1040 if (ar->debug.roam_tbl == NULL)
1041 return -ENOMEM;
1042
1043 tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl;
1044 num_entries = le16_to_cpu(tbl->num_entries);
1045
1046 buf_len = 100 + num_entries * 100;
1047 buf = kzalloc(buf_len, GFP_KERNEL);
1048 if (buf == NULL)
1049 return -ENOMEM;
1050 len = 0;
1051 len += scnprintf(buf + len, buf_len - len,
1052 "roam_mode=%u\n\n"
1053 "# roam_util bssid rssi rssidt last_rssi util bias\n",
1054 le16_to_cpu(tbl->roam_mode));
1055
1056 for (i = 0; i < num_entries; i++) {
1057 struct wmi_bss_roam_info *info = &tbl->info[i];
1058 len += scnprintf(buf + len, buf_len - len,
1059 "%d %pM %d %d %d %d %d\n",
1060 a_sle32_to_cpu(info->roam_util), info->bssid,
1061 info->rssi, info->rssidt, info->last_rssi,
1062 info->util, info->bias);
1063 }
1064
1065 if (len > buf_len)
1066 len = buf_len;
1067
1068 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1069
1070 kfree(buf);
1071 return ret_cnt;
1072}
1073
1074static const struct file_operations fops_roam_table = {
1075 .read = ath6kl_roam_table_read,
1076 .open = ath6kl_debugfs_open,
1077 .owner = THIS_MODULE,
1078 .llseek = default_llseek,
1079};
1080
Jouni Malinen12618752011-10-11 17:31:55 +03001081static ssize_t ath6kl_force_roam_write(struct file *file,
1082 const char __user *user_buf,
1083 size_t count, loff_t *ppos)
1084{
1085 struct ath6kl *ar = file->private_data;
1086 int ret;
1087 char buf[20];
1088 size_t len;
1089 u8 bssid[ETH_ALEN];
1090 int i;
1091 int addr[ETH_ALEN];
1092
1093 len = min(count, sizeof(buf) - 1);
1094 if (copy_from_user(buf, user_buf, len))
1095 return -EFAULT;
1096 buf[len] = '\0';
1097
1098 if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
1099 &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5])
1100 != ETH_ALEN)
1101 return -EINVAL;
1102 for (i = 0; i < ETH_ALEN; i++)
1103 bssid[i] = addr[i];
1104
1105 ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid);
1106 if (ret)
1107 return ret;
1108
1109 return count;
1110}
1111
1112static const struct file_operations fops_force_roam = {
1113 .write = ath6kl_force_roam_write,
1114 .open = ath6kl_debugfs_open,
1115 .owner = THIS_MODULE,
1116 .llseek = default_llseek,
1117};
1118
1119static ssize_t ath6kl_roam_mode_write(struct file *file,
1120 const char __user *user_buf,
1121 size_t count, loff_t *ppos)
1122{
1123 struct ath6kl *ar = file->private_data;
1124 int ret;
1125 char buf[20];
1126 size_t len;
1127 enum wmi_roam_mode mode;
1128
1129 len = min(count, sizeof(buf) - 1);
1130 if (copy_from_user(buf, user_buf, len))
1131 return -EFAULT;
1132 buf[len] = '\0';
1133 if (len > 0 && buf[len - 1] == '\n')
1134 buf[len - 1] = '\0';
1135
1136 if (strcasecmp(buf, "default") == 0)
1137 mode = WMI_DEFAULT_ROAM_MODE;
1138 else if (strcasecmp(buf, "bssbias") == 0)
1139 mode = WMI_HOST_BIAS_ROAM_MODE;
1140 else if (strcasecmp(buf, "lock") == 0)
1141 mode = WMI_LOCK_BSS_MODE;
1142 else
1143 return -EINVAL;
1144
1145 ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode);
1146 if (ret)
1147 return ret;
1148
1149 return count;
1150}
1151
1152static const struct file_operations fops_roam_mode = {
1153 .write = ath6kl_roam_mode_write,
1154 .open = ath6kl_debugfs_open,
1155 .owner = THIS_MODULE,
1156 .llseek = default_llseek,
1157};
1158
Jouni Malinenff0b0072011-10-11 17:31:56 +03001159void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive)
1160{
1161 ar->debug.keepalive = keepalive;
1162}
1163
1164static ssize_t ath6kl_keepalive_read(struct file *file, char __user *user_buf,
1165 size_t count, loff_t *ppos)
1166{
1167 struct ath6kl *ar = file->private_data;
1168 char buf[16];
1169 int len;
1170
1171 len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.keepalive);
1172
1173 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1174}
1175
1176static ssize_t ath6kl_keepalive_write(struct file *file,
1177 const char __user *user_buf,
1178 size_t count, loff_t *ppos)
1179{
1180 struct ath6kl *ar = file->private_data;
1181 int ret;
1182 u8 val;
1183
1184 ret = kstrtou8_from_user(user_buf, count, 0, &val);
1185 if (ret)
1186 return ret;
1187
Vasanthakumar Thiagarajan0ce59442011-10-25 19:34:25 +05301188 ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, 0, val);
Jouni Malinenff0b0072011-10-11 17:31:56 +03001189 if (ret)
1190 return ret;
1191
1192 return count;
1193}
1194
1195static const struct file_operations fops_keepalive = {
1196 .open = ath6kl_debugfs_open,
1197 .read = ath6kl_keepalive_read,
1198 .write = ath6kl_keepalive_write,
1199 .owner = THIS_MODULE,
1200 .llseek = default_llseek,
1201};
1202
1203void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout)
1204{
1205 ar->debug.disc_timeout = timeout;
1206}
1207
1208static ssize_t ath6kl_disconnect_timeout_read(struct file *file,
1209 char __user *user_buf,
1210 size_t count, loff_t *ppos)
1211{
1212 struct ath6kl *ar = file->private_data;
1213 char buf[16];
1214 int len;
1215
1216 len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.disc_timeout);
1217
1218 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1219}
1220
1221static ssize_t ath6kl_disconnect_timeout_write(struct file *file,
1222 const char __user *user_buf,
1223 size_t count, loff_t *ppos)
1224{
1225 struct ath6kl *ar = file->private_data;
1226 int ret;
1227 u8 val;
1228
1229 ret = kstrtou8_from_user(user_buf, count, 0, &val);
1230 if (ret)
1231 return ret;
1232
Vasanthakumar Thiagarajan0ce59442011-10-25 19:34:25 +05301233 ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, 0, val);
Jouni Malinenff0b0072011-10-11 17:31:56 +03001234 if (ret)
1235 return ret;
1236
1237 return count;
1238}
1239
1240static const struct file_operations fops_disconnect_timeout = {
1241 .open = ath6kl_debugfs_open,
1242 .read = ath6kl_disconnect_timeout_read,
1243 .write = ath6kl_disconnect_timeout_write,
1244 .owner = THIS_MODULE,
1245 .llseek = default_llseek,
1246};
1247
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001248static ssize_t ath6kl_create_qos_write(struct file *file,
1249 const char __user *user_buf,
1250 size_t count, loff_t *ppos)
1251{
1252
1253 struct ath6kl *ar = file->private_data;
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301254 struct ath6kl_vif *vif;
Vasanthakumar Thiagarajan8cb6d992011-11-04 18:34:55 +05301255 char buf[200];
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001256 ssize_t len;
1257 char *sptr, *token;
1258 struct wmi_create_pstream_cmd pstream;
1259 u32 val32;
1260 u16 val16;
1261
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301262 vif = ath6kl_vif_first(ar);
1263 if (!vif)
1264 return -EIO;
1265
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001266 len = min(count, sizeof(buf) - 1);
1267 if (copy_from_user(buf, user_buf, len))
1268 return -EFAULT;
1269 buf[len] = '\0';
1270 sptr = buf;
1271
1272 token = strsep(&sptr, " ");
1273 if (!token)
1274 return -EINVAL;
1275 if (kstrtou8(token, 0, &pstream.user_pri))
1276 return -EINVAL;
1277
1278 token = strsep(&sptr, " ");
1279 if (!token)
1280 return -EINVAL;
1281 if (kstrtou8(token, 0, &pstream.traffic_direc))
1282 return -EINVAL;
1283
1284 token = strsep(&sptr, " ");
1285 if (!token)
1286 return -EINVAL;
1287 if (kstrtou8(token, 0, &pstream.traffic_class))
1288 return -EINVAL;
1289
1290 token = strsep(&sptr, " ");
1291 if (!token)
1292 return -EINVAL;
1293 if (kstrtou8(token, 0, &pstream.traffic_type))
1294 return -EINVAL;
1295
1296 token = strsep(&sptr, " ");
1297 if (!token)
1298 return -EINVAL;
1299 if (kstrtou8(token, 0, &pstream.voice_psc_cap))
1300 return -EINVAL;
1301
1302 token = strsep(&sptr, " ");
1303 if (!token)
1304 return -EINVAL;
1305 if (kstrtou32(token, 0, &val32))
1306 return -EINVAL;
1307 pstream.min_service_int = cpu_to_le32(val32);
1308
1309 token = strsep(&sptr, " ");
1310 if (!token)
1311 return -EINVAL;
1312 if (kstrtou32(token, 0, &val32))
1313 return -EINVAL;
1314 pstream.max_service_int = cpu_to_le32(val32);
1315
1316 token = strsep(&sptr, " ");
1317 if (!token)
1318 return -EINVAL;
1319 if (kstrtou32(token, 0, &val32))
1320 return -EINVAL;
1321 pstream.inactivity_int = cpu_to_le32(val32);
1322
1323 token = strsep(&sptr, " ");
1324 if (!token)
1325 return -EINVAL;
1326 if (kstrtou32(token, 0, &val32))
1327 return -EINVAL;
1328 pstream.suspension_int = cpu_to_le32(val32);
1329
1330 token = strsep(&sptr, " ");
1331 if (!token)
1332 return -EINVAL;
1333 if (kstrtou32(token, 0, &val32))
1334 return -EINVAL;
1335 pstream.service_start_time = cpu_to_le32(val32);
1336
1337 token = strsep(&sptr, " ");
1338 if (!token)
1339 return -EINVAL;
1340 if (kstrtou8(token, 0, &pstream.tsid))
1341 return -EINVAL;
1342
1343 token = strsep(&sptr, " ");
1344 if (!token)
1345 return -EINVAL;
1346 if (kstrtou16(token, 0, &val16))
1347 return -EINVAL;
1348 pstream.nominal_msdu = cpu_to_le16(val16);
1349
1350 token = strsep(&sptr, " ");
1351 if (!token)
1352 return -EINVAL;
1353 if (kstrtou16(token, 0, &val16))
1354 return -EINVAL;
1355 pstream.max_msdu = cpu_to_le16(val16);
1356
1357 token = strsep(&sptr, " ");
1358 if (!token)
1359 return -EINVAL;
1360 if (kstrtou32(token, 0, &val32))
1361 return -EINVAL;
1362 pstream.min_data_rate = cpu_to_le32(val32);
1363
1364 token = strsep(&sptr, " ");
1365 if (!token)
1366 return -EINVAL;
1367 if (kstrtou32(token, 0, &val32))
1368 return -EINVAL;
1369 pstream.mean_data_rate = cpu_to_le32(val32);
1370
1371 token = strsep(&sptr, " ");
1372 if (!token)
1373 return -EINVAL;
1374 if (kstrtou32(token, 0, &val32))
1375 return -EINVAL;
1376 pstream.peak_data_rate = cpu_to_le32(val32);
1377
1378 token = strsep(&sptr, " ");
1379 if (!token)
1380 return -EINVAL;
1381 if (kstrtou32(token, 0, &val32))
1382 return -EINVAL;
1383 pstream.max_burst_size = cpu_to_le32(val32);
1384
1385 token = strsep(&sptr, " ");
1386 if (!token)
1387 return -EINVAL;
1388 if (kstrtou32(token, 0, &val32))
1389 return -EINVAL;
1390 pstream.delay_bound = cpu_to_le32(val32);
1391
1392 token = strsep(&sptr, " ");
1393 if (!token)
1394 return -EINVAL;
1395 if (kstrtou32(token, 0, &val32))
1396 return -EINVAL;
1397 pstream.min_phy_rate = cpu_to_le32(val32);
1398
1399 token = strsep(&sptr, " ");
1400 if (!token)
1401 return -EINVAL;
1402 if (kstrtou32(token, 0, &val32))
1403 return -EINVAL;
1404 pstream.sba = cpu_to_le32(val32);
1405
1406 token = strsep(&sptr, " ");
1407 if (!token)
1408 return -EINVAL;
1409 if (kstrtou32(token, 0, &val32))
1410 return -EINVAL;
1411 pstream.medium_time = cpu_to_le32(val32);
1412
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301413 ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream);
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001414
1415 return count;
1416}
1417
1418static const struct file_operations fops_create_qos = {
1419 .write = ath6kl_create_qos_write,
1420 .open = ath6kl_debugfs_open,
1421 .owner = THIS_MODULE,
1422 .llseek = default_llseek,
1423};
1424
1425static ssize_t ath6kl_delete_qos_write(struct file *file,
1426 const char __user *user_buf,
1427 size_t count, loff_t *ppos)
1428{
1429
1430 struct ath6kl *ar = file->private_data;
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301431 struct ath6kl_vif *vif;
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001432 char buf[100];
1433 ssize_t len;
1434 char *sptr, *token;
1435 u8 traffic_class;
1436 u8 tsid;
1437
Vasanthakumar Thiagarajan990bd912011-10-25 19:34:20 +05301438 vif = ath6kl_vif_first(ar);
1439 if (!vif)
1440 return -EIO;
1441
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001442 len = min(count, sizeof(buf) - 1);
1443 if (copy_from_user(buf, user_buf, len))
1444 return -EFAULT;
1445 buf[len] = '\0';
1446 sptr = buf;
1447
1448 token = strsep(&sptr, " ");
1449 if (!token)
1450 return -EINVAL;
1451 if (kstrtou8(token, 0, &traffic_class))
1452 return -EINVAL;
1453
1454 token = strsep(&sptr, " ");
1455 if (!token)
1456 return -EINVAL;
1457 if (kstrtou8(token, 0, &tsid))
1458 return -EINVAL;
1459
Vasanthakumar Thiagarajan240d2792011-10-25 19:34:13 +05301460 ath6kl_wmi_delete_pstream_cmd(ar->wmi, vif->fw_vif_idx,
1461 traffic_class, tsid);
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001462
1463 return count;
1464}
1465
1466static const struct file_operations fops_delete_qos = {
1467 .write = ath6kl_delete_qos_write,
1468 .open = ath6kl_debugfs_open,
1469 .owner = THIS_MODULE,
1470 .llseek = default_llseek,
1471};
1472
Rishi Panjwani116b3a22011-10-18 17:20:06 -07001473static ssize_t ath6kl_bgscan_int_write(struct file *file,
1474 const char __user *user_buf,
1475 size_t count, loff_t *ppos)
1476{
1477 struct ath6kl *ar = file->private_data;
1478 u16 bgscan_int;
1479 char buf[32];
1480 ssize_t len;
1481
1482 len = min(count, sizeof(buf) - 1);
1483 if (copy_from_user(buf, user_buf, len))
1484 return -EFAULT;
1485
1486 buf[len] = '\0';
1487 if (kstrtou16(buf, 0, &bgscan_int))
1488 return -EINVAL;
1489
1490 if (bgscan_int == 0)
1491 bgscan_int = 0xffff;
1492
Vasanthakumar Thiagarajan334234b2011-10-25 19:34:12 +05301493 ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
Rishi Panjwani116b3a22011-10-18 17:20:06 -07001494 0, 0, 0);
1495
1496 return count;
1497}
1498
1499static const struct file_operations fops_bgscan_int = {
1500 .write = ath6kl_bgscan_int_write,
1501 .open = ath6kl_debugfs_open,
1502 .owner = THIS_MODULE,
1503 .llseek = default_llseek,
1504};
1505
Rishi Panjwanief8f0eb2011-10-25 17:26:29 -07001506static ssize_t ath6kl_listen_int_write(struct file *file,
1507 const char __user *user_buf,
1508 size_t count, loff_t *ppos)
1509{
1510 struct ath6kl *ar = file->private_data;
1511 u16 listen_int_t, listen_int_b;
1512 char buf[32];
1513 char *sptr, *token;
1514 ssize_t len;
1515
1516 len = min(count, sizeof(buf) - 1);
1517 if (copy_from_user(buf, user_buf, len))
1518 return -EFAULT;
1519
1520 buf[len] = '\0';
1521 sptr = buf;
1522
1523 token = strsep(&sptr, " ");
1524 if (!token)
1525 return -EINVAL;
1526
1527 if (kstrtou16(token, 0, &listen_int_t))
1528 return -EINVAL;
1529
1530 if (kstrtou16(sptr, 0, &listen_int_b))
1531 return -EINVAL;
1532
1533 if ((listen_int_t < 15) || (listen_int_t > 5000))
1534 return -EINVAL;
1535
1536 if ((listen_int_b < 1) || (listen_int_b > 50))
1537 return -EINVAL;
1538
1539 ar->listen_intvl_t = listen_int_t;
1540 ar->listen_intvl_b = listen_int_b;
1541
1542 ath6kl_wmi_listeninterval_cmd(ar->wmi, 0, ar->listen_intvl_t,
1543 ar->listen_intvl_b);
1544
1545 return count;
1546}
1547
1548static ssize_t ath6kl_listen_int_read(struct file *file,
1549 char __user *user_buf,
1550 size_t count, loff_t *ppos)
1551{
1552 struct ath6kl *ar = file->private_data;
1553 char buf[16];
1554 int len;
1555
1556 len = snprintf(buf, sizeof(buf), "%u %u\n", ar->listen_intvl_t,
1557 ar->listen_intvl_b);
1558
1559 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1560}
1561
1562static const struct file_operations fops_listen_int = {
1563 .read = ath6kl_listen_int_read,
1564 .write = ath6kl_listen_int_write,
1565 .open = ath6kl_debugfs_open,
1566 .owner = THIS_MODULE,
1567 .llseek = default_llseek,
1568};
1569
Rishi Panjwania24fc7c2011-10-25 19:52:41 -07001570static ssize_t ath6kl_power_params_write(struct file *file,
1571 const char __user *user_buf,
1572 size_t count, loff_t *ppos)
1573{
1574 struct ath6kl *ar = file->private_data;
1575 u8 buf[100];
1576 unsigned int len = 0;
1577 char *sptr, *token;
1578 u16 idle_period, ps_poll_num, dtim,
1579 tx_wakeup, num_tx;
1580
1581 len = min(count, sizeof(buf) - 1);
1582 if (copy_from_user(buf, user_buf, len))
1583 return -EFAULT;
1584 buf[len] = '\0';
1585 sptr = buf;
1586
1587 token = strsep(&sptr, " ");
1588 if (!token)
1589 return -EINVAL;
1590 if (kstrtou16(token, 0, &idle_period))
1591 return -EINVAL;
1592
1593 token = strsep(&sptr, " ");
1594 if (!token)
1595 return -EINVAL;
1596 if (kstrtou16(token, 0, &ps_poll_num))
1597 return -EINVAL;
1598
1599 token = strsep(&sptr, " ");
1600 if (!token)
1601 return -EINVAL;
1602 if (kstrtou16(token, 0, &dtim))
1603 return -EINVAL;
1604
1605 token = strsep(&sptr, " ");
1606 if (!token)
1607 return -EINVAL;
1608 if (kstrtou16(token, 0, &tx_wakeup))
1609 return -EINVAL;
1610
1611 token = strsep(&sptr, " ");
1612 if (!token)
1613 return -EINVAL;
1614 if (kstrtou16(token, 0, &num_tx))
1615 return -EINVAL;
1616
1617 ath6kl_wmi_pmparams_cmd(ar->wmi, 0, idle_period, ps_poll_num,
1618 dtim, tx_wakeup, num_tx, 0);
1619
1620 return count;
1621}
1622
1623static const struct file_operations fops_power_params = {
1624 .write = ath6kl_power_params_write,
1625 .open = ath6kl_debugfs_open,
1626 .owner = THIS_MODULE,
1627 .llseek = default_llseek,
1628};
1629
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +05301630int ath6kl_debug_init(struct ath6kl *ar)
1631{
Kalle Valobdf53962011-09-02 10:32:04 +03001632 ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
1633 if (ar->debug.fwlog_buf.buf == NULL)
1634 return -ENOMEM;
1635
1636 ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
1637 if (ar->debug.fwlog_tmp == NULL) {
1638 vfree(ar->debug.fwlog_buf.buf);
1639 return -ENOMEM;
1640 }
1641
1642 spin_lock_init(&ar->debug.fwlog_lock);
1643
Kalle Valo939f1cc2011-09-02 10:32:04 +03001644 /*
1645 * Actually we are lying here but don't know how to read the mask
1646 * value from the firmware.
1647 */
1648 ar->debug.fwlog_mask = 0;
1649
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +05301650 ar->debugfs_phy = debugfs_create_dir("ath6kl",
Vasanthakumar Thiagarajanbe98e3a2011-10-25 19:33:57 +05301651 ar->wiphy->debugfsdir);
Kalle Valobdf53962011-09-02 10:32:04 +03001652 if (!ar->debugfs_phy) {
1653 vfree(ar->debug.fwlog_buf.buf);
1654 kfree(ar->debug.fwlog_tmp);
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +05301655 return -ENOMEM;
Kalle Valobdf53962011-09-02 10:32:04 +03001656 }
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +05301657
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +05301658 debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
1659 &fops_tgt_stats);
1660
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +05301661 debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
1662 &fops_credit_dist_stats);
1663
Jouni Malinene8091282011-10-11 17:31:53 +03001664 debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR,
1665 ar->debugfs_phy, ar, &fops_endpoint_stats);
1666
Kalle Valobdf53962011-09-02 10:32:04 +03001667 debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
1668 &fops_fwlog);
1669
Kalle Valo939f1cc2011-09-02 10:32:04 +03001670 debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy,
1671 ar, &fops_fwlog_mask);
1672
Vasanthakumar Thiagarajan91d57de2011-09-02 10:40:06 +03001673 debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
1674 &fops_diag_reg_read);
1675
1676 debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar,
1677 &fops_reg_dump);
1678
Vivek Natarajane5090442011-08-31 15:02:19 +05301679 debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR,
1680 ar->debugfs_phy, ar, &fops_lrssi_roam_threshold);
Vasanthakumar Thiagarajan252c0682011-09-05 11:19:46 +03001681
1682 debugfs_create_file("reg_write", S_IRUSR | S_IWUSR,
1683 ar->debugfs_phy, ar, &fops_diag_reg_write);
1684
Kalle Valo9a730832011-09-27 23:33:28 +03001685 debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar,
1686 &fops_war_stats);
1687
Jouni Malinen4b28a802011-10-11 17:31:54 +03001688 debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar,
1689 &fops_roam_table);
1690
Jouni Malinen12618752011-10-11 17:31:55 +03001691 debugfs_create_file("force_roam", S_IWUSR, ar->debugfs_phy, ar,
1692 &fops_force_roam);
1693
1694 debugfs_create_file("roam_mode", S_IWUSR, ar->debugfs_phy, ar,
1695 &fops_roam_mode);
1696
Jouni Malinenff0b0072011-10-11 17:31:56 +03001697 debugfs_create_file("keepalive", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar,
1698 &fops_keepalive);
1699
1700 debugfs_create_file("disconnect_timeout", S_IRUSR | S_IWUSR,
1701 ar->debugfs_phy, ar, &fops_disconnect_timeout);
1702
Rishi Panjwani8fffd9e2011-10-14 17:48:07 -07001703 debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar,
1704 &fops_create_qos);
1705
1706 debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar,
1707 &fops_delete_qos);
1708
Rishi Panjwani116b3a22011-10-18 17:20:06 -07001709 debugfs_create_file("bgscan_interval", S_IWUSR,
1710 ar->debugfs_phy, ar, &fops_bgscan_int);
1711
Rishi Panjwania24fc7c2011-10-25 19:52:41 -07001712 debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar,
1713 &fops_power_params);
1714
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +05301715 return 0;
1716}
Kalle Valobdf53962011-09-02 10:32:04 +03001717
1718void ath6kl_debug_cleanup(struct ath6kl *ar)
1719{
1720 vfree(ar->debug.fwlog_buf.buf);
1721 kfree(ar->debug.fwlog_tmp);
Jouni Malinen4b28a802011-10-11 17:31:54 +03001722 kfree(ar->debug.roam_tbl);
Kalle Valobdf53962011-09-02 10:32:04 +03001723}
1724
Kalle Valobdcd8172011-07-18 00:22:30 +03001725#endif