blob: b2706da581492e35e61fdde346cf977df393317c [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>
20
Kalle Valobdcd8172011-07-18 00:22:30 +030021#include "debug.h"
Kalle Valobdf53962011-09-02 10:32:04 +030022#include "target.h"
23
24struct ath6kl_fwlog_slot {
25 __le32 timestamp;
26 __le32 length;
27
28 /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
29 u8 payload[0];
30};
31
32#define ATH6KL_FWLOG_SIZE 32768
33#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
34 ATH6KL_FWLOG_PAYLOAD_SIZE)
Kalle Valobdcd8172011-07-18 00:22:30 +030035
36int ath6kl_printk(const char *level, const char *fmt, ...)
37{
38 struct va_format vaf;
39 va_list args;
40 int rtn;
41
42 va_start(args, fmt);
43
44 vaf.fmt = fmt;
45 vaf.va = &args;
46
47 rtn = printk("%sath6kl: %pV", level, &vaf);
48
49 va_end(args);
50
51 return rtn;
52}
53
54#ifdef CONFIG_ATH6KL_DEBUG
55void ath6kl_dump_registers(struct ath6kl_device *dev,
56 struct ath6kl_irq_proc_registers *irq_proc_reg,
57 struct ath6kl_irq_enable_reg *irq_enable_reg)
58{
59
60 ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
61
62 if (irq_proc_reg != NULL) {
63 ath6kl_dbg(ATH6KL_DBG_ANY,
64 "Host Int status: 0x%x\n",
65 irq_proc_reg->host_int_status);
66 ath6kl_dbg(ATH6KL_DBG_ANY,
67 "CPU Int status: 0x%x\n",
68 irq_proc_reg->cpu_int_status);
69 ath6kl_dbg(ATH6KL_DBG_ANY,
70 "Error Int status: 0x%x\n",
71 irq_proc_reg->error_int_status);
72 ath6kl_dbg(ATH6KL_DBG_ANY,
73 "Counter Int status: 0x%x\n",
74 irq_proc_reg->counter_int_status);
75 ath6kl_dbg(ATH6KL_DBG_ANY,
76 "Mbox Frame: 0x%x\n",
77 irq_proc_reg->mbox_frame);
78 ath6kl_dbg(ATH6KL_DBG_ANY,
79 "Rx Lookahead Valid: 0x%x\n",
80 irq_proc_reg->rx_lkahd_valid);
81 ath6kl_dbg(ATH6KL_DBG_ANY,
82 "Rx Lookahead 0: 0x%x\n",
83 irq_proc_reg->rx_lkahd[0]);
84 ath6kl_dbg(ATH6KL_DBG_ANY,
85 "Rx Lookahead 1: 0x%x\n",
86 irq_proc_reg->rx_lkahd[1]);
87
88 if (dev->ar->mbox_info.gmbox_addr != 0) {
89 /*
90 * If the target supports GMBOX hardware, dump some
91 * additional state.
92 */
93 ath6kl_dbg(ATH6KL_DBG_ANY,
94 "GMBOX Host Int status 2: 0x%x\n",
95 irq_proc_reg->host_int_status2);
96 ath6kl_dbg(ATH6KL_DBG_ANY,
97 "GMBOX RX Avail: 0x%x\n",
98 irq_proc_reg->gmbox_rx_avail);
99 ath6kl_dbg(ATH6KL_DBG_ANY,
100 "GMBOX lookahead alias 0: 0x%x\n",
101 irq_proc_reg->rx_gmbox_lkahd_alias[0]);
102 ath6kl_dbg(ATH6KL_DBG_ANY,
103 "GMBOX lookahead alias 1: 0x%x\n",
104 irq_proc_reg->rx_gmbox_lkahd_alias[1]);
105 }
106
107 }
108
109 if (irq_enable_reg != NULL) {
110 ath6kl_dbg(ATH6KL_DBG_ANY,
111 "Int status Enable: 0x%x\n",
112 irq_enable_reg->int_status_en);
113 ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
114 irq_enable_reg->cntr_int_status_en);
115 }
116 ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
117}
118
119static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
120{
121 ath6kl_dbg(ATH6KL_DBG_ANY,
122 "--- endpoint: %d svc_id: 0x%X ---\n",
123 ep_dist->endpoint, ep_dist->svc_id);
124 ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n",
125 ep_dist->dist_flags);
126 ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n",
127 ep_dist->cred_norm);
128 ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n",
129 ep_dist->cred_min);
130 ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n",
131 ep_dist->credits);
132 ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n",
133 ep_dist->cred_assngd);
134 ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n",
135 ep_dist->seek_cred);
136 ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n",
137 ep_dist->cred_sz);
138 ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n",
139 ep_dist->cred_per_msg);
140 ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n",
141 ep_dist->cred_to_dist);
142 ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n",
143 get_queue_depth(&((struct htc_endpoint *)
144 ep_dist->htc_rsvd)->txq));
145 ath6kl_dbg(ATH6KL_DBG_ANY,
146 "----------------------------------\n");
147}
148
149void dump_cred_dist_stats(struct htc_target *target)
150{
151 struct htc_endpoint_credit_dist *ep_list;
152
153 if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
154 return;
155
156 list_for_each_entry(ep_list, &target->cred_dist_list, list)
157 dump_cred_dist(ep_list);
158
159 ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
160 target->cred_dist_cntxt, NULL);
161 ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
162 target->cred_dist_cntxt->total_avail_credits,
163 target->cred_dist_cntxt->cur_free_credits);
164}
165
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530166static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
167{
168 file->private_data = inode->i_private;
169 return 0;
170}
171
Kalle Valobdf53962011-09-02 10:32:04 +0300172static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf,
173 size_t buf_len)
174{
175 struct circ_buf *fwlog = &ar->debug.fwlog_buf;
176 size_t space;
177 int i;
178
179 /* entries must all be equal size */
180 if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
181 return;
182
183 space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE);
184 if (space < buf_len)
185 /* discard oldest slot */
186 fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
187 (ATH6KL_FWLOG_SIZE - 1);
188
189 for (i = 0; i < buf_len; i += space) {
190 space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail,
191 ATH6KL_FWLOG_SIZE);
192
193 if ((size_t) space > buf_len - i)
194 space = buf_len - i;
195
196 memcpy(&fwlog->buf[fwlog->head], buf, space);
197 fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1);
198 }
199
200}
201
202void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
203{
204 struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
205 size_t slot_len;
206
207 if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
208 return;
209
210 spin_lock_bh(&ar->debug.fwlog_lock);
211
212 slot->timestamp = cpu_to_le32(jiffies);
213 slot->length = cpu_to_le32(len);
214 memcpy(slot->payload, buf, len);
215
216 slot_len = sizeof(*slot) + len;
217
218 if (slot_len < ATH6KL_FWLOG_SLOT_SIZE)
219 memset(slot->payload + len, 0,
220 ATH6KL_FWLOG_SLOT_SIZE - slot_len);
221
222 ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE);
223
224 spin_unlock_bh(&ar->debug.fwlog_lock);
225}
226
227static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar)
228{
229 return CIRC_CNT(ar->debug.fwlog_buf.head,
230 ar->debug.fwlog_buf.tail,
231 ATH6KL_FWLOG_SLOT_SIZE) == 0;
232}
233
234static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
235 size_t count, loff_t *ppos)
236{
237 struct ath6kl *ar = file->private_data;
238 struct circ_buf *fwlog = &ar->debug.fwlog_buf;
239 size_t len = 0, buf_len = count;
240 ssize_t ret_cnt;
241 char *buf;
242 int ccnt;
243
244 buf = vmalloc(buf_len);
245 if (!buf)
246 return -ENOMEM;
247
248 spin_lock_bh(&ar->debug.fwlog_lock);
249
250 while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
251 ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail,
252 ATH6KL_FWLOG_SIZE);
253
254 if ((size_t) ccnt > buf_len - len)
255 ccnt = buf_len - len;
256
257 memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt);
258 len += ccnt;
259
260 fwlog->tail = (fwlog->tail + ccnt) &
261 (ATH6KL_FWLOG_SIZE - 1);
262 }
263
264 spin_unlock_bh(&ar->debug.fwlog_lock);
265
266 if (WARN_ON(len > buf_len))
267 len = buf_len;
268
269 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
270
271 vfree(buf);
272
273 return ret_cnt;
274}
275
276static const struct file_operations fops_fwlog = {
277 .open = ath6kl_debugfs_open,
278 .read = ath6kl_fwlog_read,
279 .owner = THIS_MODULE,
280 .llseek = default_llseek,
281};
282
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530283static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
284 size_t count, loff_t *ppos)
285{
286 struct ath6kl *ar = file->private_data;
287 struct target_stats *tgt_stats = &ar->target_stats;
288 char *buf;
289 unsigned int len = 0, buf_len = 1500;
290 int i;
291 long left;
292 ssize_t ret_cnt;
293
294 buf = kzalloc(buf_len, GFP_KERNEL);
295 if (!buf)
296 return -ENOMEM;
297
298 if (down_interruptible(&ar->sem)) {
299 kfree(buf);
300 return -EBUSY;
301 }
302
303 set_bit(STATS_UPDATE_PEND, &ar->flag);
304
305 if (ath6kl_wmi_get_stats_cmd(ar->wmi)) {
306 up(&ar->sem);
307 kfree(buf);
308 return -EIO;
309 }
310
311 left = wait_event_interruptible_timeout(ar->event_wq,
312 !test_bit(STATS_UPDATE_PEND,
313 &ar->flag), WMI_TIMEOUT);
314
315 up(&ar->sem);
316
317 if (left <= 0) {
318 kfree(buf);
319 return -ETIMEDOUT;
320 }
321
322 len += scnprintf(buf + len, buf_len - len, "\n");
323 len += scnprintf(buf + len, buf_len - len, "%25s\n",
324 "Target Tx stats");
325 len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
326 "=================");
327 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
328 "Ucast packets", tgt_stats->tx_ucast_pkt);
329 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
330 "Bcast packets", tgt_stats->tx_bcast_pkt);
331 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
332 "Ucast byte", tgt_stats->tx_ucast_byte);
333 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
334 "Bcast byte", tgt_stats->tx_bcast_byte);
335 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
336 "Rts success cnt", tgt_stats->tx_rts_success_cnt);
337 for (i = 0; i < 4; i++)
338 len += scnprintf(buf + len, buf_len - len,
339 "%18s %d %10llu\n", "PER on ac",
340 i, tgt_stats->tx_pkt_per_ac[i]);
341 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
342 "Error", tgt_stats->tx_err);
343 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
344 "Fail count", tgt_stats->tx_fail_cnt);
345 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
346 "Retry count", tgt_stats->tx_retry_cnt);
347 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
348 "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
349 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
350 "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
351 len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
352 "TKIP counter measure used",
353 tgt_stats->tkip_cnter_measures_invoked);
354
355 len += scnprintf(buf + len, buf_len - len, "%25s\n",
356 "Target Rx stats");
357 len += scnprintf(buf + len, buf_len - len, "%25s\n",
358 "=================");
359
360 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
361 "Ucast packets", tgt_stats->rx_ucast_pkt);
362 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
363 "Ucast Rate", tgt_stats->rx_ucast_rate);
364 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
365 "Bcast packets", tgt_stats->rx_bcast_pkt);
366 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
367 "Ucast byte", tgt_stats->rx_ucast_byte);
368 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
369 "Bcast byte", tgt_stats->rx_bcast_byte);
370 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
371 "Fragmented pkt", tgt_stats->rx_frgment_pkt);
372 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
373 "Error", tgt_stats->rx_err);
374 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
375 "CRC Err", tgt_stats->rx_crc_err);
376 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
377 "Key chache miss", tgt_stats->rx_key_cache_miss);
378 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
379 "Decrypt Err", tgt_stats->rx_decrypt_err);
380 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
381 "Duplicate frame", tgt_stats->rx_dupl_frame);
382 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
383 "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
384 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
385 "TKIP format err", tgt_stats->tkip_fmt_err);
386 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
387 "CCMP format Err", tgt_stats->ccmp_fmt_err);
388 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
389 "CCMP Replay Err", tgt_stats->ccmp_replays);
390
391 len += scnprintf(buf + len, buf_len - len, "%25s\n",
392 "Misc Target stats");
393 len += scnprintf(buf + len, buf_len - len, "%25s\n",
394 "=================");
395 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
396 "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
397 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
398 "Num Connects", tgt_stats->cs_connect_cnt);
399 len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
400 "Num disconnects", tgt_stats->cs_discon_cnt);
401 len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
402 "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
403
404 if (len > buf_len)
405 len = buf_len;
406
407 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
408
409 kfree(buf);
410 return ret_cnt;
411}
412
413static const struct file_operations fops_tgt_stats = {
414 .read = read_file_tgt_stats,
415 .open = ath6kl_debugfs_open,
416 .owner = THIS_MODULE,
417 .llseek = default_llseek,
418};
419
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +0530420#define print_credit_info(fmt_str, ep_list_field) \
421 (len += scnprintf(buf + len, buf_len - len, fmt_str, \
422 ep_list->ep_list_field))
423#define CREDIT_INFO_DISPLAY_STRING_LEN 200
424#define CREDIT_INFO_LEN 128
425
426static ssize_t read_file_credit_dist_stats(struct file *file,
427 char __user *user_buf,
428 size_t count, loff_t *ppos)
429{
430 struct ath6kl *ar = file->private_data;
431 struct htc_target *target = ar->htc_target;
432 struct htc_endpoint_credit_dist *ep_list;
433 char *buf;
434 unsigned int buf_len, len = 0;
435 ssize_t ret_cnt;
436
437 buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
438 get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
439 buf = kzalloc(buf_len, GFP_KERNEL);
440 if (!buf)
441 return -ENOMEM;
442
443 len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
444 "Total Avail Credits: ",
445 target->cred_dist_cntxt->total_avail_credits);
446 len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
447 "Free credits :",
448 target->cred_dist_cntxt->cur_free_credits);
449
450 len += scnprintf(buf + len, buf_len - len,
451 " Epid Flags Cred_norm Cred_min Credits Cred_assngd"
452 " Seek_cred Cred_sz Cred_per_msg Cred_to_dist"
453 " qdepth\n");
454
455 list_for_each_entry(ep_list, &target->cred_dist_list, list) {
456 print_credit_info(" %2d", endpoint);
457 print_credit_info("%10x", dist_flags);
458 print_credit_info("%8d", cred_norm);
459 print_credit_info("%9d", cred_min);
460 print_credit_info("%9d", credits);
461 print_credit_info("%10d", cred_assngd);
462 print_credit_info("%13d", seek_cred);
463 print_credit_info("%12d", cred_sz);
464 print_credit_info("%9d", cred_per_msg);
465 print_credit_info("%14d", cred_to_dist);
466 len += scnprintf(buf + len, buf_len - len, "%12d\n",
467 get_queue_depth(&((struct htc_endpoint *)
468 ep_list->htc_rsvd)->txq));
469 }
470
471 if (len > buf_len)
472 len = buf_len;
473
474 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
475 kfree(buf);
476 return ret_cnt;
477}
478
479static const struct file_operations fops_credit_dist_stats = {
480 .read = read_file_credit_dist_stats,
481 .open = ath6kl_debugfs_open,
482 .owner = THIS_MODULE,
483 .llseek = default_llseek,
484};
485
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +0530486int ath6kl_debug_init(struct ath6kl *ar)
487{
Kalle Valobdf53962011-09-02 10:32:04 +0300488 ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
489 if (ar->debug.fwlog_buf.buf == NULL)
490 return -ENOMEM;
491
492 ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
493 if (ar->debug.fwlog_tmp == NULL) {
494 vfree(ar->debug.fwlog_buf.buf);
495 return -ENOMEM;
496 }
497
498 spin_lock_init(&ar->debug.fwlog_lock);
499
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +0530500 ar->debugfs_phy = debugfs_create_dir("ath6kl",
501 ar->wdev->wiphy->debugfsdir);
Kalle Valobdf53962011-09-02 10:32:04 +0300502 if (!ar->debugfs_phy) {
503 vfree(ar->debug.fwlog_buf.buf);
504 kfree(ar->debug.fwlog_tmp);
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +0530505 return -ENOMEM;
Kalle Valobdf53962011-09-02 10:32:04 +0300506 }
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +0530507
Vasanthakumar Thiagarajan03f68a92011-08-26 13:06:32 +0530508 debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
509 &fops_tgt_stats);
510
Vasanthakumar Thiagarajan78fc4852011-08-26 13:06:33 +0530511 debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
512 &fops_credit_dist_stats);
513
Kalle Valobdf53962011-09-02 10:32:04 +0300514 debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
515 &fops_fwlog);
516
Vasanthakumar Thiagarajand999ba32011-08-26 13:06:31 +0530517 return 0;
518}
Kalle Valobdf53962011-09-02 10:32:04 +0300519
520void ath6kl_debug_cleanup(struct ath6kl *ar)
521{
522 vfree(ar->debug.fwlog_buf.buf);
523 kfree(ar->debug.fwlog_tmp);
524}
525
Kalle Valobdcd8172011-07-18 00:22:30 +0300526#endif