1 /* 2 * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. 3 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 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 <linux/module.h> 19 #include <linux/debugfs.h> 20 #include <linux/seq_file.h> 21 #include <linux/pci.h> 22 #include <linux/rtnetlink.h> 23 #include <linux/power_supply.h> 24 #include "wil6210.h" 25 #include "wmi.h" 26 #include "txrx.h" 27 #include "pmc.h" 28 29 /* Nasty hack. Better have per device instances */ 30 static u32 mem_addr; 31 static u32 dbg_txdesc_index; 32 static u32 dbg_ring_index; /* 24+ for Rx, 0..23 for Tx */ 33 static u32 dbg_status_msg_index; 34 /* 0..wil->num_rx_status_rings-1 for Rx, wil->tx_sring_idx for Tx */ 35 static u32 dbg_sring_index; 36 37 enum dbg_off_type { 38 doff_u32 = 0, 39 doff_x32 = 1, 40 doff_ulong = 2, 41 doff_io32 = 3, 42 doff_u8 = 4 43 }; 44 45 /* offset to "wil" */ 46 struct dbg_off { 47 const char *name; 48 umode_t mode; 49 ulong off; 50 enum dbg_off_type type; 51 }; 52 53 static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil, 54 struct wil_ring *ring, 55 char _s, char _h, int idx) 56 { 57 u8 num_of_descs; 58 bool has_skb = false; 59 60 if (ring->is_rx) { 61 struct wil_rx_enhanced_desc *rx_d = 62 (struct wil_rx_enhanced_desc *) 63 &ring->va[idx].rx.enhanced; 64 u16 buff_id = le16_to_cpu(rx_d->mac.buff_id); 65 66 has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; 67 seq_printf(s, "%c", (has_skb) ? _h : _s); 68 } else { 69 struct wil_tx_enhanced_desc *d = 70 (struct wil_tx_enhanced_desc *) 71 &ring->va[idx].tx.enhanced; 72 73 num_of_descs = (u8)d->mac.d[2]; 74 has_skb = ring->ctx[idx].skb; 75 if (num_of_descs >= 1) 76 seq_printf(s, "%c", ring->ctx[idx].skb ? _h : _s); 77 else 78 /* num_of_descs == 0, it's a frag in a list of descs */ 79 seq_printf(s, "%c", has_skb ? 'h' : _s); 80 } 81 } 82 83 static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, 84 const char *name, struct wil_ring *ring, 85 char _s, char _h) 86 { 87 void __iomem *x = wmi_addr(wil, ring->hwtail); 88 u32 v; 89 90 seq_printf(s, "RING %s = {\n", name); 91 seq_printf(s, " pa = %pad\n", &ring->pa); 92 seq_printf(s, " va = 0x%p\n", ring->va); 93 seq_printf(s, " size = %d\n", ring->size); 94 if (wil->use_enhanced_dma_hw && ring->is_rx) 95 seq_printf(s, " swtail = %u\n", *ring->edma_rx_swtail.va); 96 else 97 seq_printf(s, " swtail = %d\n", ring->swtail); 98 seq_printf(s, " swhead = %d\n", ring->swhead); 99 seq_printf(s, " hwtail = [0x%08x] -> ", ring->hwtail); 100 if (x) { 101 v = readl(x); 102 seq_printf(s, "0x%08x = %d\n", v, v); 103 } else { 104 seq_puts(s, "???\n"); 105 } 106 107 if (ring->va && (ring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { 108 uint i; 109 110 for (i = 0; i < ring->size; i++) { 111 if ((i % 128) == 0 && i != 0) 112 seq_puts(s, "\n"); 113 if (wil->use_enhanced_dma_hw) { 114 wil_print_desc_edma(s, wil, ring, _s, _h, i); 115 } else { 116 volatile struct vring_tx_desc *d = 117 &ring->va[i].tx.legacy; 118 seq_printf(s, "%c", (d->dma.status & BIT(0)) ? 119 _s : (ring->ctx[i].skb ? _h : 'h')); 120 } 121 } 122 seq_puts(s, "\n"); 123 } 124 seq_puts(s, "}\n"); 125 } 126 127 static int wil_ring_debugfs_show(struct seq_file *s, void *data) 128 { 129 uint i; 130 struct wil6210_priv *wil = s->private; 131 132 wil_print_ring(s, wil, "rx", &wil->ring_rx, 'S', '_'); 133 134 for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) { 135 struct wil_ring *ring = &wil->ring_tx[i]; 136 struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i]; 137 138 if (ring->va) { 139 int cid = wil->ring2cid_tid[i][0]; 140 int tid = wil->ring2cid_tid[i][1]; 141 u32 swhead = ring->swhead; 142 u32 swtail = ring->swtail; 143 int used = (ring->size + swhead - swtail) 144 % ring->size; 145 int avail = ring->size - used - 1; 146 char name[10]; 147 char sidle[10]; 148 /* performance monitoring */ 149 cycles_t now = get_cycles(); 150 uint64_t idle = txdata->idle * 100; 151 uint64_t total = now - txdata->begin; 152 153 if (total != 0) { 154 do_div(idle, total); 155 snprintf(sidle, sizeof(sidle), "%3d%%", 156 (int)idle); 157 } else { 158 snprintf(sidle, sizeof(sidle), "N/A"); 159 } 160 txdata->begin = now; 161 txdata->idle = 0ULL; 162 163 snprintf(name, sizeof(name), "tx_%2d", i); 164 165 if (cid < WIL6210_MAX_CID) 166 seq_printf(s, 167 "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", 168 wil->sta[cid].addr, cid, tid, 169 txdata->dot1x_open ? "+" : "-", 170 txdata->agg_wsize, 171 txdata->agg_timeout, 172 txdata->agg_amsdu ? "+" : "-", 173 used, avail, sidle); 174 else 175 seq_printf(s, 176 "\nBroadcast 1x%s [%3d|%3d] idle %s\n", 177 txdata->dot1x_open ? "+" : "-", 178 used, avail, sidle); 179 180 wil_print_ring(s, wil, name, ring, '_', 'H'); 181 } 182 } 183 184 return 0; 185 } 186 187 static int wil_ring_seq_open(struct inode *inode, struct file *file) 188 { 189 return single_open(file, wil_ring_debugfs_show, inode->i_private); 190 } 191 192 static const struct file_operations fops_ring = { 193 .open = wil_ring_seq_open, 194 .release = single_release, 195 .read = seq_read, 196 .llseek = seq_lseek, 197 }; 198 199 static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil, 200 struct wil_status_ring *sring) 201 { 202 void __iomem *x = wmi_addr(wil, sring->hwtail); 203 int sring_idx = sring - wil->srings; 204 u32 v; 205 206 seq_printf(s, "Status Ring %s [ %d ] = {\n", 207 sring->is_rx ? "RX" : "TX", sring_idx); 208 seq_printf(s, " pa = %pad\n", &sring->pa); 209 seq_printf(s, " va = 0x%pK\n", sring->va); 210 seq_printf(s, " size = %d\n", sring->size); 211 seq_printf(s, " elem_size = %zu\n", sring->elem_size); 212 seq_printf(s, " swhead = %d\n", sring->swhead); 213 seq_printf(s, " hwtail = [0x%08x] -> ", sring->hwtail); 214 if (x) { 215 v = readl_relaxed(x); 216 seq_printf(s, "0x%08x = %d\n", v, v); 217 } else { 218 seq_puts(s, "???\n"); 219 } 220 seq_printf(s, " desc_rdy_pol = %d\n", sring->desc_rdy_pol); 221 222 if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { 223 uint i; 224 225 for (i = 0; i < sring->size; i++) { 226 u32 *sdword_0 = 227 (u32 *)(sring->va + (sring->elem_size * i)); 228 229 if ((i % 128) == 0 && i != 0) 230 seq_puts(s, "\n"); 231 if (i == sring->swhead) 232 seq_printf(s, "%c", (*sdword_0 & BIT(31)) ? 233 'X' : 'x'); 234 else 235 seq_printf(s, "%c", (*sdword_0 & BIT(31)) ? 236 '1' : '0'); 237 } 238 seq_puts(s, "\n"); 239 } 240 seq_puts(s, "}\n"); 241 } 242 243 static int wil_srings_debugfs_show(struct seq_file *s, void *data) 244 { 245 struct wil6210_priv *wil = s->private; 246 int i = 0; 247 248 for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++) 249 if (wil->srings[i].va) 250 wil_print_sring(s, wil, &wil->srings[i]); 251 252 return 0; 253 } 254 255 static int wil_srings_seq_open(struct inode *inode, struct file *file) 256 { 257 return single_open(file, wil_srings_debugfs_show, inode->i_private); 258 } 259 260 static const struct file_operations fops_srings = { 261 .open = wil_srings_seq_open, 262 .release = single_release, 263 .read = seq_read, 264 .llseek = seq_lseek, 265 }; 266 267 static void wil_seq_hexdump(struct seq_file *s, void *p, int len, 268 const char *prefix) 269 { 270 seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false); 271 } 272 273 static void wil_print_mbox_ring(struct seq_file *s, const char *prefix, 274 void __iomem *off) 275 { 276 struct wil6210_priv *wil = s->private; 277 struct wil6210_mbox_ring r; 278 int rsize; 279 uint i; 280 281 wil_halp_vote(wil); 282 283 wil_memcpy_fromio_32(&r, off, sizeof(r)); 284 wil_mbox_ring_le2cpus(&r); 285 /* 286 * we just read memory block from NIC. This memory may be 287 * garbage. Check validity before using it. 288 */ 289 rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); 290 291 seq_printf(s, "ring %s = {\n", prefix); 292 seq_printf(s, " base = 0x%08x\n", r.base); 293 seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); 294 seq_printf(s, " tail = 0x%08x\n", r.tail); 295 seq_printf(s, " head = 0x%08x\n", r.head); 296 seq_printf(s, " entry size = %d\n", r.entry_size); 297 298 if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { 299 seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", 300 sizeof(struct wil6210_mbox_ring_desc)); 301 goto out; 302 } 303 304 if (!wmi_addr(wil, r.base) || 305 !wmi_addr(wil, r.tail) || 306 !wmi_addr(wil, r.head)) { 307 seq_puts(s, " ??? pointers are garbage?\n"); 308 goto out; 309 } 310 311 for (i = 0; i < rsize; i++) { 312 struct wil6210_mbox_ring_desc d; 313 struct wil6210_mbox_hdr hdr; 314 size_t delta = i * sizeof(d); 315 void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; 316 317 wil_memcpy_fromio_32(&d, x, sizeof(d)); 318 319 seq_printf(s, " [%2x] %s %s%s 0x%08x", i, 320 d.sync ? "F" : "E", 321 (r.tail - r.base == delta) ? "t" : " ", 322 (r.head - r.base == delta) ? "h" : " ", 323 le32_to_cpu(d.addr)); 324 if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { 325 u16 len = le16_to_cpu(hdr.len); 326 327 seq_printf(s, " -> %04x %04x %04x %02x\n", 328 le16_to_cpu(hdr.seq), len, 329 le16_to_cpu(hdr.type), hdr.flags); 330 if (len <= MAX_MBOXITEM_SIZE) { 331 unsigned char databuf[MAX_MBOXITEM_SIZE]; 332 void __iomem *src = wmi_buffer(wil, d.addr) + 333 sizeof(struct wil6210_mbox_hdr); 334 /* 335 * No need to check @src for validity - 336 * we already validated @d.addr while 337 * reading header 338 */ 339 wil_memcpy_fromio_32(databuf, src, len); 340 wil_seq_hexdump(s, databuf, len, " : "); 341 } 342 } else { 343 seq_puts(s, "\n"); 344 } 345 } 346 out: 347 seq_puts(s, "}\n"); 348 wil_halp_unvote(wil); 349 } 350 351 static int wil_mbox_debugfs_show(struct seq_file *s, void *data) 352 { 353 struct wil6210_priv *wil = s->private; 354 int ret; 355 356 ret = wil_pm_runtime_get(wil); 357 if (ret < 0) 358 return ret; 359 360 wil_print_mbox_ring(s, "tx", wil->csr + HOST_MBOX + 361 offsetof(struct wil6210_mbox_ctl, tx)); 362 wil_print_mbox_ring(s, "rx", wil->csr + HOST_MBOX + 363 offsetof(struct wil6210_mbox_ctl, rx)); 364 365 wil_pm_runtime_put(wil); 366 367 return 0; 368 } 369 370 static int wil_mbox_seq_open(struct inode *inode, struct file *file) 371 { 372 return single_open(file, wil_mbox_debugfs_show, inode->i_private); 373 } 374 375 static const struct file_operations fops_mbox = { 376 .open = wil_mbox_seq_open, 377 .release = single_release, 378 .read = seq_read, 379 .llseek = seq_lseek, 380 }; 381 382 static int wil_debugfs_iomem_x32_set(void *data, u64 val) 383 { 384 struct wil_debugfs_iomem_data *d = (struct 385 wil_debugfs_iomem_data *)data; 386 struct wil6210_priv *wil = d->wil; 387 int ret; 388 389 ret = wil_pm_runtime_get(wil); 390 if (ret < 0) 391 return ret; 392 393 writel(val, (void __iomem *)d->offset); 394 wmb(); /* make sure write propagated to HW */ 395 396 wil_pm_runtime_put(wil); 397 398 return 0; 399 } 400 401 static int wil_debugfs_iomem_x32_get(void *data, u64 *val) 402 { 403 struct wil_debugfs_iomem_data *d = (struct 404 wil_debugfs_iomem_data *)data; 405 struct wil6210_priv *wil = d->wil; 406 int ret; 407 408 ret = wil_pm_runtime_get(wil); 409 if (ret < 0) 410 return ret; 411 412 *val = readl((void __iomem *)d->offset); 413 414 wil_pm_runtime_put(wil); 415 416 return 0; 417 } 418 419 DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, 420 wil_debugfs_iomem_x32_set, "0x%08llx\n"); 421 422 static struct dentry *wil_debugfs_create_iomem_x32(const char *name, 423 umode_t mode, 424 struct dentry *parent, 425 void *value, 426 struct wil6210_priv *wil) 427 { 428 struct dentry *file; 429 struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[ 430 wil->dbg_data.iomem_data_count]; 431 432 data->wil = wil; 433 data->offset = value; 434 435 file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32); 436 if (!IS_ERR_OR_NULL(file)) 437 wil->dbg_data.iomem_data_count++; 438 439 return file; 440 } 441 442 static int wil_debugfs_ulong_set(void *data, u64 val) 443 { 444 *(ulong *)data = val; 445 return 0; 446 } 447 448 static int wil_debugfs_ulong_get(void *data, u64 *val) 449 { 450 *val = *(ulong *)data; 451 return 0; 452 } 453 454 DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, 455 wil_debugfs_ulong_set, "0x%llx\n"); 456 457 static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, 458 struct dentry *parent, 459 ulong *value) 460 { 461 return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); 462 } 463 464 /** 465 * wil6210_debugfs_init_offset - create set of debugfs files 466 * @wil - driver's context, used for printing 467 * @dbg - directory on the debugfs, where files will be created 468 * @base - base address used in address calculation 469 * @tbl - table with file descriptions. Should be terminated with empty element. 470 * 471 * Creates files accordingly to the @tbl. 472 */ 473 static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, 474 struct dentry *dbg, void *base, 475 const struct dbg_off * const tbl) 476 { 477 int i; 478 479 for (i = 0; tbl[i].name; i++) { 480 struct dentry *f; 481 482 switch (tbl[i].type) { 483 case doff_u32: 484 f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, 485 base + tbl[i].off); 486 break; 487 case doff_x32: 488 f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, 489 base + tbl[i].off); 490 break; 491 case doff_ulong: 492 f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode, 493 dbg, base + tbl[i].off); 494 break; 495 case doff_io32: 496 f = wil_debugfs_create_iomem_x32(tbl[i].name, 497 tbl[i].mode, dbg, 498 base + tbl[i].off, 499 wil); 500 break; 501 case doff_u8: 502 f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, 503 base + tbl[i].off); 504 break; 505 default: 506 f = ERR_PTR(-EINVAL); 507 } 508 if (IS_ERR_OR_NULL(f)) 509 wil_err(wil, "Create file \"%s\": err %ld\n", 510 tbl[i].name, PTR_ERR(f)); 511 } 512 } 513 514 static const struct dbg_off isr_off[] = { 515 {"ICC", 0644, offsetof(struct RGF_ICR, ICC), doff_io32}, 516 {"ICR", 0644, offsetof(struct RGF_ICR, ICR), doff_io32}, 517 {"ICM", 0644, offsetof(struct RGF_ICR, ICM), doff_io32}, 518 {"ICS", 0244, offsetof(struct RGF_ICR, ICS), doff_io32}, 519 {"IMV", 0644, offsetof(struct RGF_ICR, IMV), doff_io32}, 520 {"IMS", 0244, offsetof(struct RGF_ICR, IMS), doff_io32}, 521 {"IMC", 0244, offsetof(struct RGF_ICR, IMC), doff_io32}, 522 {}, 523 }; 524 525 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, 526 const char *name, 527 struct dentry *parent, u32 off) 528 { 529 struct dentry *d = debugfs_create_dir(name, parent); 530 531 if (IS_ERR_OR_NULL(d)) 532 return -ENODEV; 533 534 wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off, 535 isr_off); 536 537 return 0; 538 } 539 540 static const struct dbg_off pseudo_isr_off[] = { 541 {"CAUSE", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32}, 542 {"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32}, 543 {"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32}, 544 {}, 545 }; 546 547 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, 548 struct dentry *parent) 549 { 550 struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); 551 552 if (IS_ERR_OR_NULL(d)) 553 return -ENODEV; 554 555 wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, 556 pseudo_isr_off); 557 558 return 0; 559 } 560 561 static const struct dbg_off lgc_itr_cnt_off[] = { 562 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32}, 563 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32}, 564 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32}, 565 {}, 566 }; 567 568 static const struct dbg_off tx_itr_cnt_off[] = { 569 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH), 570 doff_io32}, 571 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA), 572 doff_io32}, 573 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL), 574 doff_io32}, 575 {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH), 576 doff_io32}, 577 {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA), 578 doff_io32}, 579 {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL), 580 doff_io32}, 581 {}, 582 }; 583 584 static const struct dbg_off rx_itr_cnt_off[] = { 585 {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH), 586 doff_io32}, 587 {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA), 588 doff_io32}, 589 {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL), 590 doff_io32}, 591 {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH), 592 doff_io32}, 593 {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA), 594 doff_io32}, 595 {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL), 596 doff_io32}, 597 {}, 598 }; 599 600 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, 601 struct dentry *parent) 602 { 603 struct dentry *d, *dtx, *drx; 604 605 d = debugfs_create_dir("ITR_CNT", parent); 606 if (IS_ERR_OR_NULL(d)) 607 return -ENODEV; 608 609 dtx = debugfs_create_dir("TX", d); 610 drx = debugfs_create_dir("RX", d); 611 if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx)) 612 return -ENODEV; 613 614 wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, 615 lgc_itr_cnt_off); 616 617 wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr, 618 tx_itr_cnt_off); 619 620 wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr, 621 rx_itr_cnt_off); 622 return 0; 623 } 624 625 static int wil_memread_debugfs_show(struct seq_file *s, void *data) 626 { 627 struct wil6210_priv *wil = s->private; 628 void __iomem *a; 629 int ret; 630 631 ret = wil_pm_runtime_get(wil); 632 if (ret < 0) 633 return ret; 634 635 a = wmi_buffer(wil, cpu_to_le32(mem_addr)); 636 637 if (a) 638 seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a)); 639 else 640 seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); 641 642 wil_pm_runtime_put(wil); 643 644 return 0; 645 } 646 647 static int wil_memread_seq_open(struct inode *inode, struct file *file) 648 { 649 return single_open(file, wil_memread_debugfs_show, inode->i_private); 650 } 651 652 static const struct file_operations fops_memread = { 653 .open = wil_memread_seq_open, 654 .release = single_release, 655 .read = seq_read, 656 .llseek = seq_lseek, 657 }; 658 659 static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, 660 size_t count, loff_t *ppos) 661 { 662 enum { max_count = 4096 }; 663 struct wil_blob_wrapper *wil_blob = file->private_data; 664 struct wil6210_priv *wil = wil_blob->wil; 665 loff_t pos = *ppos; 666 size_t available = wil_blob->blob.size; 667 void *buf; 668 size_t ret; 669 int rc; 670 671 if (test_bit(wil_status_suspending, wil_blob->wil->status) || 672 test_bit(wil_status_suspended, wil_blob->wil->status)) 673 return 0; 674 675 if (pos < 0) 676 return -EINVAL; 677 678 if (pos >= available || !count) 679 return 0; 680 681 if (count > available - pos) 682 count = available - pos; 683 if (count > max_count) 684 count = max_count; 685 686 buf = kmalloc(count, GFP_KERNEL); 687 if (!buf) 688 return -ENOMEM; 689 690 rc = wil_pm_runtime_get(wil); 691 if (rc < 0) { 692 kfree(buf); 693 return rc; 694 } 695 696 wil_memcpy_fromio_32(buf, (const void __iomem *) 697 wil_blob->blob.data + pos, count); 698 699 ret = copy_to_user(user_buf, buf, count); 700 701 wil_pm_runtime_put(wil); 702 703 kfree(buf); 704 if (ret == count) 705 return -EFAULT; 706 707 count -= ret; 708 *ppos = pos + count; 709 710 return count; 711 } 712 713 static const struct file_operations fops_ioblob = { 714 .read = wil_read_file_ioblob, 715 .open = simple_open, 716 .llseek = default_llseek, 717 }; 718 719 static 720 struct dentry *wil_debugfs_create_ioblob(const char *name, 721 umode_t mode, 722 struct dentry *parent, 723 struct wil_blob_wrapper *wil_blob) 724 { 725 return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob); 726 } 727 728 /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ 729 static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, 730 size_t len, loff_t *ppos) 731 { 732 struct wil6210_priv *wil = file->private_data; 733 int rc; 734 long channel; 735 bool on; 736 737 char *kbuf = memdup_user_nul(buf, len); 738 739 if (IS_ERR(kbuf)) 740 return PTR_ERR(kbuf); 741 rc = kstrtol(kbuf, 0, &channel); 742 kfree(kbuf); 743 if (rc) 744 return rc; 745 746 if ((channel < 0) || (channel > 4)) { 747 wil_err(wil, "Invalid channel %ld\n", channel); 748 return -EINVAL; 749 } 750 on = !!channel; 751 752 if (on) { 753 rc = wmi_set_channel(wil, (int)channel); 754 if (rc) 755 return rc; 756 } 757 758 rc = wmi_rxon(wil, on); 759 if (rc) 760 return rc; 761 762 return len; 763 } 764 765 static const struct file_operations fops_rxon = { 766 .write = wil_write_file_rxon, 767 .open = simple_open, 768 }; 769 770 /* block ack control, write: 771 * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA 772 * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side 773 * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side 774 */ 775 static ssize_t wil_write_back(struct file *file, const char __user *buf, 776 size_t len, loff_t *ppos) 777 { 778 struct wil6210_priv *wil = file->private_data; 779 int rc; 780 char *kbuf = kmalloc(len + 1, GFP_KERNEL); 781 char cmd[9]; 782 int p1, p2, p3; 783 784 if (!kbuf) 785 return -ENOMEM; 786 787 rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 788 if (rc != len) { 789 kfree(kbuf); 790 return rc >= 0 ? -EIO : rc; 791 } 792 793 kbuf[len] = '\0'; 794 rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3); 795 kfree(kbuf); 796 797 if (rc < 0) 798 return rc; 799 if (rc < 2) 800 return -EINVAL; 801 802 if ((strcmp(cmd, "add") == 0) || 803 (strcmp(cmd, "del_tx") == 0)) { 804 struct wil_ring_tx_data *txdata; 805 806 if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) { 807 wil_err(wil, "BACK: invalid ring id %d\n", p1); 808 return -EINVAL; 809 } 810 txdata = &wil->ring_tx_data[p1]; 811 if (strcmp(cmd, "add") == 0) { 812 if (rc < 3) { 813 wil_err(wil, "BACK: add require at least 2 params\n"); 814 return -EINVAL; 815 } 816 if (rc < 4) 817 p3 = 0; 818 wmi_addba(wil, txdata->mid, p1, p2, p3); 819 } else { 820 if (rc < 3) 821 p2 = WLAN_REASON_QSTA_LEAVE_QBSS; 822 wmi_delba_tx(wil, txdata->mid, p1, p2); 823 } 824 } else if (strcmp(cmd, "del_rx") == 0) { 825 struct wil_sta_info *sta; 826 827 if (rc < 3) { 828 wil_err(wil, 829 "BACK: del_rx require at least 2 params\n"); 830 return -EINVAL; 831 } 832 if (p1 < 0 || p1 >= WIL6210_MAX_CID) { 833 wil_err(wil, "BACK: invalid CID %d\n", p1); 834 return -EINVAL; 835 } 836 if (rc < 4) 837 p3 = WLAN_REASON_QSTA_LEAVE_QBSS; 838 sta = &wil->sta[p1]; 839 wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3); 840 } else { 841 wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); 842 return -EINVAL; 843 } 844 845 return len; 846 } 847 848 static ssize_t wil_read_back(struct file *file, char __user *user_buf, 849 size_t count, loff_t *ppos) 850 { 851 static const char text[] = "block ack control, write:\n" 852 " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n" 853 "If missing, <timeout> defaults to 0\n" 854 " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n" 855 " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n" 856 "If missing, <reason> set to \"STA_LEAVING\" (36)\n"; 857 858 return simple_read_from_buffer(user_buf, count, ppos, text, 859 sizeof(text)); 860 } 861 862 static const struct file_operations fops_back = { 863 .read = wil_read_back, 864 .write = wil_write_back, 865 .open = simple_open, 866 }; 867 868 /* pmc control, write: 869 * - "alloc <num descriptors> <descriptor_size>" to allocate PMC 870 * - "free" to release memory allocated for PMC 871 */ 872 static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf, 873 size_t len, loff_t *ppos) 874 { 875 struct wil6210_priv *wil = file->private_data; 876 int rc; 877 char *kbuf = kmalloc(len + 1, GFP_KERNEL); 878 char cmd[9]; 879 int num_descs, desc_size; 880 881 if (!kbuf) 882 return -ENOMEM; 883 884 rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 885 if (rc != len) { 886 kfree(kbuf); 887 return rc >= 0 ? -EIO : rc; 888 } 889 890 kbuf[len] = '\0'; 891 rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size); 892 kfree(kbuf); 893 894 if (rc < 0) 895 return rc; 896 897 if (rc < 1) { 898 wil_err(wil, "pmccfg: no params given\n"); 899 return -EINVAL; 900 } 901 902 if (0 == strcmp(cmd, "alloc")) { 903 if (rc != 3) { 904 wil_err(wil, "pmccfg: alloc requires 2 params\n"); 905 return -EINVAL; 906 } 907 wil_pmc_alloc(wil, num_descs, desc_size); 908 } else if (0 == strcmp(cmd, "free")) { 909 if (rc != 1) { 910 wil_err(wil, "pmccfg: free does not have any params\n"); 911 return -EINVAL; 912 } 913 wil_pmc_free(wil, true); 914 } else { 915 wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd); 916 return -EINVAL; 917 } 918 919 return len; 920 } 921 922 static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf, 923 size_t count, loff_t *ppos) 924 { 925 struct wil6210_priv *wil = file->private_data; 926 char text[256]; 927 char help[] = "pmc control, write:\n" 928 " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n" 929 " - \"free\" to free memory allocated for pmc\n"; 930 931 sprintf(text, "Last command status: %d\n\n%s", 932 wil_pmc_last_cmd_status(wil), 933 help); 934 935 return simple_read_from_buffer(user_buf, count, ppos, text, 936 strlen(text) + 1); 937 } 938 939 static const struct file_operations fops_pmccfg = { 940 .read = wil_read_pmccfg, 941 .write = wil_write_pmccfg, 942 .open = simple_open, 943 }; 944 945 static const struct file_operations fops_pmcdata = { 946 .open = simple_open, 947 .read = wil_pmc_read, 948 .llseek = wil_pmc_llseek, 949 }; 950 951 /*---tx_mgmt---*/ 952 /* Write mgmt frame to this file to send it */ 953 static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, 954 size_t len, loff_t *ppos) 955 { 956 struct wil6210_priv *wil = file->private_data; 957 struct wiphy *wiphy = wil_to_wiphy(wil); 958 struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; 959 struct cfg80211_mgmt_tx_params params; 960 int rc; 961 void *frame; 962 963 if (!len) 964 return -EINVAL; 965 966 frame = memdup_user(buf, len); 967 if (IS_ERR(frame)) 968 return PTR_ERR(frame); 969 970 params.buf = frame; 971 params.len = len; 972 973 rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); 974 975 kfree(frame); 976 wil_info(wil, "-> %d\n", rc); 977 978 return len; 979 } 980 981 static const struct file_operations fops_txmgmt = { 982 .write = wil_write_file_txmgmt, 983 .open = simple_open, 984 }; 985 986 /* Write WMI command (w/o mbox header) to this file to send it 987 * WMI starts from wil6210_mbox_hdr_wmi header 988 */ 989 static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, 990 size_t len, loff_t *ppos) 991 { 992 struct wil6210_priv *wil = file->private_data; 993 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 994 struct wmi_cmd_hdr *wmi; 995 void *cmd; 996 int cmdlen = len - sizeof(struct wmi_cmd_hdr); 997 u16 cmdid; 998 int rc, rc1; 999 1000 if (cmdlen < 0) 1001 return -EINVAL; 1002 1003 wmi = kmalloc(len, GFP_KERNEL); 1004 if (!wmi) 1005 return -ENOMEM; 1006 1007 rc = simple_write_to_buffer(wmi, len, ppos, buf, len); 1008 if (rc < 0) { 1009 kfree(wmi); 1010 return rc; 1011 } 1012 1013 cmd = (cmdlen > 0) ? &wmi[1] : NULL; 1014 cmdid = le16_to_cpu(wmi->command_id); 1015 1016 rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen); 1017 kfree(wmi); 1018 1019 wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); 1020 1021 return rc; 1022 } 1023 1024 static const struct file_operations fops_wmi = { 1025 .write = wil_write_file_wmi, 1026 .open = simple_open, 1027 }; 1028 1029 static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) 1030 { 1031 int i = 0; 1032 int len = skb_headlen(skb); 1033 void *p = skb->data; 1034 int nr_frags = skb_shinfo(skb)->nr_frags; 1035 1036 seq_printf(s, " len = %d\n", len); 1037 wil_seq_hexdump(s, p, len, " : "); 1038 1039 if (nr_frags) { 1040 seq_printf(s, " nr_frags = %d\n", nr_frags); 1041 for (i = 0; i < nr_frags; i++) { 1042 const struct skb_frag_struct *frag = 1043 &skb_shinfo(skb)->frags[i]; 1044 1045 len = skb_frag_size(frag); 1046 p = skb_frag_address_safe(frag); 1047 seq_printf(s, " [%2d] : len = %d\n", i, len); 1048 wil_seq_hexdump(s, p, len, " : "); 1049 } 1050 } 1051 } 1052 1053 /*---------Tx/Rx descriptor------------*/ 1054 static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) 1055 { 1056 struct wil6210_priv *wil = s->private; 1057 struct wil_ring *ring; 1058 bool tx; 1059 int ring_idx = dbg_ring_index; 1060 int txdesc_idx = dbg_txdesc_index; 1061 volatile struct vring_tx_desc *d; 1062 volatile u32 *u; 1063 struct sk_buff *skb; 1064 1065 if (wil->use_enhanced_dma_hw) { 1066 /* RX ring index == 0 */ 1067 if (ring_idx >= WIL6210_MAX_TX_RINGS) { 1068 seq_printf(s, "invalid ring index %d\n", ring_idx); 1069 return 0; 1070 } 1071 tx = ring_idx > 0; /* desc ring 0 is reserved for RX */ 1072 } else { 1073 /* RX ring index == WIL6210_MAX_TX_RINGS */ 1074 if (ring_idx > WIL6210_MAX_TX_RINGS) { 1075 seq_printf(s, "invalid ring index %d\n", ring_idx); 1076 return 0; 1077 } 1078 tx = (ring_idx < WIL6210_MAX_TX_RINGS); 1079 } 1080 1081 ring = tx ? &wil->ring_tx[ring_idx] : &wil->ring_rx; 1082 1083 if (!ring->va) { 1084 if (tx) 1085 seq_printf(s, "No Tx[%2d] RING\n", ring_idx); 1086 else 1087 seq_puts(s, "No Rx RING\n"); 1088 return 0; 1089 } 1090 1091 if (txdesc_idx >= ring->size) { 1092 if (tx) 1093 seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", 1094 ring_idx, txdesc_idx, ring->size); 1095 else 1096 seq_printf(s, "RxDesc index (%d) >= size (%d)\n", 1097 txdesc_idx, ring->size); 1098 return 0; 1099 } 1100 1101 /* use struct vring_tx_desc for Rx as well, 1102 * only field used, .dma.length, is the same 1103 */ 1104 d = &ring->va[txdesc_idx].tx.legacy; 1105 u = (volatile u32 *)d; 1106 skb = NULL; 1107 1108 if (wil->use_enhanced_dma_hw) { 1109 if (tx) { 1110 skb = ring->ctx[txdesc_idx].skb; 1111 } else { 1112 struct wil_rx_enhanced_desc *rx_d = 1113 (struct wil_rx_enhanced_desc *) 1114 &ring->va[txdesc_idx].rx.enhanced; 1115 u16 buff_id = le16_to_cpu(rx_d->mac.buff_id); 1116 1117 if (!wil_val_in_range(buff_id, 0, 1118 wil->rx_buff_mgmt.size)) { 1119 seq_printf(s, "invalid buff_id %d\n", buff_id); 1120 return 0; 1121 } 1122 skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; 1123 } 1124 } else { 1125 skb = ring->ctx[txdesc_idx].skb; 1126 } 1127 if (tx) 1128 seq_printf(s, "Tx[%2d][%3d] = {\n", ring_idx, 1129 txdesc_idx); 1130 else 1131 seq_printf(s, "Rx[%3d] = {\n", txdesc_idx); 1132 seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", 1133 u[0], u[1], u[2], u[3]); 1134 seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", 1135 u[4], u[5], u[6], u[7]); 1136 seq_printf(s, " SKB = 0x%p\n", skb); 1137 1138 if (skb) { 1139 skb_get(skb); 1140 wil_seq_print_skb(s, skb); 1141 kfree_skb(skb); 1142 } 1143 seq_puts(s, "}\n"); 1144 1145 return 0; 1146 } 1147 1148 static int wil_txdesc_seq_open(struct inode *inode, struct file *file) 1149 { 1150 return single_open(file, wil_txdesc_debugfs_show, inode->i_private); 1151 } 1152 1153 static const struct file_operations fops_txdesc = { 1154 .open = wil_txdesc_seq_open, 1155 .release = single_release, 1156 .read = seq_read, 1157 .llseek = seq_lseek, 1158 }; 1159 1160 /*---------Tx/Rx status message------------*/ 1161 static int wil_status_msg_debugfs_show(struct seq_file *s, void *data) 1162 { 1163 struct wil6210_priv *wil = s->private; 1164 int sring_idx = dbg_sring_index; 1165 struct wil_status_ring *sring; 1166 bool tx = sring_idx == wil->tx_sring_idx ? 1 : 0; 1167 u32 status_msg_idx = dbg_status_msg_index; 1168 u32 *u; 1169 1170 if (sring_idx >= WIL6210_MAX_STATUS_RINGS) { 1171 seq_printf(s, "invalid status ring index %d\n", sring_idx); 1172 return 0; 1173 } 1174 1175 sring = &wil->srings[sring_idx]; 1176 1177 if (!sring->va) { 1178 seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R'); 1179 return 0; 1180 } 1181 1182 if (status_msg_idx >= sring->size) { 1183 seq_printf(s, "%cxDesc index (%d) >= size (%d)\n", 1184 tx ? 'T' : 'R', status_msg_idx, sring->size); 1185 return 0; 1186 } 1187 1188 u = sring->va + (sring->elem_size * status_msg_idx); 1189 1190 seq_printf(s, "%cx[%d][%3d] = {\n", 1191 tx ? 'T' : 'R', sring_idx, status_msg_idx); 1192 1193 seq_printf(s, " 0x%08x 0x%08x 0x%08x 0x%08x\n", 1194 u[0], u[1], u[2], u[3]); 1195 if (!tx && !wil->use_compressed_rx_status) 1196 seq_printf(s, " 0x%08x 0x%08x 0x%08x 0x%08x\n", 1197 u[4], u[5], u[6], u[7]); 1198 1199 seq_puts(s, "}\n"); 1200 1201 return 0; 1202 } 1203 1204 static int wil_status_msg_seq_open(struct inode *inode, struct file *file) 1205 { 1206 return single_open(file, wil_status_msg_debugfs_show, 1207 inode->i_private); 1208 } 1209 1210 static const struct file_operations fops_status_msg = { 1211 .open = wil_status_msg_seq_open, 1212 .release = single_release, 1213 .read = seq_read, 1214 .llseek = seq_lseek, 1215 }; 1216 1217 static int wil_print_rx_buff(struct seq_file *s, struct list_head *lh) 1218 { 1219 struct wil_rx_buff *it; 1220 int i = 0; 1221 1222 list_for_each_entry(it, lh, list) { 1223 if ((i % 16) == 0 && i != 0) 1224 seq_puts(s, "\n "); 1225 seq_printf(s, "[%4d] ", it->id); 1226 i++; 1227 } 1228 seq_printf(s, "\nNumber of buffers: %u\n", i); 1229 1230 return i; 1231 } 1232 1233 static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data) 1234 { 1235 struct wil6210_priv *wil = s->private; 1236 struct wil_rx_buff_mgmt *rbm = &wil->rx_buff_mgmt; 1237 int num_active; 1238 int num_free; 1239 1240 if (!rbm->buff_arr) 1241 return -EINVAL; 1242 1243 seq_printf(s, " size = %zu\n", rbm->size); 1244 seq_printf(s, " free_list_empty_cnt = %lu\n", 1245 rbm->free_list_empty_cnt); 1246 1247 /* Print active list */ 1248 seq_puts(s, " Active list:\n"); 1249 num_active = wil_print_rx_buff(s, &rbm->active); 1250 seq_puts(s, "\n Free list:\n"); 1251 num_free = wil_print_rx_buff(s, &rbm->free); 1252 1253 seq_printf(s, " Total number of buffers: %u\n", 1254 num_active + num_free); 1255 1256 return 0; 1257 } 1258 1259 static int wil_rx_buff_mgmt_seq_open(struct inode *inode, struct file *file) 1260 { 1261 return single_open(file, wil_rx_buff_mgmt_debugfs_show, 1262 inode->i_private); 1263 } 1264 1265 static const struct file_operations fops_rx_buff_mgmt = { 1266 .open = wil_rx_buff_mgmt_seq_open, 1267 .release = single_release, 1268 .read = seq_read, 1269 .llseek = seq_lseek, 1270 }; 1271 1272 /*---------beamforming------------*/ 1273 static char *wil_bfstatus_str(u32 status) 1274 { 1275 switch (status) { 1276 case 0: 1277 return "Failed"; 1278 case 1: 1279 return "OK"; 1280 case 2: 1281 return "Retrying"; 1282 default: 1283 return "??"; 1284 } 1285 } 1286 1287 static bool is_all_zeros(void * const x_, size_t sz) 1288 { 1289 /* if reply is all-0, ignore this CID */ 1290 u32 *x = x_; 1291 int n; 1292 1293 for (n = 0; n < sz / sizeof(*x); n++) 1294 if (x[n]) 1295 return false; 1296 1297 return true; 1298 } 1299 1300 static int wil_bf_debugfs_show(struct seq_file *s, void *data) 1301 { 1302 int rc; 1303 int i; 1304 struct wil6210_priv *wil = s->private; 1305 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 1306 struct wmi_notify_req_cmd cmd = { 1307 .interval_usec = 0, 1308 }; 1309 struct { 1310 struct wmi_cmd_hdr wmi; 1311 struct wmi_notify_req_done_event evt; 1312 } __packed reply; 1313 1314 memset(&reply, 0, sizeof(reply)); 1315 1316 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1317 u32 status; 1318 1319 cmd.cid = i; 1320 rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, 1321 &cmd, sizeof(cmd), 1322 WMI_NOTIFY_REQ_DONE_EVENTID, &reply, 1323 sizeof(reply), 20); 1324 /* if reply is all-0, ignore this CID */ 1325 if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt))) 1326 continue; 1327 1328 status = le32_to_cpu(reply.evt.status); 1329 seq_printf(s, "CID %d {\n" 1330 " TSF = 0x%016llx\n" 1331 " TxMCS = %2d TxTpt = %4d\n" 1332 " SQI = %4d\n" 1333 " RSSI = %4d\n" 1334 " Status = 0x%08x %s\n" 1335 " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" 1336 " Goodput(rx:tx) %4d:%4d\n" 1337 "}\n", 1338 i, 1339 le64_to_cpu(reply.evt.tsf), 1340 le16_to_cpu(reply.evt.bf_mcs), 1341 le32_to_cpu(reply.evt.tx_tpt), 1342 reply.evt.sqi, 1343 reply.evt.rssi, 1344 status, wil_bfstatus_str(status), 1345 le16_to_cpu(reply.evt.my_rx_sector), 1346 le16_to_cpu(reply.evt.my_tx_sector), 1347 le16_to_cpu(reply.evt.other_rx_sector), 1348 le16_to_cpu(reply.evt.other_tx_sector), 1349 le32_to_cpu(reply.evt.rx_goodput), 1350 le32_to_cpu(reply.evt.tx_goodput)); 1351 } 1352 return 0; 1353 } 1354 1355 static int wil_bf_seq_open(struct inode *inode, struct file *file) 1356 { 1357 return single_open(file, wil_bf_debugfs_show, inode->i_private); 1358 } 1359 1360 static const struct file_operations fops_bf = { 1361 .open = wil_bf_seq_open, 1362 .release = single_release, 1363 .read = seq_read, 1364 .llseek = seq_lseek, 1365 }; 1366 1367 /*---------temp------------*/ 1368 static void print_temp(struct seq_file *s, const char *prefix, s32 t) 1369 { 1370 switch (t) { 1371 case 0: 1372 case ~(u32)0: 1373 seq_printf(s, "%s N/A\n", prefix); 1374 break; 1375 default: 1376 seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""), 1377 abs(t / 1000), abs(t % 1000)); 1378 break; 1379 } 1380 } 1381 1382 static int wil_temp_debugfs_show(struct seq_file *s, void *data) 1383 { 1384 struct wil6210_priv *wil = s->private; 1385 s32 t_m, t_r; 1386 int rc = wmi_get_temperature(wil, &t_m, &t_r); 1387 1388 if (rc) { 1389 seq_puts(s, "Failed\n"); 1390 return 0; 1391 } 1392 1393 print_temp(s, "T_mac =", t_m); 1394 print_temp(s, "T_radio =", t_r); 1395 1396 return 0; 1397 } 1398 1399 static int wil_temp_seq_open(struct inode *inode, struct file *file) 1400 { 1401 return single_open(file, wil_temp_debugfs_show, inode->i_private); 1402 } 1403 1404 static const struct file_operations fops_temp = { 1405 .open = wil_temp_seq_open, 1406 .release = single_release, 1407 .read = seq_read, 1408 .llseek = seq_lseek, 1409 }; 1410 1411 /*---------freq------------*/ 1412 static int wil_freq_debugfs_show(struct seq_file *s, void *data) 1413 { 1414 struct wil6210_priv *wil = s->private; 1415 struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; 1416 u32 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; 1417 1418 seq_printf(s, "Freq = %d\n", freq); 1419 1420 return 0; 1421 } 1422 1423 static int wil_freq_seq_open(struct inode *inode, struct file *file) 1424 { 1425 return single_open(file, wil_freq_debugfs_show, inode->i_private); 1426 } 1427 1428 static const struct file_operations fops_freq = { 1429 .open = wil_freq_seq_open, 1430 .release = single_release, 1431 .read = seq_read, 1432 .llseek = seq_lseek, 1433 }; 1434 1435 /*---------link------------*/ 1436 static int wil_link_debugfs_show(struct seq_file *s, void *data) 1437 { 1438 struct wil6210_priv *wil = s->private; 1439 struct station_info *sinfo; 1440 int i, rc = 0; 1441 1442 sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); 1443 if (!sinfo) 1444 return -ENOMEM; 1445 1446 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1447 struct wil_sta_info *p = &wil->sta[i]; 1448 char *status = "unknown"; 1449 struct wil6210_vif *vif; 1450 u8 mid; 1451 1452 switch (p->status) { 1453 case wil_sta_unused: 1454 status = "unused "; 1455 break; 1456 case wil_sta_conn_pending: 1457 status = "pending "; 1458 break; 1459 case wil_sta_connected: 1460 status = "connected"; 1461 break; 1462 } 1463 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; 1464 seq_printf(s, "[%d][MID %d] %pM %s\n", 1465 i, mid, p->addr, status); 1466 1467 if (p->status != wil_sta_connected) 1468 continue; 1469 1470 vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; 1471 if (vif) { 1472 rc = wil_cid_fill_sinfo(vif, i, sinfo); 1473 if (rc) 1474 goto out; 1475 1476 seq_printf(s, " Tx_mcs = %d\n", sinfo->txrate.mcs); 1477 seq_printf(s, " Rx_mcs = %d\n", sinfo->rxrate.mcs); 1478 seq_printf(s, " SQ = %d\n", sinfo->signal); 1479 } else { 1480 seq_puts(s, " INVALID MID\n"); 1481 } 1482 } 1483 1484 out: 1485 kfree(sinfo); 1486 return rc; 1487 } 1488 1489 static int wil_link_seq_open(struct inode *inode, struct file *file) 1490 { 1491 return single_open(file, wil_link_debugfs_show, inode->i_private); 1492 } 1493 1494 static const struct file_operations fops_link = { 1495 .open = wil_link_seq_open, 1496 .release = single_release, 1497 .read = seq_read, 1498 .llseek = seq_lseek, 1499 }; 1500 1501 /*---------info------------*/ 1502 static int wil_info_debugfs_show(struct seq_file *s, void *data) 1503 { 1504 struct wil6210_priv *wil = s->private; 1505 struct net_device *ndev = wil->main_ndev; 1506 int is_ac = power_supply_is_system_supplied(); 1507 int rx = atomic_xchg(&wil->isr_count_rx, 0); 1508 int tx = atomic_xchg(&wil->isr_count_tx, 0); 1509 static ulong rxf_old, txf_old; 1510 ulong rxf = ndev->stats.rx_packets; 1511 ulong txf = ndev->stats.tx_packets; 1512 unsigned int i; 1513 1514 /* >0 : AC; 0 : battery; <0 : error */ 1515 seq_printf(s, "AC powered : %d\n", is_ac); 1516 seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); 1517 seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); 1518 rxf_old = rxf; 1519 txf_old = txf; 1520 1521 #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ 1522 " " __stringify(x) : "" 1523 1524 for (i = 0; i < ndev->num_tx_queues; i++) { 1525 struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); 1526 unsigned long state = txq->state; 1527 1528 seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, 1529 CHECK_QSTATE(DRV_XOFF), 1530 CHECK_QSTATE(STACK_XOFF), 1531 CHECK_QSTATE(FROZEN) 1532 ); 1533 } 1534 #undef CHECK_QSTATE 1535 return 0; 1536 } 1537 1538 static int wil_info_seq_open(struct inode *inode, struct file *file) 1539 { 1540 return single_open(file, wil_info_debugfs_show, inode->i_private); 1541 } 1542 1543 static const struct file_operations fops_info = { 1544 .open = wil_info_seq_open, 1545 .release = single_release, 1546 .read = seq_read, 1547 .llseek = seq_lseek, 1548 }; 1549 1550 /*---------recovery------------*/ 1551 /* mode = [manual|auto] 1552 * state = [idle|pending|running] 1553 */ 1554 static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf, 1555 size_t count, loff_t *ppos) 1556 { 1557 struct wil6210_priv *wil = file->private_data; 1558 char buf[80]; 1559 int n; 1560 static const char * const sstate[] = {"idle", "pending", "running"}; 1561 1562 n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n", 1563 no_fw_recovery ? "manual" : "auto", 1564 sstate[wil->recovery_state]); 1565 1566 n = min_t(int, n, sizeof(buf)); 1567 1568 return simple_read_from_buffer(user_buf, count, ppos, 1569 buf, n); 1570 } 1571 1572 static ssize_t wil_write_file_recovery(struct file *file, 1573 const char __user *buf_, 1574 size_t count, loff_t *ppos) 1575 { 1576 struct wil6210_priv *wil = file->private_data; 1577 static const char run_command[] = "run"; 1578 char buf[sizeof(run_command) + 1]; /* to detect "runx" */ 1579 ssize_t rc; 1580 1581 if (wil->recovery_state != fw_recovery_pending) { 1582 wil_err(wil, "No recovery pending\n"); 1583 return -EINVAL; 1584 } 1585 1586 if (*ppos != 0) { 1587 wil_err(wil, "Offset [%d]\n", (int)*ppos); 1588 return -EINVAL; 1589 } 1590 1591 if (count > sizeof(buf)) { 1592 wil_err(wil, "Input too long, len = %d\n", (int)count); 1593 return -EINVAL; 1594 } 1595 1596 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count); 1597 if (rc < 0) 1598 return rc; 1599 1600 buf[rc] = '\0'; 1601 if (0 == strcmp(buf, run_command)) 1602 wil_set_recovery_state(wil, fw_recovery_running); 1603 else 1604 wil_err(wil, "Bad recovery command \"%s\"\n", buf); 1605 1606 return rc; 1607 } 1608 1609 static const struct file_operations fops_recovery = { 1610 .read = wil_read_file_recovery, 1611 .write = wil_write_file_recovery, 1612 .open = simple_open, 1613 }; 1614 1615 /*---------Station matrix------------*/ 1616 static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) 1617 { 1618 int i; 1619 u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; 1620 unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old; 1621 unsigned long long drop_dup_mcast = r->drop_dup_mcast; 1622 1623 seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num); 1624 for (i = 0; i < r->buf_size; i++) { 1625 if (i == index) 1626 seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); 1627 else 1628 seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); 1629 } 1630 seq_printf(s, 1631 "] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n", 1632 r->total, drop_dup + drop_old + drop_dup_mcast, drop_dup, 1633 drop_old, drop_dup_mcast, r->ssn_last_drop); 1634 } 1635 1636 static void wil_print_rxtid_crypto(struct seq_file *s, int tid, 1637 struct wil_tid_crypto_rx *c) 1638 { 1639 int i; 1640 1641 for (i = 0; i < 4; i++) { 1642 struct wil_tid_crypto_rx_single *cc = &c->key_id[i]; 1643 1644 if (cc->key_set) 1645 goto has_keys; 1646 } 1647 return; 1648 1649 has_keys: 1650 if (tid < WIL_STA_TID_NUM) 1651 seq_printf(s, " [%2d] PN", tid); 1652 else 1653 seq_puts(s, " [GR] PN"); 1654 1655 for (i = 0; i < 4; i++) { 1656 struct wil_tid_crypto_rx_single *cc = &c->key_id[i]; 1657 1658 seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-", 1659 cc->pn); 1660 } 1661 seq_puts(s, "\n"); 1662 } 1663 1664 static int wil_sta_debugfs_show(struct seq_file *s, void *data) 1665 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) 1666 { 1667 struct wil6210_priv *wil = s->private; 1668 int i, tid, mcs; 1669 1670 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1671 struct wil_sta_info *p = &wil->sta[i]; 1672 char *status = "unknown"; 1673 u8 aid = 0; 1674 u8 mid; 1675 bool sta_connected = false; 1676 1677 switch (p->status) { 1678 case wil_sta_unused: 1679 status = "unused "; 1680 break; 1681 case wil_sta_conn_pending: 1682 status = "pending "; 1683 break; 1684 case wil_sta_connected: 1685 status = "connected"; 1686 aid = p->aid; 1687 break; 1688 } 1689 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; 1690 if (mid < wil->max_vifs) { 1691 struct wil6210_vif *vif = wil->vifs[mid]; 1692 1693 if (vif->wdev.iftype == NL80211_IFTYPE_STATION && 1694 p->status == wil_sta_connected) 1695 sta_connected = true; 1696 } 1697 /* print roam counter only for connected stations */ 1698 if (sta_connected) 1699 seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n", 1700 i, p->addr, p->stats.ft_roams, mid, aid); 1701 else 1702 seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, 1703 p->addr, status, mid, aid); 1704 1705 if (p->status == wil_sta_connected) { 1706 spin_lock_bh(&p->tid_rx_lock); 1707 for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { 1708 struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; 1709 struct wil_tid_crypto_rx *c = 1710 &p->tid_crypto_rx[tid]; 1711 1712 if (r) { 1713 seq_printf(s, " [%2d] ", tid); 1714 wil_print_rxtid(s, r); 1715 } 1716 1717 wil_print_rxtid_crypto(s, tid, c); 1718 } 1719 wil_print_rxtid_crypto(s, WIL_STA_TID_NUM, 1720 &p->group_crypto_rx); 1721 spin_unlock_bh(&p->tid_rx_lock); 1722 seq_printf(s, 1723 "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n", 1724 p->stats.rx_non_data_frame, 1725 p->stats.rx_short_frame, 1726 p->stats.rx_large_frame, 1727 p->stats.rx_replay); 1728 seq_printf(s, 1729 "mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n", 1730 p->stats.rx_mic_error, 1731 p->stats.rx_key_error, 1732 p->stats.rx_amsdu_error, 1733 p->stats.rx_csum_err); 1734 1735 seq_puts(s, "Rx/MCS:"); 1736 for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); 1737 mcs++) 1738 seq_printf(s, " %lld", 1739 p->stats.rx_per_mcs[mcs]); 1740 seq_puts(s, "\n"); 1741 } 1742 } 1743 1744 return 0; 1745 } 1746 1747 static int wil_sta_seq_open(struct inode *inode, struct file *file) 1748 { 1749 return single_open(file, wil_sta_debugfs_show, inode->i_private); 1750 } 1751 1752 static const struct file_operations fops_sta = { 1753 .open = wil_sta_seq_open, 1754 .release = single_release, 1755 .read = seq_read, 1756 .llseek = seq_lseek, 1757 }; 1758 1759 static int wil_mids_debugfs_show(struct seq_file *s, void *data) 1760 { 1761 struct wil6210_priv *wil = s->private; 1762 struct wil6210_vif *vif; 1763 struct net_device *ndev; 1764 int i; 1765 1766 mutex_lock(&wil->vif_mutex); 1767 for (i = 0; i < wil->max_vifs; i++) { 1768 vif = wil->vifs[i]; 1769 1770 if (vif) { 1771 ndev = vif_to_ndev(vif); 1772 seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr, 1773 ndev->name); 1774 } else { 1775 seq_printf(s, "[%d] unused\n", i); 1776 } 1777 } 1778 mutex_unlock(&wil->vif_mutex); 1779 1780 return 0; 1781 } 1782 1783 static int wil_mids_seq_open(struct inode *inode, struct file *file) 1784 { 1785 return single_open(file, wil_mids_debugfs_show, inode->i_private); 1786 } 1787 1788 static const struct file_operations fops_mids = { 1789 .open = wil_mids_seq_open, 1790 .release = single_release, 1791 .read = seq_read, 1792 .llseek = seq_lseek, 1793 }; 1794 1795 static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data) 1796 __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) 1797 { 1798 struct wil6210_priv *wil = s->private; 1799 int i, bin; 1800 1801 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1802 struct wil_sta_info *p = &wil->sta[i]; 1803 char *status = "unknown"; 1804 u8 aid = 0; 1805 u8 mid; 1806 1807 if (!p->tx_latency_bins) 1808 continue; 1809 1810 switch (p->status) { 1811 case wil_sta_unused: 1812 status = "unused "; 1813 break; 1814 case wil_sta_conn_pending: 1815 status = "pending "; 1816 break; 1817 case wil_sta_connected: 1818 status = "connected"; 1819 aid = p->aid; 1820 break; 1821 } 1822 mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; 1823 seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, 1824 mid, aid); 1825 1826 if (p->status == wil_sta_connected) { 1827 u64 num_packets = 0; 1828 u64 tx_latency_avg = p->stats.tx_latency_total_us; 1829 1830 seq_puts(s, "Tx/Latency bin:"); 1831 for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) { 1832 seq_printf(s, " %lld", 1833 p->tx_latency_bins[bin]); 1834 num_packets += p->tx_latency_bins[bin]; 1835 } 1836 seq_puts(s, "\n"); 1837 if (!num_packets) 1838 continue; 1839 do_div(tx_latency_avg, num_packets); 1840 seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d", 1841 p->stats.tx_latency_min_us, 1842 tx_latency_avg, 1843 p->stats.tx_latency_max_us); 1844 1845 seq_puts(s, "\n"); 1846 } 1847 } 1848 1849 return 0; 1850 } 1851 1852 static int wil_tx_latency_seq_open(struct inode *inode, struct file *file) 1853 { 1854 return single_open(file, wil_tx_latency_debugfs_show, 1855 inode->i_private); 1856 } 1857 1858 static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf, 1859 size_t len, loff_t *ppos) 1860 { 1861 struct seq_file *s = file->private_data; 1862 struct wil6210_priv *wil = s->private; 1863 int val, rc, i; 1864 bool enable; 1865 1866 rc = kstrtoint_from_user(buf, len, 0, &val); 1867 if (rc) { 1868 wil_err(wil, "Invalid argument\n"); 1869 return rc; 1870 } 1871 if (val == 1) 1872 /* default resolution */ 1873 val = 500; 1874 if (val && (val < 50 || val > 1000)) { 1875 wil_err(wil, "Invalid resolution %d\n", val); 1876 return -EINVAL; 1877 } 1878 1879 enable = !!val; 1880 if (wil->tx_latency == enable) 1881 return len; 1882 1883 wil_info(wil, "%s TX latency measurements (resolution %dusec)\n", 1884 enable ? "Enabling" : "Disabling", val); 1885 1886 if (enable) { 1887 size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS; 1888 1889 wil->tx_latency_res = val; 1890 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1891 struct wil_sta_info *sta = &wil->sta[i]; 1892 1893 kfree(sta->tx_latency_bins); 1894 sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL); 1895 if (!sta->tx_latency_bins) 1896 return -ENOMEM; 1897 sta->stats.tx_latency_min_us = U32_MAX; 1898 sta->stats.tx_latency_max_us = 0; 1899 sta->stats.tx_latency_total_us = 0; 1900 } 1901 } 1902 wil->tx_latency = enable; 1903 1904 return len; 1905 } 1906 1907 static const struct file_operations fops_tx_latency = { 1908 .open = wil_tx_latency_seq_open, 1909 .release = single_release, 1910 .read = seq_read, 1911 .write = wil_tx_latency_write, 1912 .llseek = seq_lseek, 1913 }; 1914 1915 static void wil_link_stats_print_basic(struct wil6210_vif *vif, 1916 struct seq_file *s, 1917 struct wmi_link_stats_basic *basic) 1918 { 1919 char per[5] = "?"; 1920 1921 if (basic->per_average != 0xff) 1922 snprintf(per, sizeof(per), "%d%%", basic->per_average); 1923 1924 seq_printf(s, "CID %d {\n" 1925 "\tTxMCS %d TxTpt %d\n" 1926 "\tGoodput(rx:tx) %d:%d\n" 1927 "\tRxBcastFrames %d\n" 1928 "\tRSSI %d SQI %d SNR %d PER %s\n" 1929 "\tRx RFC %d Ant num %d\n" 1930 "\tSectors(rx:tx) my %d:%d peer %d:%d\n" 1931 "}\n", 1932 basic->cid, 1933 basic->bf_mcs, le32_to_cpu(basic->tx_tpt), 1934 le32_to_cpu(basic->rx_goodput), 1935 le32_to_cpu(basic->tx_goodput), 1936 le32_to_cpu(basic->rx_bcast_frames), 1937 basic->rssi, basic->sqi, basic->snr, per, 1938 basic->selected_rfc, basic->rx_effective_ant_num, 1939 basic->my_rx_sector, basic->my_tx_sector, 1940 basic->other_rx_sector, basic->other_tx_sector); 1941 } 1942 1943 static void wil_link_stats_print_global(struct wil6210_priv *wil, 1944 struct seq_file *s, 1945 struct wmi_link_stats_global *global) 1946 { 1947 seq_printf(s, "Frames(rx:tx) %d:%d\n" 1948 "BA Frames(rx:tx) %d:%d\n" 1949 "Beacons %d\n" 1950 "Rx Errors (MIC:CRC) %d:%d\n" 1951 "Tx Errors (no ack) %d\n", 1952 le32_to_cpu(global->rx_frames), 1953 le32_to_cpu(global->tx_frames), 1954 le32_to_cpu(global->rx_ba_frames), 1955 le32_to_cpu(global->tx_ba_frames), 1956 le32_to_cpu(global->tx_beacons), 1957 le32_to_cpu(global->rx_mic_errors), 1958 le32_to_cpu(global->rx_crc_errors), 1959 le32_to_cpu(global->tx_fail_no_ack)); 1960 } 1961 1962 static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif, 1963 struct seq_file *s) 1964 { 1965 struct wil6210_priv *wil = vif_to_wil(vif); 1966 struct wmi_link_stats_basic *stats; 1967 int i; 1968 1969 if (!vif->fw_stats_ready) { 1970 seq_puts(s, "no statistics\n"); 1971 return; 1972 } 1973 1974 seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf); 1975 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 1976 if (wil->sta[i].status == wil_sta_unused) 1977 continue; 1978 if (wil->sta[i].mid != vif->mid) 1979 continue; 1980 1981 stats = &wil->sta[i].fw_stats_basic; 1982 wil_link_stats_print_basic(vif, s, stats); 1983 } 1984 } 1985 1986 static int wil_link_stats_debugfs_show(struct seq_file *s, void *data) 1987 { 1988 struct wil6210_priv *wil = s->private; 1989 struct wil6210_vif *vif; 1990 int i, rc; 1991 1992 rc = mutex_lock_interruptible(&wil->vif_mutex); 1993 if (rc) 1994 return rc; 1995 1996 /* iterate over all MIDs and show per-cid statistics. Then show the 1997 * global statistics 1998 */ 1999 for (i = 0; i < wil->max_vifs; i++) { 2000 vif = wil->vifs[i]; 2001 2002 seq_printf(s, "MID %d ", i); 2003 if (!vif) { 2004 seq_puts(s, "unused\n"); 2005 continue; 2006 } 2007 2008 wil_link_stats_debugfs_show_vif(vif, s); 2009 } 2010 2011 mutex_unlock(&wil->vif_mutex); 2012 2013 return 0; 2014 } 2015 2016 static int wil_link_stats_seq_open(struct inode *inode, struct file *file) 2017 { 2018 return single_open(file, wil_link_stats_debugfs_show, inode->i_private); 2019 } 2020 2021 static ssize_t wil_link_stats_write(struct file *file, const char __user *buf, 2022 size_t len, loff_t *ppos) 2023 { 2024 struct seq_file *s = file->private_data; 2025 struct wil6210_priv *wil = s->private; 2026 int cid, interval, rc, i; 2027 struct wil6210_vif *vif; 2028 char *kbuf = kmalloc(len + 1, GFP_KERNEL); 2029 2030 if (!kbuf) 2031 return -ENOMEM; 2032 2033 rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 2034 if (rc != len) { 2035 kfree(kbuf); 2036 return rc >= 0 ? -EIO : rc; 2037 } 2038 2039 kbuf[len] = '\0'; 2040 /* specify cid (use -1 for all cids) and snapshot interval in ms */ 2041 rc = sscanf(kbuf, "%d %d", &cid, &interval); 2042 kfree(kbuf); 2043 if (rc < 0) 2044 return rc; 2045 if (rc < 2 || interval < 0) 2046 return -EINVAL; 2047 2048 wil_info(wil, "request link statistics, cid %d interval %d\n", 2049 cid, interval); 2050 2051 rc = mutex_lock_interruptible(&wil->vif_mutex); 2052 if (rc) 2053 return rc; 2054 2055 for (i = 0; i < wil->max_vifs; i++) { 2056 vif = wil->vifs[i]; 2057 if (!vif) 2058 continue; 2059 2060 rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC, 2061 (cid == -1 ? 0xff : cid), interval); 2062 if (rc) 2063 wil_err(wil, "link statistics failed for mid %d\n", i); 2064 } 2065 mutex_unlock(&wil->vif_mutex); 2066 2067 return len; 2068 } 2069 2070 static const struct file_operations fops_link_stats = { 2071 .open = wil_link_stats_seq_open, 2072 .release = single_release, 2073 .read = seq_read, 2074 .write = wil_link_stats_write, 2075 .llseek = seq_lseek, 2076 }; 2077 2078 static int 2079 wil_link_stats_global_debugfs_show(struct seq_file *s, void *data) 2080 { 2081 struct wil6210_priv *wil = s->private; 2082 2083 if (!wil->fw_stats_global.ready) 2084 return 0; 2085 2086 seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf); 2087 wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats); 2088 2089 return 0; 2090 } 2091 2092 static int 2093 wil_link_stats_global_seq_open(struct inode *inode, struct file *file) 2094 { 2095 return single_open(file, wil_link_stats_global_debugfs_show, 2096 inode->i_private); 2097 } 2098 2099 static ssize_t 2100 wil_link_stats_global_write(struct file *file, const char __user *buf, 2101 size_t len, loff_t *ppos) 2102 { 2103 struct seq_file *s = file->private_data; 2104 struct wil6210_priv *wil = s->private; 2105 int interval, rc; 2106 struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 2107 2108 /* specify snapshot interval in ms */ 2109 rc = kstrtoint_from_user(buf, len, 0, &interval); 2110 if (rc || interval < 0) { 2111 wil_err(wil, "Invalid argument\n"); 2112 return -EINVAL; 2113 } 2114 2115 wil_info(wil, "request global link stats, interval %d\n", interval); 2116 2117 rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval); 2118 if (rc) 2119 wil_err(wil, "global link stats failed %d\n", rc); 2120 2121 return rc ? rc : len; 2122 } 2123 2124 static const struct file_operations fops_link_stats_global = { 2125 .open = wil_link_stats_global_seq_open, 2126 .release = single_release, 2127 .read = seq_read, 2128 .write = wil_link_stats_global_write, 2129 .llseek = seq_lseek, 2130 }; 2131 2132 static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, 2133 size_t count, loff_t *ppos) 2134 { 2135 char buf[80]; 2136 int n; 2137 2138 n = snprintf(buf, sizeof(buf), 2139 "led_id is set to %d, echo 1 to enable, 0 to disable\n", 2140 led_id); 2141 2142 n = min_t(int, n, sizeof(buf)); 2143 2144 return simple_read_from_buffer(user_buf, count, ppos, 2145 buf, n); 2146 } 2147 2148 static ssize_t wil_write_file_led_cfg(struct file *file, 2149 const char __user *buf_, 2150 size_t count, loff_t *ppos) 2151 { 2152 struct wil6210_priv *wil = file->private_data; 2153 int val; 2154 int rc; 2155 2156 rc = kstrtoint_from_user(buf_, count, 0, &val); 2157 if (rc) { 2158 wil_err(wil, "Invalid argument\n"); 2159 return rc; 2160 } 2161 2162 wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id); 2163 rc = wmi_led_cfg(wil, val); 2164 if (rc) { 2165 wil_info(wil, "%s led %d failed\n", 2166 val ? "Enabling" : "Disabling", led_id); 2167 return rc; 2168 } 2169 2170 return count; 2171 } 2172 2173 static const struct file_operations fops_led_cfg = { 2174 .read = wil_read_file_led_cfg, 2175 .write = wil_write_file_led_cfg, 2176 .open = simple_open, 2177 }; 2178 2179 /* led_blink_time, write: 2180 * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast> 2181 */ 2182 static ssize_t wil_write_led_blink_time(struct file *file, 2183 const char __user *buf, 2184 size_t len, loff_t *ppos) 2185 { 2186 int rc; 2187 char *kbuf = kmalloc(len + 1, GFP_KERNEL); 2188 2189 if (!kbuf) 2190 return -ENOMEM; 2191 2192 rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 2193 if (rc != len) { 2194 kfree(kbuf); 2195 return rc >= 0 ? -EIO : rc; 2196 } 2197 2198 kbuf[len] = '\0'; 2199 rc = sscanf(kbuf, "%d %d %d %d %d %d", 2200 &led_blink_time[WIL_LED_TIME_SLOW].on_ms, 2201 &led_blink_time[WIL_LED_TIME_SLOW].off_ms, 2202 &led_blink_time[WIL_LED_TIME_MED].on_ms, 2203 &led_blink_time[WIL_LED_TIME_MED].off_ms, 2204 &led_blink_time[WIL_LED_TIME_FAST].on_ms, 2205 &led_blink_time[WIL_LED_TIME_FAST].off_ms); 2206 kfree(kbuf); 2207 2208 if (rc < 0) 2209 return rc; 2210 if (rc < 6) 2211 return -EINVAL; 2212 2213 return len; 2214 } 2215 2216 static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf, 2217 size_t count, loff_t *ppos) 2218 { 2219 static char text[400]; 2220 2221 snprintf(text, sizeof(text), 2222 "To set led blink on/off time variables write:\n" 2223 "<blink_on_slow> <blink_off_slow> <blink_on_med> " 2224 "<blink_off_med> <blink_on_fast> <blink_off_fast>\n" 2225 "The current values are:\n" 2226 "%d %d %d %d %d %d\n", 2227 led_blink_time[WIL_LED_TIME_SLOW].on_ms, 2228 led_blink_time[WIL_LED_TIME_SLOW].off_ms, 2229 led_blink_time[WIL_LED_TIME_MED].on_ms, 2230 led_blink_time[WIL_LED_TIME_MED].off_ms, 2231 led_blink_time[WIL_LED_TIME_FAST].on_ms, 2232 led_blink_time[WIL_LED_TIME_FAST].off_ms); 2233 2234 return simple_read_from_buffer(user_buf, count, ppos, text, 2235 sizeof(text)); 2236 } 2237 2238 static const struct file_operations fops_led_blink_time = { 2239 .read = wil_read_led_blink_time, 2240 .write = wil_write_led_blink_time, 2241 .open = simple_open, 2242 }; 2243 2244 /*---------FW capabilities------------*/ 2245 static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data) 2246 { 2247 struct wil6210_priv *wil = s->private; 2248 2249 seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX, 2250 wil->fw_capabilities); 2251 2252 return 0; 2253 } 2254 2255 static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file) 2256 { 2257 return single_open(file, wil_fw_capabilities_debugfs_show, 2258 inode->i_private); 2259 } 2260 2261 static const struct file_operations fops_fw_capabilities = { 2262 .open = wil_fw_capabilities_seq_open, 2263 .release = single_release, 2264 .read = seq_read, 2265 .llseek = seq_lseek, 2266 }; 2267 2268 /*---------FW version------------*/ 2269 static int wil_fw_version_debugfs_show(struct seq_file *s, void *data) 2270 { 2271 struct wil6210_priv *wil = s->private; 2272 2273 if (wil->fw_version[0]) 2274 seq_printf(s, "%s\n", wil->fw_version); 2275 else 2276 seq_puts(s, "N/A\n"); 2277 2278 return 0; 2279 } 2280 2281 static int wil_fw_version_seq_open(struct inode *inode, struct file *file) 2282 { 2283 return single_open(file, wil_fw_version_debugfs_show, 2284 inode->i_private); 2285 } 2286 2287 static const struct file_operations fops_fw_version = { 2288 .open = wil_fw_version_seq_open, 2289 .release = single_release, 2290 .read = seq_read, 2291 .llseek = seq_lseek, 2292 }; 2293 2294 /*---------suspend_stats---------*/ 2295 static ssize_t wil_write_suspend_stats(struct file *file, 2296 const char __user *buf, 2297 size_t len, loff_t *ppos) 2298 { 2299 struct wil6210_priv *wil = file->private_data; 2300 2301 memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); 2302 2303 return len; 2304 } 2305 2306 static ssize_t wil_read_suspend_stats(struct file *file, 2307 char __user *user_buf, 2308 size_t count, loff_t *ppos) 2309 { 2310 struct wil6210_priv *wil = file->private_data; 2311 char *text; 2312 int n, ret, text_size = 500; 2313 2314 text = kmalloc(text_size, GFP_KERNEL); 2315 if (!text) 2316 return -ENOMEM; 2317 2318 n = snprintf(text, text_size, 2319 "Radio on suspend statistics:\n" 2320 "successful suspends:%ld failed suspends:%ld\n" 2321 "successful resumes:%ld failed resumes:%ld\n" 2322 "rejected by device:%ld\n" 2323 "Radio off suspend statistics:\n" 2324 "successful suspends:%ld failed suspends:%ld\n" 2325 "successful resumes:%ld failed resumes:%ld\n" 2326 "General statistics:\n" 2327 "rejected by host:%ld\n", 2328 wil->suspend_stats.r_on.successful_suspends, 2329 wil->suspend_stats.r_on.failed_suspends, 2330 wil->suspend_stats.r_on.successful_resumes, 2331 wil->suspend_stats.r_on.failed_resumes, 2332 wil->suspend_stats.rejected_by_device, 2333 wil->suspend_stats.r_off.successful_suspends, 2334 wil->suspend_stats.r_off.failed_suspends, 2335 wil->suspend_stats.r_off.successful_resumes, 2336 wil->suspend_stats.r_off.failed_resumes, 2337 wil->suspend_stats.rejected_by_host); 2338 2339 n = min_t(int, n, text_size); 2340 2341 ret = simple_read_from_buffer(user_buf, count, ppos, text, n); 2342 2343 kfree(text); 2344 2345 return ret; 2346 } 2347 2348 static const struct file_operations fops_suspend_stats = { 2349 .read = wil_read_suspend_stats, 2350 .write = wil_write_suspend_stats, 2351 .open = simple_open, 2352 }; 2353 2354 /*---------compressed_rx_status---------*/ 2355 static ssize_t wil_compressed_rx_status_write(struct file *file, 2356 const char __user *buf, 2357 size_t len, loff_t *ppos) 2358 { 2359 struct seq_file *s = file->private_data; 2360 struct wil6210_priv *wil = s->private; 2361 int compressed_rx_status; 2362 int rc; 2363 2364 rc = kstrtoint_from_user(buf, len, 0, &compressed_rx_status); 2365 if (rc) { 2366 wil_err(wil, "Invalid argument\n"); 2367 return rc; 2368 } 2369 2370 if (wil_has_active_ifaces(wil, true, false)) { 2371 wil_err(wil, "cannot change edma config after iface is up\n"); 2372 return -EPERM; 2373 } 2374 2375 wil_info(wil, "%sable compressed_rx_status\n", 2376 compressed_rx_status ? "En" : "Dis"); 2377 2378 wil->use_compressed_rx_status = compressed_rx_status; 2379 2380 return len; 2381 } 2382 2383 static int 2384 wil_compressed_rx_status_show(struct seq_file *s, void *data) 2385 { 2386 struct wil6210_priv *wil = s->private; 2387 2388 seq_printf(s, "%d\n", wil->use_compressed_rx_status); 2389 2390 return 0; 2391 } 2392 2393 static int 2394 wil_compressed_rx_status_seq_open(struct inode *inode, struct file *file) 2395 { 2396 return single_open(file, wil_compressed_rx_status_show, 2397 inode->i_private); 2398 } 2399 2400 static const struct file_operations fops_compressed_rx_status = { 2401 .open = wil_compressed_rx_status_seq_open, 2402 .release = single_release, 2403 .read = seq_read, 2404 .write = wil_compressed_rx_status_write, 2405 .llseek = seq_lseek, 2406 }; 2407 2408 /*----------------*/ 2409 static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, 2410 struct dentry *dbg) 2411 { 2412 int i; 2413 char name[32]; 2414 2415 for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { 2416 struct wil_blob_wrapper *wil_blob = &wil->blobs[i]; 2417 struct debugfs_blob_wrapper *blob = &wil_blob->blob; 2418 const struct fw_map *map = &fw_mapping[i]; 2419 2420 if (!map->name) 2421 continue; 2422 2423 wil_blob->wil = wil; 2424 blob->data = (void * __force)wil->csr + HOSTADDR(map->host); 2425 blob->size = map->to - map->from; 2426 snprintf(name, sizeof(name), "blob_%s", map->name); 2427 wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob); 2428 } 2429 } 2430 2431 /* misc files */ 2432 static const struct { 2433 const char *name; 2434 umode_t mode; 2435 const struct file_operations *fops; 2436 } dbg_files[] = { 2437 {"mbox", 0444, &fops_mbox}, 2438 {"rings", 0444, &fops_ring}, 2439 {"stations", 0444, &fops_sta}, 2440 {"mids", 0444, &fops_mids}, 2441 {"desc", 0444, &fops_txdesc}, 2442 {"bf", 0444, &fops_bf}, 2443 {"mem_val", 0644, &fops_memread}, 2444 {"rxon", 0244, &fops_rxon}, 2445 {"tx_mgmt", 0244, &fops_txmgmt}, 2446 {"wmi_send", 0244, &fops_wmi}, 2447 {"back", 0644, &fops_back}, 2448 {"pmccfg", 0644, &fops_pmccfg}, 2449 {"pmcdata", 0444, &fops_pmcdata}, 2450 {"temp", 0444, &fops_temp}, 2451 {"freq", 0444, &fops_freq}, 2452 {"link", 0444, &fops_link}, 2453 {"info", 0444, &fops_info}, 2454 {"recovery", 0644, &fops_recovery}, 2455 {"led_cfg", 0644, &fops_led_cfg}, 2456 {"led_blink_time", 0644, &fops_led_blink_time}, 2457 {"fw_capabilities", 0444, &fops_fw_capabilities}, 2458 {"fw_version", 0444, &fops_fw_version}, 2459 {"suspend_stats", 0644, &fops_suspend_stats}, 2460 {"compressed_rx_status", 0644, &fops_compressed_rx_status}, 2461 {"srings", 0444, &fops_srings}, 2462 {"status_msg", 0444, &fops_status_msg}, 2463 {"rx_buff_mgmt", 0444, &fops_rx_buff_mgmt}, 2464 {"tx_latency", 0644, &fops_tx_latency}, 2465 {"link_stats", 0644, &fops_link_stats}, 2466 {"link_stats_global", 0644, &fops_link_stats_global}, 2467 }; 2468 2469 static void wil6210_debugfs_init_files(struct wil6210_priv *wil, 2470 struct dentry *dbg) 2471 { 2472 int i; 2473 2474 for (i = 0; i < ARRAY_SIZE(dbg_files); i++) 2475 debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg, 2476 wil, dbg_files[i].fops); 2477 } 2478 2479 /* interrupt control blocks */ 2480 static const struct { 2481 const char *name; 2482 u32 icr_off; 2483 } dbg_icr[] = { 2484 {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)}, 2485 {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)}, 2486 {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)}, 2487 {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)}, 2488 }; 2489 2490 static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, 2491 struct dentry *dbg) 2492 { 2493 int i; 2494 2495 for (i = 0; i < ARRAY_SIZE(dbg_icr); i++) 2496 wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg, 2497 dbg_icr[i].icr_off); 2498 } 2499 2500 #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \ 2501 offsetof(struct wil6210_priv, name), type} 2502 2503 /* fields in struct wil6210_priv */ 2504 static const struct dbg_off dbg_wil_off[] = { 2505 WIL_FIELD(status[0], 0644, doff_ulong), 2506 WIL_FIELD(hw_version, 0444, doff_x32), 2507 WIL_FIELD(recovery_count, 0444, doff_u32), 2508 WIL_FIELD(discovery_mode, 0644, doff_u8), 2509 WIL_FIELD(chip_revision, 0444, doff_u8), 2510 WIL_FIELD(abft_len, 0644, doff_u8), 2511 WIL_FIELD(wakeup_trigger, 0644, doff_u8), 2512 WIL_FIELD(ring_idle_trsh, 0644, doff_u32), 2513 WIL_FIELD(num_rx_status_rings, 0644, doff_u8), 2514 WIL_FIELD(rx_status_ring_order, 0644, doff_u32), 2515 WIL_FIELD(tx_status_ring_order, 0644, doff_u32), 2516 WIL_FIELD(rx_buff_id_count, 0644, doff_u32), 2517 WIL_FIELD(amsdu_en, 0644, doff_u8), 2518 {}, 2519 }; 2520 2521 static const struct dbg_off dbg_wil_regs[] = { 2522 {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0), 2523 doff_io32}, 2524 {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32}, 2525 {}, 2526 }; 2527 2528 /* static parameters */ 2529 static const struct dbg_off dbg_statics[] = { 2530 {"desc_index", 0644, (ulong)&dbg_txdesc_index, doff_u32}, 2531 {"ring_index", 0644, (ulong)&dbg_ring_index, doff_u32}, 2532 {"mem_addr", 0644, (ulong)&mem_addr, doff_u32}, 2533 {"led_polarity", 0644, (ulong)&led_polarity, doff_u8}, 2534 {"status_index", 0644, (ulong)&dbg_status_msg_index, doff_u32}, 2535 {"sring_index", 0644, (ulong)&dbg_sring_index, doff_u32}, 2536 {}, 2537 }; 2538 2539 static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) + 2540 ARRAY_SIZE(dbg_wil_regs) - 1 + 2541 ARRAY_SIZE(pseudo_isr_off) - 1 + 2542 ARRAY_SIZE(lgc_itr_cnt_off) - 1 + 2543 ARRAY_SIZE(tx_itr_cnt_off) - 1 + 2544 ARRAY_SIZE(rx_itr_cnt_off) - 1; 2545 2546 int wil6210_debugfs_init(struct wil6210_priv *wil) 2547 { 2548 struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, 2549 wil_to_wiphy(wil)->debugfsdir); 2550 if (IS_ERR_OR_NULL(dbg)) 2551 return -ENODEV; 2552 2553 wil->dbg_data.data_arr = kcalloc(dbg_off_count, 2554 sizeof(struct wil_debugfs_iomem_data), 2555 GFP_KERNEL); 2556 if (!wil->dbg_data.data_arr) { 2557 debugfs_remove_recursive(dbg); 2558 wil->debug = NULL; 2559 return -ENOMEM; 2560 } 2561 2562 wil->dbg_data.iomem_data_count = 0; 2563 2564 wil_pmc_init(wil); 2565 2566 wil6210_debugfs_init_files(wil, dbg); 2567 wil6210_debugfs_init_isr(wil, dbg); 2568 wil6210_debugfs_init_blobs(wil, dbg); 2569 wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off); 2570 wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr, 2571 dbg_wil_regs); 2572 wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics); 2573 2574 wil6210_debugfs_create_pseudo_ISR(wil, dbg); 2575 2576 wil6210_debugfs_create_ITR_CNT(wil, dbg); 2577 2578 return 0; 2579 } 2580 2581 void wil6210_debugfs_remove(struct wil6210_priv *wil) 2582 { 2583 int i; 2584 2585 debugfs_remove_recursive(wil->debug); 2586 wil->debug = NULL; 2587 2588 kfree(wil->dbg_data.data_arr); 2589 for (i = 0; i < ARRAY_SIZE(wil->sta); i++) 2590 kfree(wil->sta[i].tx_latency_bins); 2591 2592 /* free pmc memory without sending command to fw, as it will 2593 * be reset on the way down anyway 2594 */ 2595 wil_pmc_free(wil, false); 2596 } 2597