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