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