1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * nxpwifi: debugfs 4 * 5 * Copyright 2011-2024 NXP 6 */ 7 8 #include <linux/debugfs.h> 9 10 #include "main.h" 11 #include "cmdevt.h" 12 #include "11n.h" 13 14 static struct dentry *nxpwifi_dfs_dir; 15 16 static char *bss_modes[] = { 17 "UNSPECIFIED", 18 "ADHOC", 19 "STATION", 20 "AP", 21 "AP_VLAN", 22 "WDS", 23 "MONITOR", 24 "MESH_POINT", 25 "P2P_CLIENT", 26 "P2P_GO", 27 "P2P_DEVICE", 28 }; 29 30 /* 31 * debugfs "info" read handler: dump driver name/version, interface, BSS mode, 32 * link state, MAC, counters; STA adds SSID/BSSID/channel/country/region and 33 * multicast list. 34 */ 35 static ssize_t 36 nxpwifi_info_read(struct file *file, char __user *ubuf, 37 size_t count, loff_t *ppos) 38 { 39 struct nxpwifi_private *priv = 40 (struct nxpwifi_private *)file->private_data; 41 struct net_device *netdev = priv->netdev; 42 struct netdev_hw_addr *ha; 43 struct netdev_queue *txq; 44 unsigned long page = get_zeroed_page(GFP_KERNEL); 45 char *p = (char *)page, fmt[64]; 46 struct nxpwifi_bss_info info; 47 ssize_t ret; 48 int i = 0; 49 50 if (!p) 51 return -ENOMEM; 52 53 memset(&info, 0, sizeof(info)); 54 ret = nxpwifi_get_bss_info(priv, &info); 55 if (ret) 56 goto free_and_exit; 57 58 nxpwifi_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); 59 60 nxpwifi_get_ver_ext(priv, 0); 61 62 p += sprintf(p, "driver_name = "); 63 p += sprintf(p, "\"nxpwifi\"\n"); 64 p += sprintf(p, "driver_version = %s", fmt); 65 p += sprintf(p, "\nverext = %s", priv->version_str); 66 p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); 67 68 if (info.bss_mode >= ARRAY_SIZE(bss_modes)) 69 p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); 70 else 71 p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); 72 73 p += sprintf(p, "media_state=\"%s\"\n", 74 (!priv->media_connected ? "Disconnected" : "Connected")); 75 p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); 76 77 if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA) { 78 p += sprintf(p, "multicast_count=\"%d\"\n", 79 netdev_mc_count(netdev)); 80 p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len, 81 info.ssid.ssid); 82 p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); 83 p += sprintf(p, "channel=\"%d\"\n", (int)info.bss_chan); 84 p += sprintf(p, "country_code = \"%s\"\n", info.country_code); 85 p += sprintf(p, "region_code=\"0x%x\"\n", 86 priv->adapter->region_code); 87 88 netdev_for_each_mc_addr(ha, netdev) 89 p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", 90 i++, ha->addr); 91 } 92 93 p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); 94 p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); 95 p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); 96 p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); 97 p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); 98 p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); 99 p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); 100 p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); 101 p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) 102 ? "on" : "off")); 103 p += sprintf(p, "tx queue"); 104 for (i = 0; i < netdev->num_tx_queues; i++) { 105 txq = netdev_get_tx_queue(netdev, i); 106 p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? 107 "stopped" : "started"); 108 } 109 p += sprintf(p, "\n"); 110 111 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 112 (unsigned long)p - page); 113 114 free_and_exit: 115 free_page(page); 116 return ret; 117 } 118 119 /* 120 * debugfs "getlog" read handler: dump firmware/802.11 counters (retry, RTS/ACK, dup, 121 * frag, mcast, FCS, beacon stats). 122 */ 123 static ssize_t 124 nxpwifi_getlog_read(struct file *file, char __user *ubuf, 125 size_t count, loff_t *ppos) 126 { 127 struct nxpwifi_private *priv = 128 (struct nxpwifi_private *)file->private_data; 129 unsigned long page = get_zeroed_page(GFP_KERNEL); 130 char *p = (char *)page; 131 ssize_t ret; 132 struct nxpwifi_ds_get_stats stats; 133 134 if (!p) 135 return -ENOMEM; 136 137 memset(&stats, 0, sizeof(stats)); 138 ret = nxpwifi_get_stats_info(priv, &stats); 139 if (ret) 140 goto free_and_exit; 141 142 p += sprintf(p, "\n" 143 "mcasttxframe %u\n" 144 "failed %u\n" 145 "retry %u\n" 146 "multiretry %u\n" 147 "framedup %u\n" 148 "rtssuccess %u\n" 149 "rtsfailure %u\n" 150 "ackfailure %u\n" 151 "rxfrag %u\n" 152 "mcastrxframe %u\n" 153 "fcserror %u\n" 154 "txframe %u\n" 155 "wepicverrcnt-1 %u\n" 156 "wepicverrcnt-2 %u\n" 157 "wepicverrcnt-3 %u\n" 158 "wepicverrcnt-4 %u\n" 159 "bcn_rcv_cnt %u\n" 160 "bcn_miss_cnt %u\n", 161 stats.mcast_tx_frame, 162 stats.failed, 163 stats.retry, 164 stats.multi_retry, 165 stats.frame_dup, 166 stats.rts_success, 167 stats.rts_failure, 168 stats.ack_failure, 169 stats.rx_frag, 170 stats.mcast_rx_frame, 171 stats.fcs_error, 172 stats.tx_frame, 173 stats.wep_icv_error[0], 174 stats.wep_icv_error[1], 175 stats.wep_icv_error[2], 176 stats.wep_icv_error[3], 177 stats.bcn_rcv_cnt, 178 stats.bcn_miss_cnt); 179 180 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 181 (unsigned long)p - page); 182 183 free_and_exit: 184 free_page(page); 185 return ret; 186 } 187 188 /* 189 * debugfs "histogram" read handler: report sample count and per-rate/SNR/noise 190 * floor/signal strength histograms. 191 */ 192 static ssize_t 193 nxpwifi_histogram_read(struct file *file, char __user *ubuf, 194 size_t count, loff_t *ppos) 195 { 196 struct nxpwifi_private *priv = 197 (struct nxpwifi_private *)file->private_data; 198 ssize_t ret; 199 struct nxpwifi_histogram_data *phist_data; 200 int i, value; 201 unsigned long page = get_zeroed_page(GFP_KERNEL); 202 char *p = (char *)page; 203 204 if (!p) 205 return -ENOMEM; 206 207 if (!priv || !priv->hist_data) { 208 ret = -EFAULT; 209 goto free_and_exit; 210 } 211 212 phist_data = priv->hist_data; 213 214 p += sprintf(p, "\n" 215 "total samples = %d\n", 216 atomic_read(&phist_data->num_samples)); 217 218 p += sprintf(p, 219 "rx rates (in Mbps): 0=1M 1=2M 2=5.5M 3=11M 4=6M 5=9M 6=12M\n" 220 "7=18M 8=24M 9=36M 10=48M 11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); 221 222 if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 223 p += sprintf(p, 224 "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n"); 225 } else { 226 p += sprintf(p, "\n"); 227 } 228 229 for (i = 0; i < NXPWIFI_MAX_RX_RATES; i++) { 230 value = atomic_read(&phist_data->rx_rate[i]); 231 if (value) 232 p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); 233 } 234 235 if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 236 for (i = NXPWIFI_MAX_RX_RATES; i < NXPWIFI_MAX_AC_RX_RATES; 237 i++) { 238 value = atomic_read(&phist_data->rx_rate[i]); 239 if (value) 240 p += sprintf(p, "rx_rate[%02d] = %d\n", 241 i, value); 242 } 243 } 244 245 for (i = 0; i < NXPWIFI_MAX_SNR; i++) { 246 value = atomic_read(&phist_data->snr[i]); 247 if (value) 248 p += sprintf(p, "snr[%02ddB] = %d\n", i, value); 249 } 250 for (i = 0; i < NXPWIFI_MAX_NOISE_FLR; i++) { 251 value = atomic_read(&phist_data->noise_flr[i]); 252 if (value) 253 p += sprintf(p, "noise_flr[%02ddBm] = %d\n", 254 (int)(i - 128), value); 255 } 256 for (i = 0; i < NXPWIFI_MAX_SIG_STRENGTH; i++) { 257 value = atomic_read(&phist_data->sig_str[i]); 258 if (value) 259 p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", 260 i, value); 261 } 262 263 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 264 (unsigned long)p - page); 265 266 free_and_exit: 267 free_page(page); 268 return ret; 269 } 270 271 static ssize_t 272 nxpwifi_histogram_write(struct file *file, const char __user *ubuf, 273 size_t count, loff_t *ppos) 274 { 275 struct nxpwifi_private *priv = (void *)file->private_data; 276 277 if (priv && priv->hist_data) 278 nxpwifi_hist_data_reset(priv); 279 return 0; 280 } 281 282 static struct nxpwifi_debug_info info; 283 284 /* debugfs "debug" read handler: dump adapter debug info and BA/reorder tables. */ 285 static ssize_t 286 nxpwifi_debug_read(struct file *file, char __user *ubuf, 287 size_t count, loff_t *ppos) 288 { 289 struct nxpwifi_private *priv = 290 (struct nxpwifi_private *)file->private_data; 291 unsigned long page = get_zeroed_page(GFP_KERNEL); 292 char *p = (char *)page; 293 ssize_t ret; 294 295 if (!p) 296 return -ENOMEM; 297 298 ret = nxpwifi_get_debug_info(priv, &info); 299 if (ret) 300 goto free_and_exit; 301 302 p += nxpwifi_debug_info_to_buffer(priv, p, &info); 303 304 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 305 (unsigned long)p - page); 306 307 free_and_exit: 308 free_page(page); 309 return ret; 310 } 311 312 static u32 saved_reg_type, saved_reg_offset, saved_reg_value; 313 314 /* 315 * debugfs "regrdwr" write handler: parse <type offset value> and store for 316 * readback/IO. 317 */ 318 static ssize_t 319 nxpwifi_regrdwr_write(struct file *file, 320 const char __user *ubuf, size_t count, loff_t *ppos) 321 { 322 char *buf; 323 int ret; 324 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; 325 int rv; 326 327 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 328 if (IS_ERR(buf)) 329 return PTR_ERR(buf); 330 331 rv = sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); 332 333 if (rv != 3) { 334 ret = -EINVAL; 335 goto done; 336 } 337 338 if (reg_type == 0 || reg_offset == 0) { 339 ret = -EINVAL; 340 goto done; 341 } else { 342 saved_reg_type = reg_type; 343 saved_reg_offset = reg_offset; 344 saved_reg_value = reg_value; 345 ret = count; 346 } 347 done: 348 kfree(buf); 349 return ret; 350 } 351 352 /* 353 * debugfs "regrdwr" read handler: perform pending register read/write and return 354 * <type offset value>. 355 */ 356 static ssize_t 357 nxpwifi_regrdwr_read(struct file *file, char __user *ubuf, 358 size_t count, loff_t *ppos) 359 { 360 struct nxpwifi_private *priv = 361 (struct nxpwifi_private *)file->private_data; 362 unsigned long addr = get_zeroed_page(GFP_KERNEL); 363 char *buf = (char *)addr; 364 int pos = 0, ret = 0; 365 u32 reg_value; 366 367 if (!buf) 368 return -ENOMEM; 369 370 if (!saved_reg_type) { 371 /* No command has been given */ 372 pos += snprintf(buf, PAGE_SIZE, "0"); 373 goto done; 374 } 375 /* Set command has been given */ 376 if (saved_reg_value != UINT_MAX) { 377 ret = nxpwifi_reg_write(priv, saved_reg_type, saved_reg_offset, 378 saved_reg_value); 379 380 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", 381 saved_reg_type, saved_reg_offset, 382 saved_reg_value); 383 384 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 385 386 goto done; 387 } 388 /* Get command has been given */ 389 ret = nxpwifi_reg_read(priv, saved_reg_type, 390 saved_reg_offset, ®_value); 391 if (ret) { 392 ret = -EINVAL; 393 goto done; 394 } 395 396 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, 397 saved_reg_offset, reg_value); 398 399 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 400 401 done: 402 free_page(addr); 403 return ret; 404 } 405 406 /* debugfs "debug_mask" read handler: show driver debug mask. */ 407 408 static ssize_t 409 nxpwifi_debug_mask_read(struct file *file, char __user *ubuf, 410 size_t count, loff_t *ppos) 411 { 412 struct nxpwifi_private *priv = 413 (struct nxpwifi_private *)file->private_data; 414 unsigned long page = get_zeroed_page(GFP_KERNEL); 415 char *buf = (char *)page; 416 size_t ret = 0; 417 int pos = 0; 418 419 if (!buf) 420 return -ENOMEM; 421 422 pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n", 423 priv->adapter->debug_mask); 424 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 425 426 free_page(page); 427 return ret; 428 } 429 430 /* debugfs "debug_mask" write handler: set driver debug mask. */ 431 432 static ssize_t 433 nxpwifi_debug_mask_write(struct file *file, const char __user *ubuf, 434 size_t count, loff_t *ppos) 435 { 436 int ret; 437 unsigned long debug_mask; 438 struct nxpwifi_private *priv = (void *)file->private_data; 439 char *buf; 440 441 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 442 if (IS_ERR(buf)) 443 return PTR_ERR(buf); 444 445 if (kstrtoul(buf, 0, &debug_mask)) { 446 ret = -EINVAL; 447 goto done; 448 } 449 450 priv->adapter->debug_mask = debug_mask; 451 ret = count; 452 done: 453 kfree(buf); 454 return ret; 455 } 456 457 /* debugfs "verext" write handler: select extended version string. */ 458 static ssize_t 459 nxpwifi_verext_write(struct file *file, const char __user *ubuf, 460 size_t count, loff_t *ppos) 461 { 462 int ret; 463 u32 versionstrsel; 464 struct nxpwifi_private *priv = (void *)file->private_data; 465 466 ret = kstrtou32_from_user(ubuf, count, 10, &versionstrsel); 467 if (ret) 468 return ret; 469 470 priv->versionstrsel = versionstrsel; 471 472 return count; 473 } 474 475 /* debugfs "verext" read handler: show extended version string. */ 476 static ssize_t 477 nxpwifi_verext_read(struct file *file, char __user *ubuf, 478 size_t count, loff_t *ppos) 479 { 480 struct nxpwifi_private *priv = 481 (struct nxpwifi_private *)file->private_data; 482 char buf[256]; 483 int ret; 484 485 nxpwifi_get_ver_ext(priv, priv->versionstrsel); 486 ret = snprintf(buf, sizeof(buf), "version string: %s\n", 487 priv->version_str); 488 489 return simple_read_from_buffer(ubuf, count, ppos, buf, ret); 490 } 491 492 /* debugfs "memrw" write handler: read/write firmware memory (addr, value). */ 493 static ssize_t 494 nxpwifi_memrw_write(struct file *file, const char __user *ubuf, size_t count, 495 loff_t *ppos) 496 { 497 int ret; 498 char cmd; 499 struct nxpwifi_ds_mem_rw mem_rw; 500 u16 cmd_action; 501 struct nxpwifi_private *priv = (void *)file->private_data; 502 char *buf; 503 504 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 505 if (IS_ERR(buf)) 506 return PTR_ERR(buf); 507 508 ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value); 509 if (ret != 3) { 510 ret = -EINVAL; 511 goto done; 512 } 513 514 if ((cmd == 'r') || (cmd == 'R')) { 515 cmd_action = HOST_ACT_GEN_GET; 516 mem_rw.value = 0; 517 } else if ((cmd == 'w') || (cmd == 'W')) { 518 cmd_action = HOST_ACT_GEN_SET; 519 } else { 520 ret = -EINVAL; 521 goto done; 522 } 523 524 memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw)); 525 ret = nxpwifi_send_cmd(priv, HOST_CMD_MEM_ACCESS, cmd_action, 0, 526 &mem_rw, true); 527 if (!ret) 528 ret = count; 529 530 done: 531 kfree(buf); 532 return ret; 533 } 534 535 /* debugfs "memrw" read handler: show last memory access result. */ 536 static ssize_t 537 nxpwifi_memrw_read(struct file *file, char __user *ubuf, 538 size_t count, loff_t *ppos) 539 { 540 struct nxpwifi_private *priv = (void *)file->private_data; 541 unsigned long addr = get_zeroed_page(GFP_KERNEL); 542 char *buf = (char *)addr; 543 int ret, pos = 0; 544 545 if (!buf) 546 return -ENOMEM; 547 548 pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr, 549 priv->mem_rw.value); 550 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 551 552 free_page(addr); 553 return ret; 554 } 555 556 static u32 saved_offset = -1, saved_bytes = -1; 557 558 /* debugfs "rdeeprom" write handler: set EEPROM offset/length to read. */ 559 static ssize_t 560 nxpwifi_rdeeprom_write(struct file *file, 561 const char __user *ubuf, size_t count, loff_t *ppos) 562 { 563 char *buf; 564 int ret = 0; 565 int offset = -1, bytes = -1; 566 int rv; 567 568 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 569 if (IS_ERR(buf)) 570 return PTR_ERR(buf); 571 572 rv = sscanf(buf, "%d %d", &offset, &bytes); 573 574 if (rv != 2) { 575 ret = -EINVAL; 576 goto done; 577 } 578 579 if (offset == -1 || bytes == -1) { 580 ret = -EINVAL; 581 goto done; 582 } else { 583 saved_offset = offset; 584 saved_bytes = bytes; 585 ret = count; 586 } 587 done: 588 kfree(buf); 589 return ret; 590 } 591 592 /* debugfs "rdeeprom" read handler: dump EEPROM bytes from saved offset/length. */ 593 static ssize_t 594 nxpwifi_rdeeprom_read(struct file *file, char __user *ubuf, 595 size_t count, loff_t *ppos) 596 { 597 struct nxpwifi_private *priv = 598 (struct nxpwifi_private *)file->private_data; 599 unsigned long addr = get_zeroed_page(GFP_KERNEL); 600 char *buf = (char *)addr; 601 int pos, ret, i; 602 u8 value[MAX_EEPROM_DATA]; 603 604 if (!buf) 605 return -ENOMEM; 606 607 if (saved_offset == -1) { 608 /* No command has been given */ 609 pos = snprintf(buf, PAGE_SIZE, "0"); 610 goto done; 611 } 612 613 /* Get command has been given */ 614 ret = nxpwifi_eeprom_read(priv, (u16)saved_offset, 615 (u16)saved_bytes, value); 616 if (ret) { 617 ret = -EINVAL; 618 goto out_free; 619 } 620 621 pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); 622 623 for (i = 0; i < saved_bytes; i++) 624 pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); 625 626 done: 627 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 628 out_free: 629 free_page(addr); 630 return ret; 631 } 632 633 /* 634 * debugfs "hscfg" write handler: configure host-sleep (conditions/gpio/gap) or 635 * cancel. 636 */ 637 static ssize_t 638 nxpwifi_hscfg_write(struct file *file, const char __user *ubuf, 639 size_t count, loff_t *ppos) 640 { 641 struct nxpwifi_private *priv = (void *)file->private_data; 642 char *buf; 643 int ret, arg_num; 644 struct nxpwifi_ds_hs_cfg hscfg; 645 int conditions = HS_CFG_COND_DEF; 646 u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; 647 648 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 649 if (IS_ERR(buf)) 650 return PTR_ERR(buf); 651 652 arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); 653 654 memset(&hscfg, 0, sizeof(struct nxpwifi_ds_hs_cfg)); 655 656 if (arg_num > 3) { 657 nxpwifi_dbg(priv->adapter, ERROR, 658 "Too many arguments\n"); 659 ret = -EINVAL; 660 goto done; 661 } 662 663 if (arg_num >= 1 && arg_num < 3) 664 nxpwifi_set_hs_params(priv, HOST_ACT_GEN_GET, 665 NXPWIFI_SYNC_CMD, &hscfg); 666 667 if (arg_num) { 668 if (conditions == HS_CFG_CANCEL) { 669 nxpwifi_cancel_hs(priv, NXPWIFI_ASYNC_CMD); 670 ret = count; 671 goto done; 672 } 673 hscfg.conditions = conditions; 674 } 675 if (arg_num >= 2) 676 hscfg.gpio = gpio; 677 if (arg_num == 3) 678 hscfg.gap = gap; 679 680 hscfg.is_invoke_hostcmd = false; 681 nxpwifi_set_hs_params(priv, HOST_ACT_GEN_SET, 682 NXPWIFI_SYNC_CMD, &hscfg); 683 684 nxpwifi_enable_hs(priv->adapter); 685 clear_bit(NXPWIFI_IS_HS_ENABLING, &priv->adapter->work_flags); 686 ret = count; 687 done: 688 kfree(buf); 689 return ret; 690 } 691 692 /* debugfs "hscfg" read handler: show current host-sleep configuration. */ 693 static ssize_t 694 nxpwifi_hscfg_read(struct file *file, char __user *ubuf, 695 size_t count, loff_t *ppos) 696 { 697 struct nxpwifi_private *priv = (void *)file->private_data; 698 unsigned long addr = get_zeroed_page(GFP_KERNEL); 699 char *buf = (char *)addr; 700 int pos, ret; 701 struct nxpwifi_ds_hs_cfg hscfg; 702 703 if (!buf) 704 return -ENOMEM; 705 706 nxpwifi_set_hs_params(priv, HOST_ACT_GEN_GET, 707 NXPWIFI_SYNC_CMD, &hscfg); 708 709 pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, 710 hscfg.gpio, hscfg.gap); 711 712 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 713 714 free_page(addr); 715 return ret; 716 } 717 718 static ssize_t 719 nxpwifi_timeshare_coex_read(struct file *file, char __user *ubuf, 720 size_t count, loff_t *ppos) 721 { 722 struct nxpwifi_private *priv = file->private_data; 723 char buf[3]; 724 bool timeshare_coex; 725 int ret; 726 unsigned int len; 727 728 if (priv->adapter->fw_api_ver != NXPWIFI_FW_V15) 729 return -EOPNOTSUPP; 730 731 ret = nxpwifi_send_cmd(priv, HOST_CMD_ROBUST_COEX, 732 HOST_ACT_GEN_GET, 0, ×hare_coex, true); 733 if (ret) 734 return ret; 735 736 len = sprintf(buf, "%d\n", timeshare_coex); 737 return simple_read_from_buffer(ubuf, count, ppos, buf, len); 738 } 739 740 static ssize_t 741 nxpwifi_timeshare_coex_write(struct file *file, const char __user *ubuf, 742 size_t count, loff_t *ppos) 743 { 744 bool timeshare_coex; 745 struct nxpwifi_private *priv = file->private_data; 746 int ret; 747 748 if (priv->adapter->fw_api_ver != NXPWIFI_FW_V15) 749 return -EOPNOTSUPP; 750 751 ret = kstrtobool_from_user(ubuf, count, ×hare_coex); 752 if (ret) 753 return ret; 754 755 ret = nxpwifi_send_cmd(priv, HOST_CMD_ROBUST_COEX, 756 HOST_ACT_GEN_SET, 0, ×hare_coex, true); 757 if (ret) 758 return ret; 759 else 760 return count; 761 } 762 763 static ssize_t 764 nxpwifi_reset_write(struct file *file, 765 const char __user *ubuf, size_t count, loff_t *ppos) 766 { 767 struct nxpwifi_private *priv = file->private_data; 768 struct nxpwifi_adapter *adapter = priv->adapter; 769 bool result; 770 int rc; 771 772 rc = kstrtobool_from_user(ubuf, count, &result); 773 if (rc) 774 return rc; 775 776 if (!result) 777 return -EINVAL; 778 779 if (adapter->if_ops.card_reset) { 780 nxpwifi_dbg(adapter, INFO, "Resetting per request\n"); 781 adapter->if_ops.card_reset(adapter); 782 } 783 784 return count; 785 } 786 787 static ssize_t 788 nxpwifi_fake_radar_detect_write(struct file *file, 789 const char __user *ubuf, 790 size_t count, loff_t *ppos) 791 { 792 struct nxpwifi_private *priv = file->private_data; 793 struct nxpwifi_adapter *adapter = priv->adapter; 794 bool result; 795 int rc; 796 797 rc = kstrtobool_from_user(ubuf, count, &result); 798 if (rc) 799 return rc; 800 801 if (!result) 802 return -EINVAL; 803 804 if (priv->wdev.links[0].cac_started) { 805 nxpwifi_dbg(adapter, MSG, 806 "Generate fake radar detected during CAC\n"); 807 if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef)) 808 nxpwifi_dbg(adapter, ERROR, 809 "Failed to stop CAC in FW\n"); 810 wiphy_delayed_work_cancel(priv->adapter->wiphy, &priv->dfs_cac_work); 811 cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, 812 NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0); 813 cfg80211_radar_event(adapter->wiphy, &priv->dfs_chandef, 814 GFP_KERNEL); 815 } else { 816 if (priv->bss_chandef.chan->dfs_cac_ms) { 817 nxpwifi_dbg(adapter, MSG, 818 "Generate fake radar detected\n"); 819 cfg80211_radar_event(adapter->wiphy, 820 &priv->dfs_chandef, 821 GFP_KERNEL); 822 } 823 } 824 825 return count; 826 } 827 828 static ssize_t 829 nxpwifi_netmon_write(struct file *file, const char __user *ubuf, 830 size_t count, loff_t *ppos) 831 { 832 int ret; 833 struct nxpwifi_802_11_net_monitor netmon_cfg; 834 struct nxpwifi_private *priv = (void *)file->private_data; 835 char *buf; 836 837 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 838 if (IS_ERR(buf)) 839 return PTR_ERR(buf); 840 memset(&netmon_cfg, 0, sizeof(struct nxpwifi_802_11_net_monitor)); 841 ret = sscanf(buf, "%u %u %u %u %u", 842 &netmon_cfg.enable_net_mon, 843 &netmon_cfg.filter_flag, 844 &netmon_cfg.band, 845 &netmon_cfg.channel, 846 &netmon_cfg.chan_bandwidth); 847 848 ret = nxpwifi_send_cmd(priv, HOST_CMD_802_11_NET_MONITOR, 849 HOST_ACT_GEN_SET, 0, &netmon_cfg, true); 850 851 if (!ret) 852 ret = count; 853 854 kfree(buf); 855 return ret; 856 } 857 858 static ssize_t 859 nxpwifi_twt_setup_write(struct file *file, const char __user *ubuf, 860 size_t count, loff_t *ppos) 861 { 862 int ret; 863 struct nxpwifi_twt_cfg twt_cfg; 864 struct nxpwifi_private *priv = (void *)file->private_data; 865 char *buf; 866 u16 twt_mantissa, bcn_miss_threshold; 867 868 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 869 if (IS_ERR(buf)) 870 return PTR_ERR(buf); 871 872 ret = sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu %hu %hhu %hu", 873 &twt_cfg.param.twt_setup.implicit, 874 &twt_cfg.param.twt_setup.announced, 875 &twt_cfg.param.twt_setup.trigger_enabled, 876 &twt_cfg.param.twt_setup.twt_info_disabled, 877 &twt_cfg.param.twt_setup.negotiation_type, 878 &twt_cfg.param.twt_setup.twt_wakeup_duration, 879 &twt_cfg.param.twt_setup.flow_identifier, 880 &twt_cfg.param.twt_setup.hard_constraint, 881 &twt_cfg.param.twt_setup.twt_exponent, 882 &twt_mantissa, 883 &twt_cfg.param.twt_setup.twt_request, 884 &bcn_miss_threshold); 885 886 twt_cfg.param.twt_setup.twt_mantissa = cpu_to_le16(twt_mantissa); 887 twt_cfg.param.twt_setup.bcn_miss_threshold = cpu_to_le16(bcn_miss_threshold); 888 twt_cfg.sub_id = NXPWIFI_11AX_TWT_SETUP_SUBID; 889 ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_SET, 0, 890 &twt_cfg, true); 891 if (!ret) 892 ret = count; 893 894 kfree(buf); 895 return ret; 896 } 897 898 static ssize_t 899 nxpwifi_twt_teardown_write(struct file *file, const char __user *ubuf, 900 size_t count, loff_t *ppos) 901 { 902 int ret; 903 struct nxpwifi_twt_cfg twt_cfg; 904 struct nxpwifi_private *priv = (void *)file->private_data; 905 char *buf; 906 907 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 908 if (IS_ERR(buf)) 909 return PTR_ERR(buf); 910 911 ret = sscanf(buf, "%hhu %hhu %hhu", 912 &twt_cfg.param.twt_teardown.flow_identifier, 913 &twt_cfg.param.twt_teardown.negotiation_type, 914 &twt_cfg.param.twt_teardown.teardown_all_twt); 915 916 twt_cfg.sub_id = NXPWIFI_11AX_TWT_TEARDOWN_SUBID; 917 ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_SET, 0, 918 &twt_cfg, true); 919 920 if (!ret) 921 ret = count; 922 923 kfree(buf); 924 return ret; 925 } 926 927 static ssize_t 928 nxpwifi_twt_report_read(struct file *file, char __user *ubuf, 929 size_t count, loff_t *ppos) 930 { 931 struct nxpwifi_private *priv = 932 (struct nxpwifi_private *)file->private_data; 933 unsigned long page = get_zeroed_page(GFP_KERNEL); 934 char *p = (char *)page; 935 ssize_t ret; 936 struct nxpwifi_twt_cfg twt_cfg; 937 u8 num, i, j; 938 939 if (!p) 940 return -ENOMEM; 941 942 twt_cfg.sub_id = NXPWIFI_11AX_TWT_REPORT_SUBID; 943 ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_GET, 0, 944 &twt_cfg, true); 945 if (ret) 946 goto done; 947 num = twt_cfg.param.twt_report.length / NXPWIFI_BTWT_REPORT_LEN; 948 num = num <= NXPWIFI_BTWT_REPORT_MAX_NUM ? num : NXPWIFI_BTWT_REPORT_MAX_NUM; 949 p += sprintf(p, "\ntwt_report len %hhu, num %hhu, twt_report_info:\n", 950 twt_cfg.param.twt_report.length, num); 951 for (i = 0; i < num; i++) { 952 p += sprintf(p, "id[%hu]:\r\n", i); 953 for (j = 0; j < NXPWIFI_BTWT_REPORT_LEN; j++) { 954 p += sprintf(p, 955 " 0x%02x", 956 twt_cfg.param.twt_report.data[i * NXPWIFI_BTWT_REPORT_LEN + j]); 957 } 958 p += sprintf(p, "\r\n"); 959 } 960 961 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 962 (unsigned long)p - page); 963 964 done: 965 free_page(page); 966 return ret; 967 } 968 969 static ssize_t 970 nxpwifi_twt_information_write(struct file *file, const char __user *ubuf, 971 size_t count, loff_t *ppos) 972 { 973 int ret; 974 struct nxpwifi_twt_cfg twt_cfg; 975 struct nxpwifi_private *priv = (void *)file->private_data; 976 char *buf; 977 u32 suspend_duration; 978 979 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 980 if (IS_ERR(buf)) 981 return PTR_ERR(buf); 982 983 ret = sscanf(buf, "%hhu %u", 984 &twt_cfg.param.twt_information.flow_identifier, &suspend_duration); 985 twt_cfg.param.twt_information.suspend_duration = cpu_to_le32(suspend_duration); 986 987 twt_cfg.sub_id = NXPWIFI_11AX_TWT_INFORMATION_SUBID; 988 ret = nxpwifi_send_cmd(priv, HOST_CMD_TWT_CFG, HOST_ACT_GEN_SET, 0, 989 &twt_cfg, true); 990 991 if (!ret) 992 ret = count; 993 994 kfree(buf); 995 return ret; 996 } 997 998 #define NXPWIFI_DFS_ADD_FILE(name) debugfs_create_file(#name, 0644, \ 999 priv->dfs_dev_dir, priv, \ 1000 &nxpwifi_dfs_##name##_fops) 1001 1002 #define NXPWIFI_DFS_FILE_OPS(name) \ 1003 static const struct file_operations nxpwifi_dfs_##name##_fops = { \ 1004 .read = nxpwifi_##name##_read, \ 1005 .write = nxpwifi_##name##_write, \ 1006 .open = simple_open, \ 1007 } 1008 1009 #define NXPWIFI_DFS_FILE_READ_OPS(name) \ 1010 static const struct file_operations nxpwifi_dfs_##name##_fops = { \ 1011 .read = nxpwifi_##name##_read, \ 1012 .open = simple_open, \ 1013 } 1014 1015 #define NXPWIFI_DFS_FILE_WRITE_OPS(name) \ 1016 static const struct file_operations nxpwifi_dfs_##name##_fops = { \ 1017 .write = nxpwifi_##name##_write, \ 1018 .open = simple_open, \ 1019 } 1020 1021 NXPWIFI_DFS_FILE_READ_OPS(info); 1022 NXPWIFI_DFS_FILE_READ_OPS(debug); 1023 NXPWIFI_DFS_FILE_READ_OPS(getlog); 1024 NXPWIFI_DFS_FILE_OPS(regrdwr); 1025 NXPWIFI_DFS_FILE_OPS(rdeeprom); 1026 NXPWIFI_DFS_FILE_OPS(memrw); 1027 NXPWIFI_DFS_FILE_OPS(hscfg); 1028 NXPWIFI_DFS_FILE_OPS(histogram); 1029 NXPWIFI_DFS_FILE_OPS(debug_mask); 1030 NXPWIFI_DFS_FILE_OPS(timeshare_coex); 1031 NXPWIFI_DFS_FILE_WRITE_OPS(reset); 1032 NXPWIFI_DFS_FILE_WRITE_OPS(fake_radar_detect); 1033 NXPWIFI_DFS_FILE_OPS(verext); 1034 NXPWIFI_DFS_FILE_WRITE_OPS(netmon); 1035 NXPWIFI_DFS_FILE_WRITE_OPS(twt_setup); 1036 NXPWIFI_DFS_FILE_WRITE_OPS(twt_teardown); 1037 NXPWIFI_DFS_FILE_READ_OPS(twt_report); 1038 NXPWIFI_DFS_FILE_WRITE_OPS(twt_information); 1039 1040 /* Create per-netdev debugfs directory and files. */ 1041 void 1042 nxpwifi_dev_debugfs_init(struct nxpwifi_private *priv) 1043 { 1044 if (!nxpwifi_dfs_dir || !priv) 1045 return; 1046 1047 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, 1048 nxpwifi_dfs_dir); 1049 1050 NXPWIFI_DFS_ADD_FILE(info); 1051 NXPWIFI_DFS_ADD_FILE(debug); 1052 NXPWIFI_DFS_ADD_FILE(getlog); 1053 NXPWIFI_DFS_ADD_FILE(regrdwr); 1054 NXPWIFI_DFS_ADD_FILE(rdeeprom); 1055 1056 NXPWIFI_DFS_ADD_FILE(memrw); 1057 NXPWIFI_DFS_ADD_FILE(hscfg); 1058 NXPWIFI_DFS_ADD_FILE(histogram); 1059 NXPWIFI_DFS_ADD_FILE(debug_mask); 1060 NXPWIFI_DFS_ADD_FILE(timeshare_coex); 1061 NXPWIFI_DFS_ADD_FILE(reset); 1062 NXPWIFI_DFS_ADD_FILE(fake_radar_detect); 1063 NXPWIFI_DFS_ADD_FILE(verext); 1064 NXPWIFI_DFS_ADD_FILE(netmon); 1065 NXPWIFI_DFS_ADD_FILE(twt_setup); 1066 NXPWIFI_DFS_ADD_FILE(twt_teardown); 1067 NXPWIFI_DFS_ADD_FILE(twt_report); 1068 NXPWIFI_DFS_ADD_FILE(twt_information); 1069 } 1070 1071 /* Remove per-netdev debugfs directory and files. */ 1072 void 1073 nxpwifi_dev_debugfs_remove(struct nxpwifi_private *priv) 1074 { 1075 if (!priv) 1076 return; 1077 1078 debugfs_remove_recursive(priv->dfs_dev_dir); 1079 } 1080 1081 /* Create top-level debugfs directory. */ 1082 void 1083 nxpwifi_debugfs_init(void) 1084 { 1085 if (!nxpwifi_dfs_dir) 1086 nxpwifi_dfs_dir = debugfs_create_dir("nxpwifi", NULL); 1087 } 1088 1089 /* Remove top-level debugfs directory. */ 1090 void 1091 nxpwifi_debugfs_remove(void) 1092 { 1093 debugfs_remove(nxpwifi_dfs_dir); 1094 } 1095