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