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