1 /* 2 * Copyright (c) 2012-2014 Qualcomm Atheros, 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 <linux/module.h> 18 #include <linux/debugfs.h> 19 #include <linux/seq_file.h> 20 #include <linux/pci.h> 21 #include <linux/rtnetlink.h> 22 #include <linux/power_supply.h> 23 24 #include "wil6210.h" 25 #include "wmi.h" 26 #include "txrx.h" 27 28 /* Nasty hack. Better have per device instances */ 29 static u32 mem_addr; 30 static u32 dbg_txdesc_index; 31 static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ 32 u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */ 33 34 enum dbg_off_type { 35 doff_u32 = 0, 36 doff_x32 = 1, 37 doff_ulong = 2, 38 doff_io32 = 3, 39 }; 40 41 /* offset to "wil" */ 42 struct dbg_off { 43 const char *name; 44 umode_t mode; 45 ulong off; 46 enum dbg_off_type type; 47 }; 48 49 static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, 50 const char *name, struct vring *vring, 51 char _s, char _h) 52 { 53 void __iomem *x = wmi_addr(wil, vring->hwtail); 54 u32 v; 55 56 seq_printf(s, "VRING %s = {\n", name); 57 seq_printf(s, " pa = %pad\n", &vring->pa); 58 seq_printf(s, " va = 0x%p\n", vring->va); 59 seq_printf(s, " size = %d\n", vring->size); 60 seq_printf(s, " swtail = %d\n", vring->swtail); 61 seq_printf(s, " swhead = %d\n", vring->swhead); 62 seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); 63 if (x) { 64 v = ioread32(x); 65 seq_printf(s, "0x%08x = %d\n", v, v); 66 } else { 67 seq_puts(s, "???\n"); 68 } 69 70 if (vring->va && (vring->size < 1025)) { 71 uint i; 72 73 for (i = 0; i < vring->size; i++) { 74 volatile struct vring_tx_desc *d = &vring->va[i].tx; 75 76 if ((i % 64) == 0 && (i != 0)) 77 seq_puts(s, "\n"); 78 seq_printf(s, "%c", (d->dma.status & BIT(0)) ? 79 _s : (vring->ctx[i].skb ? _h : 'h')); 80 } 81 seq_puts(s, "\n"); 82 } 83 seq_puts(s, "}\n"); 84 } 85 86 static int wil_vring_debugfs_show(struct seq_file *s, void *data) 87 { 88 uint i; 89 struct wil6210_priv *wil = s->private; 90 91 wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); 92 93 for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { 94 struct vring *vring = &wil->vring_tx[i]; 95 struct vring_tx_data *txdata = &wil->vring_tx_data[i]; 96 97 if (vring->va) { 98 int cid = wil->vring2cid_tid[i][0]; 99 int tid = wil->vring2cid_tid[i][1]; 100 u32 swhead = vring->swhead; 101 u32 swtail = vring->swtail; 102 int used = (vring->size + swhead - swtail) 103 % vring->size; 104 int avail = vring->size - used - 1; 105 char name[10]; 106 char sidle[10]; 107 /* performance monitoring */ 108 cycles_t now = get_cycles(); 109 uint64_t idle = txdata->idle * 100; 110 uint64_t total = now - txdata->begin; 111 112 if (total != 0) { 113 do_div(idle, total); 114 snprintf(sidle, sizeof(sidle), "%3d%%", 115 (int)idle); 116 } else { 117 snprintf(sidle, sizeof(sidle), "N/A"); 118 } 119 txdata->begin = now; 120 txdata->idle = 0ULL; 121 122 snprintf(name, sizeof(name), "tx_%2d", i); 123 124 if (cid < WIL6210_MAX_CID) 125 seq_printf(s, 126 "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", 127 wil->sta[cid].addr, cid, tid, 128 txdata->agg_wsize, 129 txdata->agg_timeout, 130 txdata->agg_amsdu ? "+" : "-", 131 used, avail, sidle); 132 else 133 seq_printf(s, 134 "\nBroadcast [%3d|%3d] idle %s\n", 135 used, avail, sidle); 136 137 wil_print_vring(s, wil, name, vring, '_', 'H'); 138 } 139 } 140 141 return 0; 142 } 143 144 static int wil_vring_seq_open(struct inode *inode, struct file *file) 145 { 146 return single_open(file, wil_vring_debugfs_show, inode->i_private); 147 } 148 149 static const struct file_operations fops_vring = { 150 .open = wil_vring_seq_open, 151 .release = single_release, 152 .read = seq_read, 153 .llseek = seq_lseek, 154 }; 155 156 static void wil_print_ring(struct seq_file *s, const char *prefix, 157 void __iomem *off) 158 { 159 struct wil6210_priv *wil = s->private; 160 struct wil6210_mbox_ring r; 161 int rsize; 162 uint i; 163 164 wil_memcpy_fromio_32(&r, off, sizeof(r)); 165 wil_mbox_ring_le2cpus(&r); 166 /* 167 * we just read memory block from NIC. This memory may be 168 * garbage. Check validity before using it. 169 */ 170 rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); 171 172 seq_printf(s, "ring %s = {\n", prefix); 173 seq_printf(s, " base = 0x%08x\n", r.base); 174 seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); 175 seq_printf(s, " tail = 0x%08x\n", r.tail); 176 seq_printf(s, " head = 0x%08x\n", r.head); 177 seq_printf(s, " entry size = %d\n", r.entry_size); 178 179 if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { 180 seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", 181 sizeof(struct wil6210_mbox_ring_desc)); 182 goto out; 183 } 184 185 if (!wmi_addr(wil, r.base) || 186 !wmi_addr(wil, r.tail) || 187 !wmi_addr(wil, r.head)) { 188 seq_puts(s, " ??? pointers are garbage?\n"); 189 goto out; 190 } 191 192 for (i = 0; i < rsize; i++) { 193 struct wil6210_mbox_ring_desc d; 194 struct wil6210_mbox_hdr hdr; 195 size_t delta = i * sizeof(d); 196 void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; 197 198 wil_memcpy_fromio_32(&d, x, sizeof(d)); 199 200 seq_printf(s, " [%2x] %s %s%s 0x%08x", i, 201 d.sync ? "F" : "E", 202 (r.tail - r.base == delta) ? "t" : " ", 203 (r.head - r.base == delta) ? "h" : " ", 204 le32_to_cpu(d.addr)); 205 if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { 206 u16 len = le16_to_cpu(hdr.len); 207 208 seq_printf(s, " -> %04x %04x %04x %02x\n", 209 le16_to_cpu(hdr.seq), len, 210 le16_to_cpu(hdr.type), hdr.flags); 211 if (len <= MAX_MBOXITEM_SIZE) { 212 int n = 0; 213 char printbuf[16 * 3 + 2]; 214 unsigned char databuf[MAX_MBOXITEM_SIZE]; 215 void __iomem *src = wmi_buffer(wil, d.addr) + 216 sizeof(struct wil6210_mbox_hdr); 217 /* 218 * No need to check @src for validity - 219 * we already validated @d.addr while 220 * reading header 221 */ 222 wil_memcpy_fromio_32(databuf, src, len); 223 while (n < len) { 224 int l = min(len - n, 16); 225 226 hex_dump_to_buffer(databuf + n, l, 227 16, 1, printbuf, 228 sizeof(printbuf), 229 false); 230 seq_printf(s, " : %s\n", printbuf); 231 n += l; 232 } 233 } 234 } else { 235 seq_puts(s, "\n"); 236 } 237 } 238 out: 239 seq_puts(s, "}\n"); 240 } 241 242 static int wil_mbox_debugfs_show(struct seq_file *s, void *data) 243 { 244 struct wil6210_priv *wil = s->private; 245 246 wil_print_ring(s, "tx", wil->csr + HOST_MBOX + 247 offsetof(struct wil6210_mbox_ctl, tx)); 248 wil_print_ring(s, "rx", wil->csr + HOST_MBOX + 249 offsetof(struct wil6210_mbox_ctl, rx)); 250 251 return 0; 252 } 253 254 static int wil_mbox_seq_open(struct inode *inode, struct file *file) 255 { 256 return single_open(file, wil_mbox_debugfs_show, inode->i_private); 257 } 258 259 static const struct file_operations fops_mbox = { 260 .open = wil_mbox_seq_open, 261 .release = single_release, 262 .read = seq_read, 263 .llseek = seq_lseek, 264 }; 265 266 static int wil_debugfs_iomem_x32_set(void *data, u64 val) 267 { 268 iowrite32(val, (void __iomem *)data); 269 wmb(); /* make sure write propagated to HW */ 270 271 return 0; 272 } 273 274 static int wil_debugfs_iomem_x32_get(void *data, u64 *val) 275 { 276 *val = ioread32((void __iomem *)data); 277 278 return 0; 279 } 280 281 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, 282 wil_debugfs_iomem_x32_set, "0x%08llx\n"); 283 284 static struct dentry *wil_debugfs_create_iomem_x32(const char *name, 285 umode_t mode, 286 struct dentry *parent, 287 void *value) 288 { 289 return debugfs_create_file(name, mode, parent, value, 290 &fops_iomem_x32); 291 } 292 293 static int wil_debugfs_ulong_set(void *data, u64 val) 294 { 295 *(ulong *)data = val; 296 return 0; 297 } 298 299 static int wil_debugfs_ulong_get(void *data, u64 *val) 300 { 301 *val = *(ulong *)data; 302 return 0; 303 } 304 305 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, 306 wil_debugfs_ulong_set, "%llu\n"); 307 308 static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, 309 struct dentry *parent, 310 ulong *value) 311 { 312 return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); 313 } 314 315 /** 316 * wil6210_debugfs_init_offset - create set of debugfs files 317 * @wil - driver's context, used for printing 318 * @dbg - directory on the debugfs, where files will be created 319 * @base - base address used in address calculation 320 * @tbl - table with file descriptions. Should be terminated with empty element. 321 * 322 * Creates files accordingly to the @tbl. 323 */ 324 static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, 325 struct dentry *dbg, void *base, 326 const struct dbg_off * const tbl) 327 { 328 int i; 329 330 for (i = 0; tbl[i].name; i++) { 331 struct dentry *f; 332 333 switch (tbl[i].type) { 334 case doff_u32: 335 f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, 336 base + tbl[i].off); 337 break; 338 case doff_x32: 339 f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, 340 base + tbl[i].off); 341 break; 342 case doff_ulong: 343 f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode, 344 dbg, base + tbl[i].off); 345 break; 346 case doff_io32: 347 f = wil_debugfs_create_iomem_x32(tbl[i].name, 348 tbl[i].mode, dbg, 349 base + tbl[i].off); 350 break; 351 default: 352 f = ERR_PTR(-EINVAL); 353 } 354 if (IS_ERR_OR_NULL(f)) 355 wil_err(wil, "Create file \"%s\": err %ld\n", 356 tbl[i].name, PTR_ERR(f)); 357 } 358 } 359 360 static const struct dbg_off isr_off[] = { 361 {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32}, 362 {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32}, 363 {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32}, 364 {"ICS", S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32}, 365 {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32}, 366 {"IMS", S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32}, 367 {"IMC", S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32}, 368 {}, 369 }; 370 371 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, 372 const char *name, 373 struct dentry *parent, u32 off) 374 { 375 struct dentry *d = debugfs_create_dir(name, parent); 376 377 if (IS_ERR_OR_NULL(d)) 378 return -ENODEV; 379 380 wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off, 381 isr_off); 382 383 return 0; 384 } 385 386 static const struct dbg_off pseudo_isr_off[] = { 387 {"CAUSE", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32}, 388 {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32}, 389 {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32}, 390 {}, 391 }; 392 393 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, 394 struct dentry *parent) 395 { 396 struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); 397 398 if (IS_ERR_OR_NULL(d)) 399 return -ENODEV; 400 401 wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, 402 pseudo_isr_off); 403 404 return 0; 405 } 406 407 static const struct dbg_off lgc_itr_cnt_off[] = { 408 {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32}, 409 {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32}, 410 {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32}, 411 {}, 412 }; 413 414 static const struct dbg_off tx_itr_cnt_off[] = { 415 {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH), 416 doff_io32}, 417 {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA), 418 doff_io32}, 419 {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL), 420 doff_io32}, 421 {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH), 422 doff_io32}, 423 {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA), 424 doff_io32}, 425 {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL), 426 doff_io32}, 427 {}, 428 }; 429 430 static const struct dbg_off rx_itr_cnt_off[] = { 431 {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH), 432 doff_io32}, 433 {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA), 434 doff_io32}, 435 {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL), 436 doff_io32}, 437 {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH), 438 doff_io32}, 439 {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA), 440 doff_io32}, 441 {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL), 442 doff_io32}, 443 {}, 444 }; 445 446 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, 447 struct dentry *parent) 448 { 449 struct dentry *d, *dtx, *drx; 450 451 d = debugfs_create_dir("ITR_CNT", parent); 452 if (IS_ERR_OR_NULL(d)) 453 return -ENODEV; 454 455 dtx = debugfs_create_dir("TX", d); 456 drx = debugfs_create_dir("RX", d); 457 if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx)) 458 return -ENODEV; 459 460 wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, 461 lgc_itr_cnt_off); 462 463 wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr, 464 tx_itr_cnt_off); 465 466 wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr, 467 rx_itr_cnt_off); 468 return 0; 469 } 470 471 static int wil_memread_debugfs_show(struct seq_file *s, void *data) 472 { 473 struct wil6210_priv *wil = s->private; 474 void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); 475 476 if (a) 477 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); 478 else 479 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); 480 481 return 0; 482 } 483 484 static int wil_memread_seq_open(struct inode *inode, struct file *file) 485 { 486 return single_open(file, wil_memread_debugfs_show, inode->i_private); 487 } 488 489 static const struct file_operations fops_memread = { 490 .open = wil_memread_seq_open, 491 .release = single_release, 492 .read = seq_read, 493 .llseek = seq_lseek, 494 }; 495 496 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, 497 size_t count, loff_t *ppos) 498 { 499 enum { max_count = 4096 }; 500 struct debugfs_blob_wrapper *blob = file->private_data; 501 loff_t pos = *ppos; 502 size_t available = blob->size; 503 void *buf; 504 size_t ret; 505 506 if (pos < 0) 507 return -EINVAL; 508 509 if (pos >= available || !count) 510 return 0; 511 512 if (count > available - pos) 513 count = available - pos; 514 if (count > max_count) 515 count = max_count; 516 517 buf = kmalloc(count, GFP_KERNEL); 518 if (!buf) 519 return -ENOMEM; 520 521 wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data + 522 pos, count); 523 524 ret = copy_to_user(user_buf, buf, count); 525 kfree(buf); 526 if (ret == count) 527 return -EFAULT; 528 529 count -= ret; 530 *ppos = pos + count; 531 532 return count; 533 } 534 535 static const struct file_operations fops_ioblob = { 536 .read = wil_read_file_ioblob, 537 .open = simple_open, 538 .llseek = default_llseek, 539 }; 540 541 static 542 struct dentry *wil_debugfs_create_ioblob(const char *name, 543 umode_t mode, 544 struct dentry *parent, 545 struct debugfs_blob_wrapper *blob) 546 { 547 return debugfs_create_file(name, mode, parent, blob, &fops_ioblob); 548 } 549 550 /*---reset---*/ 551 static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, 552 size_t len, loff_t *ppos) 553 { 554 struct wil6210_priv *wil = file->private_data; 555 struct net_device *ndev = wil_to_ndev(wil); 556 557 /** 558 * BUG: 559 * this code does NOT sync device state with the rest of system 560 * use with care, debug only!!! 561 */ 562 rtnl_lock(); 563 dev_close(ndev); 564 ndev->flags &= ~IFF_UP; 565 rtnl_unlock(); 566 wil_reset(wil, true); 567 568 return len; 569 } 570 571 static const struct file_operations fops_reset = { 572 .write = wil_write_file_reset, 573 .open = simple_open, 574 }; 575 576 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ 577 static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, 578 size_t len, loff_t *ppos) 579 { 580 struct wil6210_priv *wil = file->private_data; 581 int rc; 582 long channel; 583 bool on; 584 585 char *kbuf = kmalloc(len + 1, GFP_KERNEL); 586 587 if (!kbuf) 588 return -ENOMEM; 589 if (copy_from_user(kbuf, buf, len)) { 590 kfree(kbuf); 591 return -EIO; 592 } 593 594 kbuf[len] = '\0'; 595 rc = kstrtol(kbuf, 0, &channel); 596 kfree(kbuf); 597 if (rc) 598 return rc; 599 600 if ((channel < 0) || (channel > 4)) { 601 wil_err(wil, "Invalid channel %ld\n", channel); 602 return -EINVAL; 603 } 604 on = !!channel; 605 606 if (on) { 607 rc = wmi_set_channel(wil, (int)channel); 608 if (rc) 609 return rc; 610 } 611 612 rc = wmi_rxon(wil, on); 613 if (rc) 614 return rc; 615 616 return len; 617 } 618 619 static const struct file_operations fops_rxon = { 620 .write = wil_write_file_rxon, 621 .open = simple_open, 622 }; 623 624 /* block ack control, write: 625 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA 626 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side 627 * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side 628 */ 629 static ssize_t wil_write_back(struct file *file, const char __user *buf, 630 size_t len, loff_t *ppos) 631 { 632 struct wil6210_priv *wil = file->private_data; 633 int rc; 634 char *kbuf = kmalloc(len + 1, GFP_KERNEL); 635 char cmd[9]; 636 int p1, p2, p3; 637 638 if (!kbuf) 639 return -ENOMEM; 640 641 rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 642 if (rc != len) { 643 kfree(kbuf); 644 return rc >= 0 ? -EIO : rc; 645 } 646 647 kbuf[len] = '\0'; 648 rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3); 649 kfree(kbuf); 650 651 if (rc < 0) 652 return rc; 653 if (rc < 2) 654 return -EINVAL; 655 656 if (0 == strcmp(cmd, "add")) { 657 if (rc < 3) { 658 wil_err(wil, "BACK: add require at least 2 params\n"); 659 return -EINVAL; 660 } 661 if (rc < 4) 662 p3 = 0; 663 wmi_addba(wil, p1, p2, p3); 664 } else if (0 == strcmp(cmd, "del_tx")) { 665 if (rc < 3) 666 p2 = WLAN_REASON_QSTA_LEAVE_QBSS; 667 wmi_delba_tx(wil, p1, p2); 668 } else if (0 == strcmp(cmd, "del_rx")) { 669 if (rc < 3) { 670 wil_err(wil, 671 "BACK: del_rx require at least 2 params\n"); 672 return -EINVAL; 673 } 674 if (rc < 4) 675 p3 = WLAN_REASON_QSTA_LEAVE_QBSS; 676 wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3); 677 } else { 678 wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); 679 return -EINVAL; 680 } 681 682 return len; 683 } 684 685 static ssize_t wil_read_back(struct file *file, char __user *user_buf, 686 size_t count, loff_t *ppos) 687 { 688 static const char text[] = "block ack control, write:\n" 689 " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n" 690 "If missing, <timeout> defaults to 0\n" 691 " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n" 692 " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n" 693 "If missing, <reason> set to \"STA_LEAVING\" (36)\n"; 694 695 return simple_read_from_buffer(user_buf, count, ppos, text, 696 sizeof(text)); 697 } 698 699 static const struct file_operations fops_back = { 700 .read = wil_read_back, 701 .write = wil_write_back, 702 .open = simple_open, 703 }; 704 705 /*---tx_mgmt---*/ 706 /* Write mgmt frame to this file to send it */ 707 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, 708 size_t len, loff_t *ppos) 709 { 710 struct wil6210_priv *wil = file->private_data; 711 struct wiphy *wiphy = wil_to_wiphy(wil); 712 struct wireless_dev *wdev = wil_to_wdev(wil); 713 struct cfg80211_mgmt_tx_params params; 714 int rc; 715 void *frame = kmalloc(len, GFP_KERNEL); 716 717 if (!frame) 718 return -ENOMEM; 719 720 if (copy_from_user(frame, buf, len)) { 721 kfree(frame); 722 return -EIO; 723 } 724 725 params.buf = frame; 726 params.len = len; 727 params.chan = wdev->preset_chandef.chan; 728 729 rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); 730 731 kfree(frame); 732 wil_info(wil, "%s() -> %d\n", __func__, rc); 733 734 return len; 735 } 736 737 static const struct file_operations fops_txmgmt = { 738 .write = wil_write_file_txmgmt, 739 .open = simple_open, 740 }; 741 742 /* Write WMI command (w/o mbox header) to this file to send it 743 * WMI starts from wil6210_mbox_hdr_wmi header 744 */ 745 static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, 746 size_t len, loff_t *ppos) 747 { 748 struct wil6210_priv *wil = file->private_data; 749 struct wil6210_mbox_hdr_wmi *wmi; 750 void *cmd; 751 int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi); 752 u16 cmdid; 753 int rc, rc1; 754 755 if (cmdlen <= 0) 756 return -EINVAL; 757 758 wmi = kmalloc(len, GFP_KERNEL); 759 if (!wmi) 760 return -ENOMEM; 761 762 rc = simple_write_to_buffer(wmi, len, ppos, buf, len); 763 if (rc < 0) { 764 kfree(wmi); 765 return rc; 766 } 767 768 cmd = &wmi[1]; 769 cmdid = le16_to_cpu(wmi->id); 770 771 rc1 = wmi_send(wil, cmdid, cmd, cmdlen); 772 kfree(wmi); 773 774 wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1); 775 776 return rc; 777 } 778 779 static const struct file_operations fops_wmi = { 780 .write = wil_write_file_wmi, 781 .open = simple_open, 782 }; 783 784 static void wil_seq_hexdump(struct seq_file *s, void *p, int len, 785 const char *prefix) 786 { 787 char printbuf[16 * 3 + 2]; 788 int i = 0; 789 790 while (i < len) { 791 int l = min(len - i, 16); 792 793 hex_dump_to_buffer(p + i, l, 16, 1, printbuf, 794 sizeof(printbuf), false); 795 seq_printf(s, "%s%s\n", prefix, printbuf); 796 i += l; 797 } 798 } 799 800 static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) 801 { 802 int i = 0; 803 int len = skb_headlen(skb); 804 void *p = skb->data; 805 int nr_frags = skb_shinfo(skb)->nr_frags; 806 807 seq_printf(s, " len = %d\n", len); 808 wil_seq_hexdump(s, p, len, " : "); 809 810 if (nr_frags) { 811 seq_printf(s, " nr_frags = %d\n", nr_frags); 812 for (i = 0; i < nr_frags; i++) { 813 const struct skb_frag_struct *frag = 814 &skb_shinfo(skb)->frags[i]; 815 816 len = skb_frag_size(frag); 817 p = skb_frag_address_safe(frag); 818 seq_printf(s, " [%2d] : len = %d\n", i, len); 819 wil_seq_hexdump(s, p, len, " : "); 820 } 821 } 822 } 823 824 /*---------Tx/Rx descriptor------------*/ 825 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) 826 { 827 struct wil6210_priv *wil = s->private; 828 struct vring *vring; 829 bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); 830 831 vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx; 832 833 if (!vring->va) { 834 if (tx) 835 seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); 836 else 837 seq_puts(s, "No Rx VRING\n"); 838 return 0; 839 } 840 841 if (dbg_txdesc_index < vring->size) { 842 /* use struct vring_tx_desc for Rx as well, 843 * only field used, .dma.length, is the same 844 */ 845 volatile struct vring_tx_desc *d = 846 &vring->va[dbg_txdesc_index].tx; 847 volatile u32 *u = (volatile u32 *)d; 848 struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; 849 850 if (tx) 851 seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, 852 dbg_txdesc_index); 853 else 854 seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); 855 seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", 856 u[0], u[1], u[2], u[3]); 857 seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", 858 u[4], u[5], u[6], u[7]); 859 seq_printf(s, " SKB = 0x%p\n", skb); 860 861 if (skb) { 862 skb_get(skb); 863 wil_seq_print_skb(s, skb); 864 kfree_skb(skb); 865 } 866 seq_puts(s, "}\n"); 867 } else { 868 if (tx) 869 seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", 870 dbg_vring_index, dbg_txdesc_index, 871 vring->size); 872 else 873 seq_printf(s, "RxDesc index (%d) >= size (%d)\n", 874 dbg_txdesc_index, vring->size); 875 } 876 877 return 0; 878 } 879 880 static int wil_txdesc_seq_open(struct inode *inode, struct file *file) 881 { 882 return single_open(file, wil_txdesc_debugfs_show, inode->i_private); 883 } 884 885 static const struct file_operations fops_txdesc = { 886 .open = wil_txdesc_seq_open, 887 .release = single_release, 888 .read = seq_read, 889 .llseek = seq_lseek, 890 }; 891 892 /*---------beamforming------------*/ 893 static char *wil_bfstatus_str(u32 status) 894 { 895 switch (status) { 896 case 0: 897 return "Failed"; 898 case 1: 899 return "OK"; 900 case 2: 901 return "Retrying"; 902 default: 903 return "??"; 904 } 905 } 906 907 static bool is_all_zeros(void * const x_, size_t sz) 908 { 909 /* if reply is all-0, ignore this CID */ 910 u32 *x = x_; 911 int n; 912 913 for (n = 0; n < sz / sizeof(*x); n++) 914 if (x[n]) 915 return false; 916 917 return true; 918 } 919 920 static int wil_bf_debugfs_show(struct seq_file *s, void *data) 921 { 922 int rc; 923 int i; 924 struct wil6210_priv *wil = s->private; 925 struct wmi_notify_req_cmd cmd = { 926 .interval_usec = 0, 927 }; 928 struct { 929 struct wil6210_mbox_hdr_wmi wmi; 930 struct wmi_notify_req_done_event evt; 931 } __packed reply; 932 933 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 934 u32 status; 935 936 cmd.cid = i; 937 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), 938 WMI_NOTIFY_REQ_DONE_EVENTID, &reply, 939 sizeof(reply), 20); 940 /* if reply is all-0, ignore this CID */ 941 if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt))) 942 continue; 943 944 status = le32_to_cpu(reply.evt.status); 945 seq_printf(s, "CID %d {\n" 946 " TSF = 0x%016llx\n" 947 " TxMCS = %2d TxTpt = %4d\n" 948 " SQI = %4d\n" 949 " Status = 0x%08x %s\n" 950 " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" 951 " Goodput(rx:tx) %4d:%4d\n" 952 "}\n", 953 i, 954 le64_to_cpu(reply.evt.tsf), 955 le16_to_cpu(reply.evt.bf_mcs), 956 le32_to_cpu(reply.evt.tx_tpt), 957 reply.evt.sqi, 958 status, wil_bfstatus_str(status), 959 le16_to_cpu(reply.evt.my_rx_sector), 960 le16_to_cpu(reply.evt.my_tx_sector), 961 le16_to_cpu(reply.evt.other_rx_sector), 962 le16_to_cpu(reply.evt.other_tx_sector), 963 le32_to_cpu(reply.evt.rx_goodput), 964 le32_to_cpu(reply.evt.tx_goodput)); 965 } 966 return 0; 967 } 968 969 static int wil_bf_seq_open(struct inode *inode, struct file *file) 970 { 971 return single_open(file, wil_bf_debugfs_show, inode->i_private); 972 } 973 974 static const struct file_operations fops_bf = { 975 .open = wil_bf_seq_open, 976 .release = single_release, 977 .read = seq_read, 978 .llseek = seq_lseek, 979 }; 980 981 /*---------SSID------------*/ 982 static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf, 983 size_t count, loff_t *ppos) 984 { 985 struct wil6210_priv *wil = file->private_data; 986 struct wireless_dev *wdev = wil_to_wdev(wil); 987 988 return simple_read_from_buffer(user_buf, count, ppos, 989 wdev->ssid, wdev->ssid_len); 990 } 991 992 static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf, 993 size_t count, loff_t *ppos) 994 { 995 struct wil6210_priv *wil = file->private_data; 996 struct wireless_dev *wdev = wil_to_wdev(wil); 997 struct net_device *ndev = wil_to_ndev(wil); 998 999 if (*ppos != 0) { 1000 wil_err(wil, "Unable to set SSID substring from [%d]\n", 1001 (int)*ppos); 1002 return -EINVAL; 1003 } 1004 1005 if (count > sizeof(wdev->ssid)) { 1006 wil_err(wil, "SSID too long, len = %d\n", (int)count); 1007 return -EINVAL; 1008 } 1009 if (netif_running(ndev)) { 1010 wil_err(wil, "Unable to change SSID on running interface\n"); 1011 return -EINVAL; 1012 } 1013 1014 wdev->ssid_len = count; 1015 return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos, 1016 buf, count); 1017 } 1018 1019 static const struct file_operations fops_ssid = { 1020 .read = wil_read_file_ssid, 1021 .write = wil_write_file_ssid, 1022 .open = simple_open, 1023 }; 1024 1025 /*---------temp------------*/ 1026 static void print_temp(struct seq_file *s, const char *prefix, u32 t) 1027 { 1028 switch (t) { 1029 case 0: 1030 case ~(u32)0: 1031 seq_printf(s, "%s N/A\n", prefix); 1032 break; 1033 default: 1034 seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000); 1035 break; 1036 } 1037 } 1038 1039 static int wil_temp_debugfs_show(struct seq_file *s, void *data) 1040 { 1041 struct wil6210_priv *wil = s->private; 1042 u32 t_m, t_r; 1043 int rc = wmi_get_temperature(wil, &t_m, &t_r); 1044 1045 if (rc) { 1046 seq_puts(s, "Failed\n"); 1047 return 0; 1048 } 1049 1050 print_temp(s, "T_mac =", t_m); 1051 print_temp(s, "T_radio =", t_r); 1052 1053 return 0; 1054 } 1055 1056 static int wil_temp_seq_open(struct inode *inode, struct file *file) 1057 { 1058 return single_open(file, wil_temp_debugfs_show, inode->i_private); 1059 } 1060 1061 static const struct file_operations fops_temp = { 1062 .open = wil_temp_seq_open, 1063 .release = single_release, 1064 .read = seq_read, 1065 .llseek = seq_lseek, 1066 }; 1067 1068 /*---------freq------------*/ 1069 static int wil_freq_debugfs_show(struct seq_file *s, void *data) 1070 { 1071 struct wil6210_priv *wil = s->private; 1072 struct wireless_dev *wdev = wil_to_wdev(wil); 1073 u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; 1074 1075 seq_printf(s, "Freq = %d\n", freq); 1076 1077 return 0; 1078 } 1079 1080 static int wil_freq_seq_open(struct inode *inode, struct file *file) 1081 { 1082 return single_open(file, wil_freq_debugfs_show, inode->i_private); 1083 } 1084 1085 static const struct file_operations fops_freq = { 1086 .open = wil_freq_seq_open, 1087 .release = single_release, 1088 .read = seq_read, 1089 .llseek = seq_lseek, 1090 }; 1091 1092 /*---------link------------*/ 1093 static int wil_link_debugfs_show(struct seq_file *s, void *data) 1094 { 1095 struct wil6210_priv *wil = s->private; 1096 struct station_info sinfo; 1097 int i, rc; 1098 1099 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1100 struct wil_sta_info *p = &wil->sta[i]; 1101 char *status = "unknown"; 1102 1103 switch (p->status) { 1104 case wil_sta_unused: 1105 status = "unused "; 1106 break; 1107 case wil_sta_conn_pending: 1108 status = "pending "; 1109 break; 1110 case wil_sta_connected: 1111 status = "connected"; 1112 break; 1113 } 1114 seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, 1115 (p->data_port_open ? " data_port_open" : "")); 1116 1117 if (p->status == wil_sta_connected) { 1118 rc = wil_cid_fill_sinfo(wil, i, &sinfo); 1119 if (rc) 1120 return rc; 1121 1122 seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); 1123 seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); 1124 seq_printf(s, " SQ = %d\n", sinfo.signal); 1125 } 1126 } 1127 1128 return 0; 1129 } 1130 1131 static int wil_link_seq_open(struct inode *inode, struct file *file) 1132 { 1133 return single_open(file, wil_link_debugfs_show, inode->i_private); 1134 } 1135 1136 static const struct file_operations fops_link = { 1137 .open = wil_link_seq_open, 1138 .release = single_release, 1139 .read = seq_read, 1140 .llseek = seq_lseek, 1141 }; 1142 1143 /*---------info------------*/ 1144 static int wil_info_debugfs_show(struct seq_file *s, void *data) 1145 { 1146 struct wil6210_priv *wil = s->private; 1147 struct net_device *ndev = wil_to_ndev(wil); 1148 int is_ac = power_supply_is_system_supplied(); 1149 int rx = atomic_xchg(&wil->isr_count_rx, 0); 1150 int tx = atomic_xchg(&wil->isr_count_tx, 0); 1151 static ulong rxf_old, txf_old; 1152 ulong rxf = ndev->stats.rx_packets; 1153 ulong txf = ndev->stats.tx_packets; 1154 unsigned int i; 1155 1156 /* >0 : AC; 0 : battery; <0 : error */ 1157 seq_printf(s, "AC powered : %d\n", is_ac); 1158 seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); 1159 seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); 1160 rxf_old = rxf; 1161 txf_old = txf; 1162 1163 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ 1164 " " __stringify(x) : "" 1165 1166 for (i = 0; i < ndev->num_tx_queues; i++) { 1167 struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); 1168 unsigned long state = txq->state; 1169 1170 seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, 1171 CHECK_QSTATE(DRV_XOFF), 1172 CHECK_QSTATE(STACK_XOFF), 1173 CHECK_QSTATE(FROZEN) 1174 ); 1175 } 1176 #undef CHECK_QSTATE 1177 return 0; 1178 } 1179 1180 static int wil_info_seq_open(struct inode *inode, struct file *file) 1181 { 1182 return single_open(file, wil_info_debugfs_show, inode->i_private); 1183 } 1184 1185 static const struct file_operations fops_info = { 1186 .open = wil_info_seq_open, 1187 .release = single_release, 1188 .read = seq_read, 1189 .llseek = seq_lseek, 1190 }; 1191 1192 /*---------recovery------------*/ 1193 /* mode = [manual|auto] 1194 * state = [idle|pending|running] 1195 */ 1196 static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf, 1197 size_t count, loff_t *ppos) 1198 { 1199 struct wil6210_priv *wil = file->private_data; 1200 char buf[80]; 1201 int n; 1202 static const char * const sstate[] = {"idle", "pending", "running"}; 1203 1204 n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n", 1205 no_fw_recovery ? "manual" : "auto", 1206 sstate[wil->recovery_state]); 1207 1208 n = min_t(int, n, sizeof(buf)); 1209 1210 return simple_read_from_buffer(user_buf, count, ppos, 1211 buf, n); 1212 } 1213 1214 static ssize_t wil_write_file_recovery(struct file *file, 1215 const char __user *buf_, 1216 size_t count, loff_t *ppos) 1217 { 1218 struct wil6210_priv *wil = file->private_data; 1219 static const char run_command[] = "run"; 1220 char buf[sizeof(run_command) + 1]; /* to detect "runx" */ 1221 ssize_t rc; 1222 1223 if (wil->recovery_state != fw_recovery_pending) { 1224 wil_err(wil, "No recovery pending\n"); 1225 return -EINVAL; 1226 } 1227 1228 if (*ppos != 0) { 1229 wil_err(wil, "Offset [%d]\n", (int)*ppos); 1230 return -EINVAL; 1231 } 1232 1233 if (count > sizeof(buf)) { 1234 wil_err(wil, "Input too long, len = %d\n", (int)count); 1235 return -EINVAL; 1236 } 1237 1238 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count); 1239 if (rc < 0) 1240 return rc; 1241 1242 buf[rc] = '\0'; 1243 if (0 == strcmp(buf, run_command)) 1244 wil_set_recovery_state(wil, fw_recovery_running); 1245 else 1246 wil_err(wil, "Bad recovery command \"%s\"\n", buf); 1247 1248 return rc; 1249 } 1250 1251 static const struct file_operations fops_recovery = { 1252 .read = wil_read_file_recovery, 1253 .write = wil_write_file_recovery, 1254 .open = simple_open, 1255 }; 1256 1257 /*---------Station matrix------------*/ 1258 static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) 1259 { 1260 int i; 1261 u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; 1262 1263 seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, 1264 r->head_seq_num); 1265 for (i = 0; i < r->buf_size; i++) { 1266 if (i == index) 1267 seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); 1268 else 1269 seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); 1270 } 1271 seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); 1272 } 1273 1274 static int wil_sta_debugfs_show(struct seq_file *s, void *data) 1275 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) 1276 { 1277 struct wil6210_priv *wil = s->private; 1278 int i, tid; 1279 1280 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1281 struct wil_sta_info *p = &wil->sta[i]; 1282 char *status = "unknown"; 1283 1284 switch (p->status) { 1285 case wil_sta_unused: 1286 status = "unused "; 1287 break; 1288 case wil_sta_conn_pending: 1289 status = "pending "; 1290 break; 1291 case wil_sta_connected: 1292 status = "connected"; 1293 break; 1294 } 1295 seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, 1296 (p->data_port_open ? " data_port_open" : "")); 1297 1298 if (p->status == wil_sta_connected) { 1299 spin_lock_bh(&p->tid_rx_lock); 1300 for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { 1301 struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; 1302 1303 if (r) { 1304 seq_printf(s, "[%2d] ", tid); 1305 wil_print_rxtid(s, r); 1306 } 1307 } 1308 spin_unlock_bh(&p->tid_rx_lock); 1309 } 1310 } 1311 1312 return 0; 1313 } 1314 1315 static int wil_sta_seq_open(struct inode *inode, struct file *file) 1316 { 1317 return single_open(file, wil_sta_debugfs_show, inode->i_private); 1318 } 1319 1320 static const struct file_operations fops_sta = { 1321 .open = wil_sta_seq_open, 1322 .release = single_release, 1323 .read = seq_read, 1324 .llseek = seq_lseek, 1325 }; 1326 1327 /*----------------*/ 1328 static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, 1329 struct dentry *dbg) 1330 { 1331 int i; 1332 char name[32]; 1333 1334 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { 1335 struct debugfs_blob_wrapper *blob = &wil->blobs[i]; 1336 const struct fw_map *map = &fw_mapping[i]; 1337 1338 if (!map->name) 1339 continue; 1340 1341 blob->data = (void * __force)wil->csr + HOSTADDR(map->host); 1342 blob->size = map->to - map->from; 1343 snprintf(name, sizeof(name), "blob_%s", map->name); 1344 wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob); 1345 } 1346 } 1347 1348 /* misc files */ 1349 static const struct { 1350 const char *name; 1351 umode_t mode; 1352 const struct file_operations *fops; 1353 } dbg_files[] = { 1354 {"mbox", S_IRUGO, &fops_mbox}, 1355 {"vrings", S_IRUGO, &fops_vring}, 1356 {"stations", S_IRUGO, &fops_sta}, 1357 {"desc", S_IRUGO, &fops_txdesc}, 1358 {"bf", S_IRUGO, &fops_bf}, 1359 {"ssid", S_IRUGO | S_IWUSR, &fops_ssid}, 1360 {"mem_val", S_IRUGO, &fops_memread}, 1361 {"reset", S_IWUSR, &fops_reset}, 1362 {"rxon", S_IWUSR, &fops_rxon}, 1363 {"tx_mgmt", S_IWUSR, &fops_txmgmt}, 1364 {"wmi_send", S_IWUSR, &fops_wmi}, 1365 {"back", S_IRUGO | S_IWUSR, &fops_back}, 1366 {"temp", S_IRUGO, &fops_temp}, 1367 {"freq", S_IRUGO, &fops_freq}, 1368 {"link", S_IRUGO, &fops_link}, 1369 {"info", S_IRUGO, &fops_info}, 1370 {"recovery", S_IRUGO | S_IWUSR, &fops_recovery}, 1371 }; 1372 1373 static void wil6210_debugfs_init_files(struct wil6210_priv *wil, 1374 struct dentry *dbg) 1375 { 1376 int i; 1377 1378 for (i = 0; i < ARRAY_SIZE(dbg_files); i++) 1379 debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg, 1380 wil, dbg_files[i].fops); 1381 } 1382 1383 /* interrupt control blocks */ 1384 static const struct { 1385 const char *name; 1386 u32 icr_off; 1387 } dbg_icr[] = { 1388 {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)}, 1389 {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)}, 1390 {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)}, 1391 {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)}, 1392 }; 1393 1394 static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, 1395 struct dentry *dbg) 1396 { 1397 int i; 1398 1399 for (i = 0; i < ARRAY_SIZE(dbg_icr); i++) 1400 wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg, 1401 dbg_icr[i].icr_off); 1402 } 1403 1404 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \ 1405 offsetof(struct wil6210_priv, name), type} 1406 1407 /* fields in struct wil6210_priv */ 1408 static const struct dbg_off dbg_wil_off[] = { 1409 WIL_FIELD(privacy, S_IRUGO, doff_u32), 1410 WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong), 1411 WIL_FIELD(fw_version, S_IRUGO, doff_u32), 1412 WIL_FIELD(hw_version, S_IRUGO, doff_x32), 1413 WIL_FIELD(recovery_count, S_IRUGO, doff_u32), 1414 WIL_FIELD(ap_isolate, S_IRUGO, doff_u32), 1415 {}, 1416 }; 1417 1418 static const struct dbg_off dbg_wil_regs[] = { 1419 {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0), 1420 doff_io32}, 1421 {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32}, 1422 {}, 1423 }; 1424 1425 /* static parameters */ 1426 static const struct dbg_off dbg_statics[] = { 1427 {"desc_index", S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32}, 1428 {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32}, 1429 {"mem_addr", S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32}, 1430 {"vring_idle_trsh", S_IRUGO | S_IWUSR, (ulong)&vring_idle_trsh, 1431 doff_u32}, 1432 {}, 1433 }; 1434 1435 int wil6210_debugfs_init(struct wil6210_priv *wil) 1436 { 1437 struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, 1438 wil_to_wiphy(wil)->debugfsdir); 1439 1440 if (IS_ERR_OR_NULL(dbg)) 1441 return -ENODEV; 1442 1443 wil6210_debugfs_init_files(wil, dbg); 1444 wil6210_debugfs_init_isr(wil, dbg); 1445 wil6210_debugfs_init_blobs(wil, dbg); 1446 wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off); 1447 wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr, 1448 dbg_wil_regs); 1449 wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics); 1450 1451 wil6210_debugfs_create_pseudo_ISR(wil, dbg); 1452 1453 wil6210_debugfs_create_ITR_CNT(wil, dbg); 1454 1455 return 0; 1456 } 1457 1458 void wil6210_debugfs_remove(struct wil6210_priv *wil) 1459 { 1460 debugfs_remove_recursive(wil->debug); 1461 wil->debug = NULL; 1462 } 1463