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