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