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