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