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