2709 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2005-2011 Atheros Communications Inc.4 * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.5 * Copyright (c) 2018, The Linux Foundation. All rights reserved.6 * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.7 */8 9#include <linux/module.h>10#include <linux/debugfs.h>11#include <linux/vmalloc.h>12#include <linux/crc32.h>13#include <linux/firmware.h>14#include <linux/kstrtox.h>15 16#include "core.h"17#include "debug.h"18#include "hif.h"19#include "wmi-ops.h"20 21/* ms */22#define ATH10K_DEBUG_HTT_STATS_INTERVAL 100023 24#define ATH10K_DEBUG_CAL_DATA_LEN 1206425 26void ath10k_info(struct ath10k *ar, const char *fmt, ...)27{28 struct va_format vaf = {29 .fmt = fmt,30 };31 va_list args;32 33 va_start(args, fmt);34 vaf.va = &args;35 dev_info(ar->dev, "%pV", &vaf);36 trace_ath10k_log_info(ar, &vaf);37 va_end(args);38}39EXPORT_SYMBOL(ath10k_info);40 41void ath10k_debug_print_hwfw_info(struct ath10k *ar)42{43 const struct firmware *firmware;44 char fw_features[128] = {};45 u32 crc = 0;46 47 ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));48 49 ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x",50 ar->hw_params.name,51 ar->target_version,52 ar->bus_param.chip_id,53 ar->id.subsystem_vendor, ar->id.subsystem_device);54 55 ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n",56 IS_ENABLED(CONFIG_ATH10K_DEBUG),57 IS_ENABLED(CONFIG_ATH10K_DEBUGFS),58 IS_ENABLED(CONFIG_ATH10K_TRACING),59 IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED),60 IS_ENABLED(CONFIG_NL80211_TESTMODE));61 62 firmware = ar->normal_mode_fw.fw_file.firmware;63 if (firmware)64 crc = crc32_le(0, firmware->data, firmware->size);65 66 ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",67 ar->hw->wiphy->fw_version,68 ar->fw_api,69 fw_features,70 crc);71}72 73void ath10k_debug_print_board_info(struct ath10k *ar)74{75 char boardinfo[100];76 const struct firmware *board;77 u32 crc;78 79 if (ar->id.bmi_ids_valid)80 scnprintf(boardinfo, sizeof(boardinfo), "%d:%d",81 ar->id.bmi_chip_id, ar->id.bmi_board_id);82 else83 scnprintf(boardinfo, sizeof(boardinfo), "N/A");84 85 board = ar->normal_mode_fw.board;86 if (!IS_ERR_OR_NULL(board))87 crc = crc32_le(0, board->data, board->size);88 else89 crc = 0;90 91 ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x",92 ar->bd_api,93 boardinfo,94 crc);95}96 97void ath10k_debug_print_boot_info(struct ath10k *ar)98{99 ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n",100 ar->htt.target_version_major,101 ar->htt.target_version_minor,102 ar->normal_mode_fw.fw_file.wmi_op_version,103 ar->normal_mode_fw.fw_file.htt_op_version,104 ath10k_cal_mode_str(ar->cal_mode),105 ar->max_num_stations,106 test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),107 !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags));108}109 110void ath10k_print_driver_info(struct ath10k *ar)111{112 ath10k_debug_print_hwfw_info(ar);113 ath10k_debug_print_board_info(ar);114 ath10k_debug_print_boot_info(ar);115}116EXPORT_SYMBOL(ath10k_print_driver_info);117 118void ath10k_err(struct ath10k *ar, const char *fmt, ...)119{120 struct va_format vaf = {121 .fmt = fmt,122 };123 va_list args;124 125 va_start(args, fmt);126 vaf.va = &args;127 dev_err(ar->dev, "%pV", &vaf);128 trace_ath10k_log_err(ar, &vaf);129 va_end(args);130}131EXPORT_SYMBOL(ath10k_err);132 133void ath10k_warn(struct ath10k *ar, const char *fmt, ...)134{135 struct va_format vaf = {136 .fmt = fmt,137 };138 va_list args;139 140 va_start(args, fmt);141 vaf.va = &args;142 dev_warn_ratelimited(ar->dev, "%pV", &vaf);143 trace_ath10k_log_warn(ar, &vaf);144 145 va_end(args);146}147EXPORT_SYMBOL(ath10k_warn);148 149#ifdef CONFIG_ATH10K_DEBUGFS150 151static ssize_t ath10k_read_wmi_services(struct file *file,152 char __user *user_buf,153 size_t count, loff_t *ppos)154{155 struct ath10k *ar = file->private_data;156 char *buf;157 size_t len = 0, buf_len = 8192;158 const char *name;159 ssize_t ret_cnt;160 bool enabled;161 int i;162 163 buf = kzalloc(buf_len, GFP_KERNEL);164 if (!buf)165 return -ENOMEM;166 167 mutex_lock(&ar->conf_mutex);168 169 spin_lock_bh(&ar->data_lock);170 for (i = 0; i < WMI_SERVICE_MAX; i++) {171 enabled = test_bit(i, ar->wmi.svc_map);172 name = wmi_service_name(i);173 174 if (!name) {175 if (enabled)176 len += scnprintf(buf + len, buf_len - len,177 "%-40s %s (bit %d)\n",178 "unknown", "enabled", i);179 180 continue;181 }182 183 len += scnprintf(buf + len, buf_len - len,184 "%-40s %s\n",185 name, enabled ? "enabled" : "-");186 }187 spin_unlock_bh(&ar->data_lock);188 189 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);190 191 mutex_unlock(&ar->conf_mutex);192 193 kfree(buf);194 return ret_cnt;195}196 197static const struct file_operations fops_wmi_services = {198 .read = ath10k_read_wmi_services,199 .open = simple_open,200 .owner = THIS_MODULE,201 .llseek = default_llseek,202};203 204static void ath10k_fw_stats_pdevs_free(struct list_head *head)205{206 struct ath10k_fw_stats_pdev *i, *tmp;207 208 list_for_each_entry_safe(i, tmp, head, list) {209 list_del(&i->list);210 kfree(i);211 }212}213 214static void ath10k_fw_stats_vdevs_free(struct list_head *head)215{216 struct ath10k_fw_stats_vdev *i, *tmp;217 218 list_for_each_entry_safe(i, tmp, head, list) {219 list_del(&i->list);220 kfree(i);221 }222}223 224static void ath10k_fw_stats_peers_free(struct list_head *head)225{226 struct ath10k_fw_stats_peer *i, *tmp;227 228 list_for_each_entry_safe(i, tmp, head, list) {229 list_del(&i->list);230 kfree(i);231 }232}233 234static void ath10k_fw_extd_stats_peers_free(struct list_head *head)235{236 struct ath10k_fw_extd_stats_peer *i, *tmp;237 238 list_for_each_entry_safe(i, tmp, head, list) {239 list_del(&i->list);240 kfree(i);241 }242}243 244static void ath10k_debug_fw_stats_reset(struct ath10k *ar)245{246 spin_lock_bh(&ar->data_lock);247 ar->debug.fw_stats_done = false;248 ar->debug.fw_stats.extended = false;249 ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);250 ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);251 ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);252 ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);253 spin_unlock_bh(&ar->data_lock);254}255 256void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)257{258 struct ath10k_fw_stats stats = {};259 bool is_start, is_started, is_end;260 size_t num_peers;261 size_t num_vdevs;262 int ret;263 264 INIT_LIST_HEAD(&stats.pdevs);265 INIT_LIST_HEAD(&stats.vdevs);266 INIT_LIST_HEAD(&stats.peers);267 INIT_LIST_HEAD(&stats.peers_extd);268 269 spin_lock_bh(&ar->data_lock);270 ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);271 if (ret) {272 ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);273 goto free;274 }275 276 /* Stat data may exceed htc-wmi buffer limit. In such case firmware277 * splits the stats data and delivers it in a ping-pong fashion of278 * request cmd-update event.279 *280 * However there is no explicit end-of-data. Instead start-of-data is281 * used as an implicit one. This works as follows:282 * a) discard stat update events until one with pdev stats is283 * delivered - this skips session started at end of (b)284 * b) consume stat update events until another one with pdev stats is285 * delivered which is treated as end-of-data and is itself discarded286 */287 if (ath10k_peer_stats_enabled(ar))288 ath10k_sta_update_rx_duration(ar, &stats);289 290 if (ar->debug.fw_stats_done) {291 if (!ath10k_peer_stats_enabled(ar))292 ath10k_warn(ar, "received unsolicited stats update event\n");293 294 goto free;295 }296 297 num_peers = list_count_nodes(&ar->debug.fw_stats.peers);298 num_vdevs = list_count_nodes(&ar->debug.fw_stats.vdevs);299 is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&300 !list_empty(&stats.pdevs));301 is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&302 !list_empty(&stats.pdevs));303 304 if (is_start)305 list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);306 307 if (is_end)308 ar->debug.fw_stats_done = true;309 310 if (stats.extended)311 ar->debug.fw_stats.extended = true;312 313 is_started = !list_empty(&ar->debug.fw_stats.pdevs);314 315 if (is_started && !is_end) {316 if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) {317 /* Although this is unlikely impose a sane limit to318 * prevent firmware from DoS-ing the host.319 */320 ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);321 ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);322 ath10k_warn(ar, "dropping fw peer stats\n");323 goto free;324 }325 326 if (num_vdevs >= BITS_PER_LONG) {327 ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);328 ath10k_warn(ar, "dropping fw vdev stats\n");329 goto free;330 }331 332 if (!list_empty(&stats.peers))333 list_splice_tail_init(&stats.peers_extd,334 &ar->debug.fw_stats.peers_extd);335 336 list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);337 list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);338 }339 340 complete(&ar->debug.fw_stats_complete);341 342free:343 /* In some cases lists have been spliced and cleared. Free up344 * resources if that is not the case.345 */346 ath10k_fw_stats_pdevs_free(&stats.pdevs);347 ath10k_fw_stats_vdevs_free(&stats.vdevs);348 ath10k_fw_stats_peers_free(&stats.peers);349 ath10k_fw_extd_stats_peers_free(&stats.peers_extd);350 351 spin_unlock_bh(&ar->data_lock);352}353 354int ath10k_debug_fw_stats_request(struct ath10k *ar)355{356 unsigned long timeout, time_left;357 int ret;358 359 lockdep_assert_held(&ar->conf_mutex);360 361 timeout = jiffies + msecs_to_jiffies(1 * HZ);362 363 ath10k_debug_fw_stats_reset(ar);364 365 for (;;) {366 if (time_after(jiffies, timeout))367 return -ETIMEDOUT;368 369 reinit_completion(&ar->debug.fw_stats_complete);370 371 ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);372 if (ret) {373 ath10k_warn(ar, "could not request stats (%d)\n", ret);374 return ret;375 }376 377 time_left =378 wait_for_completion_timeout(&ar->debug.fw_stats_complete,379 1 * HZ);380 if (!time_left)381 return -ETIMEDOUT;382 383 spin_lock_bh(&ar->data_lock);384 if (ar->debug.fw_stats_done) {385 spin_unlock_bh(&ar->data_lock);386 break;387 }388 spin_unlock_bh(&ar->data_lock);389 }390 391 return 0;392}393 394static int ath10k_fw_stats_open(struct inode *inode, struct file *file)395{396 struct ath10k *ar = inode->i_private;397 void *buf = NULL;398 int ret;399 400 mutex_lock(&ar->conf_mutex);401 402 if (ar->state != ATH10K_STATE_ON) {403 ret = -ENETDOWN;404 goto err_unlock;405 }406 407 buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE);408 if (!buf) {409 ret = -ENOMEM;410 goto err_unlock;411 }412 413 ret = ath10k_debug_fw_stats_request(ar);414 if (ret) {415 ath10k_warn(ar, "failed to request fw stats: %d\n", ret);416 goto err_free;417 }418 419 ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf);420 if (ret) {421 ath10k_warn(ar, "failed to fill fw stats: %d\n", ret);422 goto err_free;423 }424 425 file->private_data = buf;426 427 mutex_unlock(&ar->conf_mutex);428 return 0;429 430err_free:431 vfree(buf);432 433err_unlock:434 mutex_unlock(&ar->conf_mutex);435 return ret;436}437 438static int ath10k_fw_stats_release(struct inode *inode, struct file *file)439{440 vfree(file->private_data);441 442 return 0;443}444 445static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,446 size_t count, loff_t *ppos)447{448 const char *buf = file->private_data;449 size_t len = strlen(buf);450 451 return simple_read_from_buffer(user_buf, count, ppos, buf, len);452}453 454static const struct file_operations fops_fw_stats = {455 .open = ath10k_fw_stats_open,456 .release = ath10k_fw_stats_release,457 .read = ath10k_fw_stats_read,458 .owner = THIS_MODULE,459 .llseek = default_llseek,460};461 462static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,463 char __user *user_buf,464 size_t count, loff_t *ppos)465{466 struct ath10k *ar = file->private_data;467 int ret;468 size_t len = 0, buf_len = 500;469 char *buf;470 471 buf = kmalloc(buf_len, GFP_KERNEL);472 if (!buf)473 return -ENOMEM;474 475 spin_lock_bh(&ar->data_lock);476 477 len += scnprintf(buf + len, buf_len - len,478 "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);479 len += scnprintf(buf + len, buf_len - len,480 "fw_warm_reset_counter\t\t%d\n",481 ar->stats.fw_warm_reset_counter);482 len += scnprintf(buf + len, buf_len - len,483 "fw_cold_reset_counter\t\t%d\n",484 ar->stats.fw_cold_reset_counter);485 486 spin_unlock_bh(&ar->data_lock);487 488 ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);489 490 kfree(buf);491 492 return ret;493}494 495static const struct file_operations fops_fw_reset_stats = {496 .open = simple_open,497 .read = ath10k_debug_fw_reset_stats_read,498 .owner = THIS_MODULE,499 .llseek = default_llseek,500};501 502/* This is a clean assert crash in firmware. */503static int ath10k_debug_fw_assert(struct ath10k *ar)504{505 struct wmi_vdev_install_key_cmd *cmd;506 struct sk_buff *skb;507 508 skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16);509 if (!skb)510 return -ENOMEM;511 512 cmd = (struct wmi_vdev_install_key_cmd *)skb->data;513 memset(cmd, 0, sizeof(*cmd));514 515 /* big enough number so that firmware asserts */516 cmd->vdev_id = __cpu_to_le32(0x7ffe);517 518 return ath10k_wmi_cmd_send(ar, skb,519 ar->wmi.cmd->vdev_install_key_cmdid);520}521 522static ssize_t ath10k_read_simulate_fw_crash(struct file *file,523 char __user *user_buf,524 size_t count, loff_t *ppos)525{526 const char buf[] =527 "To simulate firmware crash write one of the keywords to this file:\n"528 "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n"529 "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n"530 "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n"531 "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";532 533 return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));534}535 536/* Simulate firmware crash:537 * 'soft': Call wmi command causing firmware hang. This firmware hang is538 * recoverable by warm firmware reset.539 * 'hard': Force firmware crash by setting any vdev parameter for not allowed540 * vdev id. This is hard firmware crash because it is recoverable only by cold541 * firmware reset.542 */543static ssize_t ath10k_write_simulate_fw_crash(struct file *file,544 const char __user *user_buf,545 size_t count, loff_t *ppos)546{547 struct ath10k *ar = file->private_data;548 char buf[32] = {0};549 ssize_t rc;550 int ret;551 552 /* filter partial writes and invalid commands */553 if (*ppos != 0 || count >= sizeof(buf) || count == 0)554 return -EINVAL;555 556 rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);557 if (rc < 0)558 return rc;559 560 /* drop the possible '\n' from the end */561 if (buf[*ppos - 1] == '\n')562 buf[*ppos - 1] = '\0';563 564 mutex_lock(&ar->conf_mutex);565 566 if (ar->state != ATH10K_STATE_ON &&567 ar->state != ATH10K_STATE_RESTARTED) {568 ret = -ENETDOWN;569 goto exit;570 }571 572 if (!strcmp(buf, "soft")) {573 ath10k_info(ar, "simulating soft firmware crash\n");574 ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);575 } else if (!strcmp(buf, "hard")) {576 ath10k_info(ar, "simulating hard firmware crash\n");577 /* 0x7fff is vdev id, and it is always out of range for all578 * firmware variants in order to force a firmware crash.579 */580 ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,581 ar->wmi.vdev_param->rts_threshold,582 0);583 } else if (!strcmp(buf, "assert")) {584 ath10k_info(ar, "simulating firmware assert crash\n");585 ret = ath10k_debug_fw_assert(ar);586 } else if (!strcmp(buf, "hw-restart")) {587 ath10k_info(ar, "user requested hw restart\n");588 ath10k_core_start_recovery(ar);589 ret = 0;590 } else {591 ret = -EINVAL;592 goto exit;593 }594 595 if (ret) {596 ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);597 goto exit;598 }599 600 ret = count;601 602exit:603 mutex_unlock(&ar->conf_mutex);604 return ret;605}606 607static const struct file_operations fops_simulate_fw_crash = {608 .read = ath10k_read_simulate_fw_crash,609 .write = ath10k_write_simulate_fw_crash,610 .open = simple_open,611 .owner = THIS_MODULE,612 .llseek = default_llseek,613};614 615static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,616 size_t count, loff_t *ppos)617{618 struct ath10k *ar = file->private_data;619 size_t len;620 char buf[50];621 622 len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->bus_param.chip_id);623 624 return simple_read_from_buffer(user_buf, count, ppos, buf, len);625}626 627static const struct file_operations fops_chip_id = {628 .read = ath10k_read_chip_id,629 .open = simple_open,630 .owner = THIS_MODULE,631 .llseek = default_llseek,632};633 634static ssize_t ath10k_reg_addr_read(struct file *file,635 char __user *user_buf,636 size_t count, loff_t *ppos)637{638 struct ath10k *ar = file->private_data;639 u8 buf[32];640 size_t len = 0;641 u32 reg_addr;642 643 mutex_lock(&ar->conf_mutex);644 reg_addr = ar->debug.reg_addr;645 mutex_unlock(&ar->conf_mutex);646 647 len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);648 649 return simple_read_from_buffer(user_buf, count, ppos, buf, len);650}651 652static ssize_t ath10k_reg_addr_write(struct file *file,653 const char __user *user_buf,654 size_t count, loff_t *ppos)655{656 struct ath10k *ar = file->private_data;657 u32 reg_addr;658 int ret;659 660 ret = kstrtou32_from_user(user_buf, count, 0, ®_addr);661 if (ret)662 return ret;663 664 if (!IS_ALIGNED(reg_addr, 4))665 return -EFAULT;666 667 mutex_lock(&ar->conf_mutex);668 ar->debug.reg_addr = reg_addr;669 mutex_unlock(&ar->conf_mutex);670 671 return count;672}673 674static const struct file_operations fops_reg_addr = {675 .read = ath10k_reg_addr_read,676 .write = ath10k_reg_addr_write,677 .open = simple_open,678 .owner = THIS_MODULE,679 .llseek = default_llseek,680};681 682static ssize_t ath10k_reg_value_read(struct file *file,683 char __user *user_buf,684 size_t count, loff_t *ppos)685{686 struct ath10k *ar = file->private_data;687 u8 buf[48];688 size_t len;689 u32 reg_addr, reg_val;690 int ret;691 692 mutex_lock(&ar->conf_mutex);693 694 if (ar->state != ATH10K_STATE_ON &&695 ar->state != ATH10K_STATE_UTF) {696 ret = -ENETDOWN;697 goto exit;698 }699 700 reg_addr = ar->debug.reg_addr;701 702 reg_val = ath10k_hif_read32(ar, reg_addr);703 len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);704 705 ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);706 707exit:708 mutex_unlock(&ar->conf_mutex);709 710 return ret;711}712 713static ssize_t ath10k_reg_value_write(struct file *file,714 const char __user *user_buf,715 size_t count, loff_t *ppos)716{717 struct ath10k *ar = file->private_data;718 u32 reg_addr, reg_val;719 int ret;720 721 mutex_lock(&ar->conf_mutex);722 723 if (ar->state != ATH10K_STATE_ON &&724 ar->state != ATH10K_STATE_UTF) {725 ret = -ENETDOWN;726 goto exit;727 }728 729 reg_addr = ar->debug.reg_addr;730 731 ret = kstrtou32_from_user(user_buf, count, 0, ®_val);732 if (ret)733 goto exit;734 735 ath10k_hif_write32(ar, reg_addr, reg_val);736 737 ret = count;738 739exit:740 mutex_unlock(&ar->conf_mutex);741 742 return ret;743}744 745static const struct file_operations fops_reg_value = {746 .read = ath10k_reg_value_read,747 .write = ath10k_reg_value_write,748 .open = simple_open,749 .owner = THIS_MODULE,750 .llseek = default_llseek,751};752 753static ssize_t ath10k_mem_value_read(struct file *file,754 char __user *user_buf,755 size_t count, loff_t *ppos)756{757 struct ath10k *ar = file->private_data;758 u8 *buf;759 int ret;760 761 if (*ppos < 0)762 return -EINVAL;763 764 if (!count)765 return 0;766 767 mutex_lock(&ar->conf_mutex);768 769 buf = vmalloc(count);770 if (!buf) {771 ret = -ENOMEM;772 goto exit;773 }774 775 if (ar->state != ATH10K_STATE_ON &&776 ar->state != ATH10K_STATE_UTF) {777 ret = -ENETDOWN;778 goto exit;779 }780 781 ret = ath10k_hif_diag_read(ar, *ppos, buf, count);782 if (ret) {783 ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",784 (u32)(*ppos), ret);785 goto exit;786 }787 788 ret = copy_to_user(user_buf, buf, count);789 if (ret) {790 ret = -EFAULT;791 goto exit;792 }793 794 count -= ret;795 *ppos += count;796 ret = count;797 798exit:799 vfree(buf);800 mutex_unlock(&ar->conf_mutex);801 802 return ret;803}804 805static ssize_t ath10k_mem_value_write(struct file *file,806 const char __user *user_buf,807 size_t count, loff_t *ppos)808{809 struct ath10k *ar = file->private_data;810 u8 *buf;811 int ret;812 813 if (*ppos < 0)814 return -EINVAL;815 816 if (!count)817 return 0;818 819 mutex_lock(&ar->conf_mutex);820 821 buf = vmalloc(count);822 if (!buf) {823 ret = -ENOMEM;824 goto exit;825 }826 827 if (ar->state != ATH10K_STATE_ON &&828 ar->state != ATH10K_STATE_UTF) {829 ret = -ENETDOWN;830 goto exit;831 }832 833 ret = copy_from_user(buf, user_buf, count);834 if (ret) {835 ret = -EFAULT;836 goto exit;837 }838 839 ret = ath10k_hif_diag_write(ar, *ppos, buf, count);840 if (ret) {841 ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",842 (u32)(*ppos), ret);843 goto exit;844 }845 846 *ppos += count;847 ret = count;848 849exit:850 vfree(buf);851 mutex_unlock(&ar->conf_mutex);852 853 return ret;854}855 856static const struct file_operations fops_mem_value = {857 .read = ath10k_mem_value_read,858 .write = ath10k_mem_value_write,859 .open = simple_open,860 .owner = THIS_MODULE,861 .llseek = default_llseek,862};863 864static int ath10k_debug_htt_stats_req(struct ath10k *ar)865{866 u64 cookie;867 int ret;868 869 lockdep_assert_held(&ar->conf_mutex);870 871 if (ar->debug.htt_stats_mask == 0)872 /* htt stats are disabled */873 return 0;874 875 if (ar->state != ATH10K_STATE_ON)876 return 0;877 878 cookie = get_jiffies_64();879 880 ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,881 ar->debug.reset_htt_stats, cookie);882 if (ret) {883 ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);884 return ret;885 }886 887 queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork,888 msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL));889 890 return 0;891}892 893static void ath10k_debug_htt_stats_dwork(struct work_struct *work)894{895 struct ath10k *ar = container_of(work, struct ath10k,896 debug.htt_stats_dwork.work);897 898 mutex_lock(&ar->conf_mutex);899 900 ath10k_debug_htt_stats_req(ar);901 902 mutex_unlock(&ar->conf_mutex);903}904 905static ssize_t ath10k_read_htt_stats_mask(struct file *file,906 char __user *user_buf,907 size_t count, loff_t *ppos)908{909 struct ath10k *ar = file->private_data;910 char buf[32];911 size_t len;912 913 len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);914 915 return simple_read_from_buffer(user_buf, count, ppos, buf, len);916}917 918static ssize_t ath10k_write_htt_stats_mask(struct file *file,919 const char __user *user_buf,920 size_t count, loff_t *ppos)921{922 struct ath10k *ar = file->private_data;923 unsigned long mask;924 int ret;925 926 ret = kstrtoul_from_user(user_buf, count, 0, &mask);927 if (ret)928 return ret;929 930 /* max 17 bit masks (for now) */931 if (mask > HTT_STATS_BIT_MASK)932 return -E2BIG;933 934 mutex_lock(&ar->conf_mutex);935 936 ar->debug.htt_stats_mask = mask;937 938 ret = ath10k_debug_htt_stats_req(ar);939 if (ret)940 goto out;941 942 ret = count;943 944out:945 mutex_unlock(&ar->conf_mutex);946 947 return ret;948}949 950static const struct file_operations fops_htt_stats_mask = {951 .read = ath10k_read_htt_stats_mask,952 .write = ath10k_write_htt_stats_mask,953 .open = simple_open,954 .owner = THIS_MODULE,955 .llseek = default_llseek,956};957 958static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,959 char __user *user_buf,960 size_t count, loff_t *ppos)961{962 struct ath10k *ar = file->private_data;963 char buf[64];964 u8 amsdu, ampdu;965 size_t len;966 967 mutex_lock(&ar->conf_mutex);968 969 amsdu = ar->htt.max_num_amsdu;970 ampdu = ar->htt.max_num_ampdu;971 mutex_unlock(&ar->conf_mutex);972 973 len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu);974 975 return simple_read_from_buffer(user_buf, count, ppos, buf, len);976}977 978static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,979 const char __user *user_buf,980 size_t count, loff_t *ppos)981{982 struct ath10k *ar = file->private_data;983 int res;984 char buf[64] = {0};985 unsigned int amsdu, ampdu;986 987 res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,988 user_buf, count);989 if (res <= 0)990 return res;991 992 res = sscanf(buf, "%u %u", &amsdu, &du);993 994 if (res != 2)995 return -EINVAL;996 997 mutex_lock(&ar->conf_mutex);998 999 res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu);1000 if (res)1001 goto out;1002 1003 res = count;1004 ar->htt.max_num_amsdu = amsdu;1005 ar->htt.max_num_ampdu = ampdu;1006 1007out:1008 mutex_unlock(&ar->conf_mutex);1009 return res;1010}1011 1012static const struct file_operations fops_htt_max_amsdu_ampdu = {1013 .read = ath10k_read_htt_max_amsdu_ampdu,1014 .write = ath10k_write_htt_max_amsdu_ampdu,1015 .open = simple_open,1016 .owner = THIS_MODULE,1017 .llseek = default_llseek,1018};1019 1020static ssize_t ath10k_read_fw_dbglog(struct file *file,1021 char __user *user_buf,1022 size_t count, loff_t *ppos)1023{1024 struct ath10k *ar = file->private_data;1025 size_t len;1026 char buf[96];1027 1028 len = scnprintf(buf, sizeof(buf), "0x%16llx %u\n",1029 ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level);1030 1031 return simple_read_from_buffer(user_buf, count, ppos, buf, len);1032}1033 1034static ssize_t ath10k_write_fw_dbglog(struct file *file,1035 const char __user *user_buf,1036 size_t count, loff_t *ppos)1037{1038 struct ath10k *ar = file->private_data;1039 int ret;1040 char buf[96] = {0};1041 unsigned int log_level;1042 u64 mask;1043 1044 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,1045 user_buf, count);1046 if (ret <= 0)1047 return ret;1048 1049 ret = sscanf(buf, "%llx %u", &mask, &log_level);1050 1051 if (!ret)1052 return -EINVAL;1053 1054 if (ret == 1)1055 /* default if user did not specify */1056 log_level = ATH10K_DBGLOG_LEVEL_WARN;1057 1058 mutex_lock(&ar->conf_mutex);1059 1060 ar->debug.fw_dbglog_mask = mask;1061 ar->debug.fw_dbglog_level = log_level;1062 1063 if (ar->state == ATH10K_STATE_ON) {1064 ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,1065 ar->debug.fw_dbglog_level);1066 if (ret) {1067 ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",1068 ret);1069 goto exit;1070 }1071 }1072 1073 ret = count;1074 1075exit:1076 mutex_unlock(&ar->conf_mutex);1077 1078 return ret;1079}1080 1081/* TODO: Would be nice to always support ethtool stats, would need to1082 * move the stats storage out of ath10k_debug, or always have ath10k_debug1083 * struct available..1084 */1085 1086/* This generally corresponds to the debugfs fw_stats file */1087static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {1088 "tx_pkts_nic",1089 "tx_bytes_nic",1090 "rx_pkts_nic",1091 "rx_bytes_nic",1092 "d_noise_floor",1093 "d_cycle_count",1094 "d_phy_error",1095 "d_rts_bad",1096 "d_rts_good",1097 "d_tx_power", /* in .5 dbM I think */1098 "d_rx_crc_err", /* fcs_bad */1099 "d_rx_crc_err_drop", /* frame with FCS error, dropped late in kernel */1100 "d_no_beacon",1101 "d_tx_mpdus_queued",1102 "d_tx_msdu_queued",1103 "d_tx_msdu_dropped",1104 "d_local_enqued",1105 "d_local_freed",1106 "d_tx_ppdu_hw_queued",1107 "d_tx_ppdu_reaped",1108 "d_tx_fifo_underrun",1109 "d_tx_ppdu_abort",1110 "d_tx_mpdu_requeued",1111 "d_tx_excessive_retries",1112 "d_tx_hw_rate",1113 "d_tx_dropped_sw_retries",1114 "d_tx_illegal_rate",1115 "d_tx_continuous_xretries",1116 "d_tx_timeout",1117 "d_tx_mpdu_txop_limit",1118 "d_pdev_resets",1119 "d_rx_mid_ppdu_route_change",1120 "d_rx_status",1121 "d_rx_extra_frags_ring0",1122 "d_rx_extra_frags_ring1",1123 "d_rx_extra_frags_ring2",1124 "d_rx_extra_frags_ring3",1125 "d_rx_msdu_htt",1126 "d_rx_mpdu_htt",1127 "d_rx_msdu_stack",1128 "d_rx_mpdu_stack",1129 "d_rx_phy_err",1130 "d_rx_phy_err_drops",1131 "d_rx_mpdu_errors", /* FCS, MIC, ENC */1132 "d_fw_crash_count",1133 "d_fw_warm_reset_count",1134 "d_fw_cold_reset_count",1135};1136 1137#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)1138 1139void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,1140 struct ieee80211_vif *vif,1141 u32 sset, u8 *data)1142{1143 if (sset == ETH_SS_STATS)1144 memcpy(data, ath10k_gstrings_stats,1145 sizeof(ath10k_gstrings_stats));1146}1147 1148int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,1149 struct ieee80211_vif *vif, int sset)1150{1151 if (sset == ETH_SS_STATS)1152 return ATH10K_SSTATS_LEN;1153 1154 return 0;1155}1156 1157void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,1158 struct ieee80211_vif *vif,1159 struct ethtool_stats *stats, u64 *data)1160{1161 struct ath10k *ar = hw->priv;1162 static const struct ath10k_fw_stats_pdev zero_stats = {};1163 const struct ath10k_fw_stats_pdev *pdev_stats;1164 int i = 0, ret;1165 1166 mutex_lock(&ar->conf_mutex);1167 1168 if (ar->state == ATH10K_STATE_ON) {1169 ret = ath10k_debug_fw_stats_request(ar);1170 if (ret) {1171 /* just print a warning and try to use older results */1172 ath10k_warn(ar,1173 "failed to get fw stats for ethtool: %d\n",1174 ret);1175 }1176 }1177 1178 pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs,1179 struct ath10k_fw_stats_pdev,1180 list);1181 if (!pdev_stats) {1182 /* no results available so just return zeroes */1183 pdev_stats = &zero_stats;1184 }1185 1186 spin_lock_bh(&ar->data_lock);1187 1188 data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */1189 data[i++] = 0; /* tx bytes */1190 data[i++] = pdev_stats->htt_mpdus;1191 data[i++] = 0; /* rx bytes */1192 data[i++] = pdev_stats->ch_noise_floor;1193 data[i++] = pdev_stats->cycle_count;1194 data[i++] = pdev_stats->phy_err_count;1195 data[i++] = pdev_stats->rts_bad;1196 data[i++] = pdev_stats->rts_good;1197 data[i++] = pdev_stats->chan_tx_power;1198 data[i++] = pdev_stats->fcs_bad;1199 data[i++] = ar->stats.rx_crc_err_drop;1200 data[i++] = pdev_stats->no_beacons;1201 data[i++] = pdev_stats->mpdu_enqued;1202 data[i++] = pdev_stats->msdu_enqued;1203 data[i++] = pdev_stats->wmm_drop;1204 data[i++] = pdev_stats->local_enqued;1205 data[i++] = pdev_stats->local_freed;1206 data[i++] = pdev_stats->hw_queued;1207 data[i++] = pdev_stats->hw_reaped;1208 data[i++] = pdev_stats->underrun;1209 data[i++] = pdev_stats->tx_abort;1210 data[i++] = pdev_stats->mpdus_requeued;1211 data[i++] = pdev_stats->tx_ko;1212 data[i++] = pdev_stats->data_rc;1213 data[i++] = pdev_stats->sw_retry_failure;1214 data[i++] = pdev_stats->illgl_rate_phy_err;1215 data[i++] = pdev_stats->pdev_cont_xretry;1216 data[i++] = pdev_stats->pdev_tx_timeout;1217 data[i++] = pdev_stats->txop_ovf;1218 data[i++] = pdev_stats->pdev_resets;1219 data[i++] = pdev_stats->mid_ppdu_route_change;1220 data[i++] = pdev_stats->status_rcvd;1221 data[i++] = pdev_stats->r0_frags;1222 data[i++] = pdev_stats->r1_frags;1223 data[i++] = pdev_stats->r2_frags;1224 data[i++] = pdev_stats->r3_frags;1225 data[i++] = pdev_stats->htt_msdus;1226 data[i++] = pdev_stats->htt_mpdus;1227 data[i++] = pdev_stats->loc_msdus;1228 data[i++] = pdev_stats->loc_mpdus;1229 data[i++] = pdev_stats->phy_errs;1230 data[i++] = pdev_stats->phy_err_drop;1231 data[i++] = pdev_stats->mpdu_errs;1232 data[i++] = ar->stats.fw_crash_counter;1233 data[i++] = ar->stats.fw_warm_reset_counter;1234 data[i++] = ar->stats.fw_cold_reset_counter;1235 1236 spin_unlock_bh(&ar->data_lock);1237 1238 mutex_unlock(&ar->conf_mutex);1239 1240 WARN_ON(i != ATH10K_SSTATS_LEN);1241}1242 1243static const struct file_operations fops_fw_dbglog = {1244 .read = ath10k_read_fw_dbglog,1245 .write = ath10k_write_fw_dbglog,1246 .open = simple_open,1247 .owner = THIS_MODULE,1248 .llseek = default_llseek,1249};1250 1251static int ath10k_debug_cal_data_fetch(struct ath10k *ar)1252{1253 u32 hi_addr;1254 __le32 addr;1255 int ret;1256 1257 lockdep_assert_held(&ar->conf_mutex);1258 1259 if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN))1260 return -EINVAL;1261 1262 if (ar->hw_params.cal_data_len == 0)1263 return -EOPNOTSUPP;1264 1265 hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));1266 1267 ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));1268 if (ret) {1269 ath10k_warn(ar, "failed to read hi_board_data address: %d\n",1270 ret);1271 return ret;1272 }1273 1274 ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data,1275 ar->hw_params.cal_data_len);1276 if (ret) {1277 ath10k_warn(ar, "failed to read calibration data: %d\n", ret);1278 return ret;1279 }1280 1281 return 0;1282}1283 1284static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)1285{1286 struct ath10k *ar = inode->i_private;1287 1288 mutex_lock(&ar->conf_mutex);1289 1290 if (ar->state == ATH10K_STATE_ON ||1291 ar->state == ATH10K_STATE_UTF) {1292 ath10k_debug_cal_data_fetch(ar);1293 }1294 1295 file->private_data = ar;1296 mutex_unlock(&ar->conf_mutex);1297 1298 return 0;1299}1300 1301static ssize_t ath10k_debug_cal_data_read(struct file *file,1302 char __user *user_buf,1303 size_t count, loff_t *ppos)1304{1305 struct ath10k *ar = file->private_data;1306 1307 mutex_lock(&ar->conf_mutex);1308 1309 count = simple_read_from_buffer(user_buf, count, ppos,1310 ar->debug.cal_data,1311 ar->hw_params.cal_data_len);1312 1313 mutex_unlock(&ar->conf_mutex);1314 1315 return count;1316}1317 1318static ssize_t ath10k_write_ani_enable(struct file *file,1319 const char __user *user_buf,1320 size_t count, loff_t *ppos)1321{1322 struct ath10k *ar = file->private_data;1323 int ret;1324 u8 enable;1325 1326 if (kstrtou8_from_user(user_buf, count, 0, &enable))1327 return -EINVAL;1328 1329 mutex_lock(&ar->conf_mutex);1330 1331 if (ar->ani_enabled == enable) {1332 ret = count;1333 goto exit;1334 }1335 1336 ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable,1337 enable);1338 if (ret) {1339 ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret);1340 goto exit;1341 }1342 ar->ani_enabled = enable;1343 1344 ret = count;1345 1346exit:1347 mutex_unlock(&ar->conf_mutex);1348 1349 return ret;1350}1351 1352static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,1353 size_t count, loff_t *ppos)1354{1355 struct ath10k *ar = file->private_data;1356 size_t len;1357 char buf[32];1358 1359 len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled);1360 1361 return simple_read_from_buffer(user_buf, count, ppos, buf, len);1362}1363 1364static const struct file_operations fops_ani_enable = {1365 .read = ath10k_read_ani_enable,1366 .write = ath10k_write_ani_enable,1367 .open = simple_open,1368 .owner = THIS_MODULE,1369 .llseek = default_llseek,1370};1371 1372static const struct file_operations fops_cal_data = {1373 .open = ath10k_debug_cal_data_open,1374 .read = ath10k_debug_cal_data_read,1375 .owner = THIS_MODULE,1376 .llseek = default_llseek,1377};1378 1379static ssize_t ath10k_read_nf_cal_period(struct file *file,1380 char __user *user_buf,1381 size_t count, loff_t *ppos)1382{1383 struct ath10k *ar = file->private_data;1384 size_t len;1385 char buf[32];1386 1387 len = scnprintf(buf, sizeof(buf), "%d\n", ar->debug.nf_cal_period);1388 1389 return simple_read_from_buffer(user_buf, count, ppos, buf, len);1390}1391 1392static ssize_t ath10k_write_nf_cal_period(struct file *file,1393 const char __user *user_buf,1394 size_t count, loff_t *ppos)1395{1396 struct ath10k *ar = file->private_data;1397 unsigned long period;1398 int ret;1399 1400 ret = kstrtoul_from_user(user_buf, count, 0, &period);1401 if (ret)1402 return ret;1403 1404 if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX)1405 return -EINVAL;1406 1407 /* there's no way to switch back to the firmware default */1408 if (period == 0)1409 return -EINVAL;1410 1411 mutex_lock(&ar->conf_mutex);1412 1413 ar->debug.nf_cal_period = period;1414 1415 if (ar->state != ATH10K_STATE_ON) {1416 /* firmware is not running, nothing else to do */1417 ret = count;1418 goto exit;1419 }1420 1421 ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period,1422 ar->debug.nf_cal_period);1423 if (ret) {1424 ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n",1425 ret);1426 goto exit;1427 }1428 1429 ret = count;1430 1431exit:1432 mutex_unlock(&ar->conf_mutex);1433 1434 return ret;1435}1436 1437static const struct file_operations fops_nf_cal_period = {1438 .read = ath10k_read_nf_cal_period,1439 .write = ath10k_write_nf_cal_period,1440 .open = simple_open,1441 .owner = THIS_MODULE,1442 .llseek = default_llseek,1443};1444 1445#define ATH10K_TPC_CONFIG_BUF_SIZE (1024 * 1024)1446 1447static int ath10k_debug_tpc_stats_request(struct ath10k *ar)1448{1449 int ret;1450 unsigned long time_left;1451 1452 lockdep_assert_held(&ar->conf_mutex);1453 1454 reinit_completion(&ar->debug.tpc_complete);1455 1456 ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM);1457 if (ret) {1458 ath10k_warn(ar, "failed to request tpc config: %d\n", ret);1459 return ret;1460 }1461 1462 time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,1463 1 * HZ);1464 if (time_left == 0)1465 return -ETIMEDOUT;1466 1467 return 0;1468}1469 1470void ath10k_debug_tpc_stats_process(struct ath10k *ar,1471 struct ath10k_tpc_stats *tpc_stats)1472{1473 spin_lock_bh(&ar->data_lock);1474 1475 kfree(ar->debug.tpc_stats);1476 ar->debug.tpc_stats = tpc_stats;1477 complete(&ar->debug.tpc_complete);1478 1479 spin_unlock_bh(&ar->data_lock);1480}1481 1482void1483ath10k_debug_tpc_stats_final_process(struct ath10k *ar,1484 struct ath10k_tpc_stats_final *tpc_stats)1485{1486 spin_lock_bh(&ar->data_lock);1487 1488 kfree(ar->debug.tpc_stats_final);1489 ar->debug.tpc_stats_final = tpc_stats;1490 complete(&ar->debug.tpc_complete);1491 1492 spin_unlock_bh(&ar->data_lock);1493}1494 1495static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,1496 unsigned int j, char *buf, size_t *len)1497{1498 int i;1499 size_t buf_len;1500 static const char table_str[][5] = { "CDD",1501 "STBC",1502 "TXBF" };1503 static const char pream_str[][6] = { "CCK",1504 "OFDM",1505 "HT20",1506 "HT40",1507 "VHT20",1508 "VHT40",1509 "VHT80",1510 "HTCUP" };1511 1512 buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;1513 *len += scnprintf(buf + *len, buf_len - *len,1514 "********************************\n");1515 *len += scnprintf(buf + *len, buf_len - *len,1516 "******************* %s POWER TABLE ****************\n",1517 table_str[j]);1518 *len += scnprintf(buf + *len, buf_len - *len,1519 "********************************\n");1520 *len += scnprintf(buf + *len, buf_len - *len,1521 "No. Preamble Rate_code ");1522 1523 for (i = 0; i < tpc_stats->num_tx_chain; i++)1524 *len += scnprintf(buf + *len, buf_len - *len,1525 "tpc_value%d ", i);1526 1527 *len += scnprintf(buf + *len, buf_len - *len, "\n");1528 1529 for (i = 0; i < tpc_stats->rate_max; i++) {1530 *len += scnprintf(buf + *len, buf_len - *len,1531 "%8d %s 0x%2x %s\n", i,1532 pream_str[tpc_stats->tpc_table[j].pream_idx[i]],1533 tpc_stats->tpc_table[j].rate_code[i],1534 tpc_stats->tpc_table[j].tpc_value[i]);1535 }1536 1537 *len += scnprintf(buf + *len, buf_len - *len,1538 "***********************************\n");1539}1540 1541static void ath10k_tpc_stats_fill(struct ath10k *ar,1542 struct ath10k_tpc_stats *tpc_stats,1543 char *buf)1544{1545 int j;1546 size_t len, buf_len;1547 1548 len = 0;1549 buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;1550 1551 spin_lock_bh(&ar->data_lock);1552 1553 if (!tpc_stats) {1554 ath10k_warn(ar, "failed to get tpc stats\n");1555 goto unlock;1556 }1557 1558 len += scnprintf(buf + len, buf_len - len, "\n");1559 len += scnprintf(buf + len, buf_len - len,1560 "*************************************\n");1561 len += scnprintf(buf + len, buf_len - len,1562 "TPC config for channel %4d mode %d\n",1563 tpc_stats->chan_freq,1564 tpc_stats->phy_mode);1565 len += scnprintf(buf + len, buf_len - len,1566 "*************************************\n");1567 len += scnprintf(buf + len, buf_len - len,1568 "CTL = 0x%2x Reg. Domain = %2d\n",1569 tpc_stats->ctl,1570 tpc_stats->reg_domain);1571 len += scnprintf(buf + len, buf_len - len,1572 "Antenna Gain = %2d Reg. Max Antenna Gain = %2d\n",1573 tpc_stats->twice_antenna_gain,1574 tpc_stats->twice_antenna_reduction);1575 len += scnprintf(buf + len, buf_len - len,1576 "Power Limit = %2d Reg. Max Power = %2d\n",1577 tpc_stats->power_limit,1578 tpc_stats->twice_max_rd_power / 2);1579 len += scnprintf(buf + len, buf_len - len,1580 "Num tx chains = %2d Num supported rates = %2d\n",1581 tpc_stats->num_tx_chain,1582 tpc_stats->rate_max);1583 1584 for (j = 0; j < WMI_TPC_FLAG; j++) {1585 switch (j) {1586 case WMI_TPC_TABLE_TYPE_CDD:1587 if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {1588 len += scnprintf(buf + len, buf_len - len,1589 "CDD not supported\n");1590 break;1591 }1592 1593 ath10k_tpc_stats_print(tpc_stats, j, buf, &len);1594 break;1595 case WMI_TPC_TABLE_TYPE_STBC:1596 if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {1597 len += scnprintf(buf + len, buf_len - len,1598 "STBC not supported\n");1599 break;1600 }1601 1602 ath10k_tpc_stats_print(tpc_stats, j, buf, &len);1603 break;1604 case WMI_TPC_TABLE_TYPE_TXBF:1605 if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {1606 len += scnprintf(buf + len, buf_len - len,1607 "TXBF not supported\n***************************\n");1608 break;1609 }1610 1611 ath10k_tpc_stats_print(tpc_stats, j, buf, &len);1612 break;1613 default:1614 len += scnprintf(buf + len, buf_len - len,1615 "Invalid Type\n");1616 break;1617 }1618 }1619 1620unlock:1621 spin_unlock_bh(&ar->data_lock);1622 1623 if (len >= buf_len)1624 buf[len - 1] = 0;1625 else1626 buf[len] = 0;1627}1628 1629static int ath10k_tpc_stats_open(struct inode *inode, struct file *file)1630{1631 struct ath10k *ar = inode->i_private;1632 void *buf = NULL;1633 int ret;1634 1635 mutex_lock(&ar->conf_mutex);1636 1637 if (ar->state != ATH10K_STATE_ON) {1638 ret = -ENETDOWN;1639 goto err_unlock;1640 }1641 1642 buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);1643 if (!buf) {1644 ret = -ENOMEM;1645 goto err_unlock;1646 }1647 1648 ret = ath10k_debug_tpc_stats_request(ar);1649 if (ret) {1650 ath10k_warn(ar, "failed to request tpc config stats: %d\n",1651 ret);1652 goto err_free;1653 }1654 1655 ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);1656 file->private_data = buf;1657 1658 mutex_unlock(&ar->conf_mutex);1659 return 0;1660 1661err_free:1662 vfree(buf);1663 1664err_unlock:1665 mutex_unlock(&ar->conf_mutex);1666 return ret;1667}1668 1669static int ath10k_tpc_stats_release(struct inode *inode, struct file *file)1670{1671 vfree(file->private_data);1672 1673 return 0;1674}1675 1676static ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf,1677 size_t count, loff_t *ppos)1678{1679 const char *buf = file->private_data;1680 size_t len = strlen(buf);1681 1682 return simple_read_from_buffer(user_buf, count, ppos, buf, len);1683}1684 1685static const struct file_operations fops_tpc_stats = {1686 .open = ath10k_tpc_stats_open,1687 .release = ath10k_tpc_stats_release,1688 .read = ath10k_tpc_stats_read,1689 .owner = THIS_MODULE,1690 .llseek = default_llseek,1691};1692 1693int ath10k_debug_start(struct ath10k *ar)1694{1695 int ret;1696 1697 lockdep_assert_held(&ar->conf_mutex);1698 1699 ret = ath10k_debug_htt_stats_req(ar);1700 if (ret)1701 /* continue normally anyway, this isn't serious */1702 ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",1703 ret);1704 1705 if (ar->debug.fw_dbglog_mask) {1706 ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,1707 ATH10K_DBGLOG_LEVEL_WARN);1708 if (ret)1709 /* not serious */1710 ath10k_warn(ar, "failed to enable dbglog during start: %d",1711 ret);1712 }1713 1714 if (ar->pktlog_filter) {1715 ret = ath10k_wmi_pdev_pktlog_enable(ar,1716 ar->pktlog_filter);1717 if (ret)1718 /* not serious */1719 ath10k_warn(ar,1720 "failed to enable pktlog filter %x: %d\n",1721 ar->pktlog_filter, ret);1722 } else {1723 ret = ath10k_wmi_pdev_pktlog_disable(ar);1724 if (ret)1725 /* not serious */1726 ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);1727 }1728 1729 if (ar->debug.nf_cal_period &&1730 !test_bit(ATH10K_FW_FEATURE_NON_BMI,1731 ar->normal_mode_fw.fw_file.fw_features)) {1732 ret = ath10k_wmi_pdev_set_param(ar,1733 ar->wmi.pdev_param->cal_period,1734 ar->debug.nf_cal_period);1735 if (ret)1736 /* not serious */1737 ath10k_warn(ar, "cal period cfg failed from debug start: %d\n",1738 ret);1739 }1740 1741 return ret;1742}1743 1744void ath10k_debug_stop(struct ath10k *ar)1745{1746 lockdep_assert_held(&ar->conf_mutex);1747 1748 if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,1749 ar->normal_mode_fw.fw_file.fw_features))1750 ath10k_debug_cal_data_fetch(ar);1751 1752 /* Must not use _sync to avoid deadlock, we do that in1753 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid1754 * warning from del_timer().1755 */1756 if (ar->debug.htt_stats_mask != 0)1757 cancel_delayed_work(&ar->debug.htt_stats_dwork);1758 1759 ath10k_wmi_pdev_pktlog_disable(ar);1760}1761 1762static ssize_t ath10k_write_simulate_radar(struct file *file,1763 const char __user *user_buf,1764 size_t count, loff_t *ppos)1765{1766 struct ath10k *ar = file->private_data;1767 struct ath10k_vif *arvif;1768 1769 /* Just check for the first vif alone, as all the vifs will be1770 * sharing the same channel and if the channel is disabled, all the1771 * vifs will share the same 'is_started' state.1772 */1773 arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);1774 if (!arvif->is_started)1775 return -EINVAL;1776 1777 ieee80211_radar_detected(ar->hw, NULL);1778 1779 return count;1780}1781 1782static const struct file_operations fops_simulate_radar = {1783 .write = ath10k_write_simulate_radar,1784 .open = simple_open,1785 .owner = THIS_MODULE,1786 .llseek = default_llseek,1787};1788 1789#define ATH10K_DFS_STAT(s, p) (\1790 len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \1791 ar->debug.dfs_stats.p))1792 1793#define ATH10K_DFS_POOL_STAT(s, p) (\1794 len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \1795 ar->debug.dfs_pool_stats.p))1796 1797static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,1798 size_t count, loff_t *ppos)1799{1800 int retval = 0, len = 0;1801 const int size = 8000;1802 struct ath10k *ar = file->private_data;1803 char *buf;1804 1805 buf = kzalloc(size, GFP_KERNEL);1806 if (buf == NULL)1807 return -ENOMEM;1808 1809 if (!ar->dfs_detector) {1810 len += scnprintf(buf + len, size - len, "DFS not enabled\n");1811 goto exit;1812 }1813 1814 ar->debug.dfs_pool_stats =1815 ar->dfs_detector->get_stats(ar->dfs_detector);1816 1817 len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");1818 1819 ATH10K_DFS_STAT("reported phy errors", phy_errors);1820 ATH10K_DFS_STAT("pulse events reported", pulses_total);1821 ATH10K_DFS_STAT("DFS pulses detected", pulses_detected);1822 ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded);1823 ATH10K_DFS_STAT("Radars detected", radar_detected);1824 1825 len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");1826 ATH10K_DFS_POOL_STAT("Pool references", pool_reference);1827 ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated);1828 ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error);1829 ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used);1830 ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated);1831 ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);1832 ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);1833 1834exit:1835 if (len > size)1836 len = size;1837 1838 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);1839 kfree(buf);1840 1841 return retval;1842}1843 1844static const struct file_operations fops_dfs_stats = {1845 .read = ath10k_read_dfs_stats,1846 .open = simple_open,1847 .owner = THIS_MODULE,1848 .llseek = default_llseek,1849};1850 1851static ssize_t ath10k_write_pktlog_filter(struct file *file,1852 const char __user *ubuf,1853 size_t count, loff_t *ppos)1854{1855 struct ath10k *ar = file->private_data;1856 u32 filter;1857 int ret;1858 1859 if (kstrtouint_from_user(ubuf, count, 0, &filter))1860 return -EINVAL;1861 1862 mutex_lock(&ar->conf_mutex);1863 1864 if (ar->state != ATH10K_STATE_ON) {1865 ar->pktlog_filter = filter;1866 ret = count;1867 goto out;1868 }1869 1870 if (filter == ar->pktlog_filter) {1871 ret = count;1872 goto out;1873 }1874 1875 if (filter) {1876 ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);1877 if (ret) {1878 ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",1879 ar->pktlog_filter, ret);1880 goto out;1881 }1882 } else {1883 ret = ath10k_wmi_pdev_pktlog_disable(ar);1884 if (ret) {1885 ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);1886 goto out;1887 }1888 }1889 1890 ar->pktlog_filter = filter;1891 ret = count;1892 1893out:1894 mutex_unlock(&ar->conf_mutex);1895 return ret;1896}1897 1898static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,1899 size_t count, loff_t *ppos)1900{1901 char buf[32];1902 struct ath10k *ar = file->private_data;1903 int len = 0;1904 1905 mutex_lock(&ar->conf_mutex);1906 len = scnprintf(buf, sizeof(buf) - len, "%08x\n",1907 ar->pktlog_filter);1908 mutex_unlock(&ar->conf_mutex);1909 1910 return simple_read_from_buffer(ubuf, count, ppos, buf, len);1911}1912 1913static const struct file_operations fops_pktlog_filter = {1914 .read = ath10k_read_pktlog_filter,1915 .write = ath10k_write_pktlog_filter,1916 .open = simple_open1917};1918 1919static ssize_t ath10k_write_quiet_period(struct file *file,1920 const char __user *ubuf,1921 size_t count, loff_t *ppos)1922{1923 struct ath10k *ar = file->private_data;1924 u32 period;1925 1926 if (kstrtouint_from_user(ubuf, count, 0, &period))1927 return -EINVAL;1928 1929 if (period < ATH10K_QUIET_PERIOD_MIN) {1930 ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n",1931 period);1932 return -EINVAL;1933 }1934 mutex_lock(&ar->conf_mutex);1935 ar->thermal.quiet_period = period;1936 ath10k_thermal_set_throttling(ar);1937 mutex_unlock(&ar->conf_mutex);1938 1939 return count;1940}1941 1942static ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf,1943 size_t count, loff_t *ppos)1944{1945 char buf[32];1946 struct ath10k *ar = file->private_data;1947 int len = 0;1948 1949 mutex_lock(&ar->conf_mutex);1950 len = scnprintf(buf, sizeof(buf) - len, "%d\n",1951 ar->thermal.quiet_period);1952 mutex_unlock(&ar->conf_mutex);1953 1954 return simple_read_from_buffer(ubuf, count, ppos, buf, len);1955}1956 1957static const struct file_operations fops_quiet_period = {1958 .read = ath10k_read_quiet_period,1959 .write = ath10k_write_quiet_period,1960 .open = simple_open1961};1962 1963static ssize_t ath10k_write_btcoex(struct file *file,1964 const char __user *ubuf,1965 size_t count, loff_t *ppos)1966{1967 struct ath10k *ar = file->private_data;1968 ssize_t ret;1969 bool val;1970 u32 pdev_param;1971 1972 ret = kstrtobool_from_user(ubuf, count, &val);1973 if (ret)1974 return ret;1975 1976 if (!ar->coex_support)1977 return -EOPNOTSUPP;1978 1979 mutex_lock(&ar->conf_mutex);1980 1981 if (ar->state != ATH10K_STATE_ON &&1982 ar->state != ATH10K_STATE_RESTARTED) {1983 ret = -ENETDOWN;1984 goto exit;1985 }1986 1987 if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) {1988 ret = count;1989 goto exit;1990 }1991 1992 pdev_param = ar->wmi.pdev_param->enable_btcoex;1993 if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,1994 ar->running_fw->fw_file.fw_features)) {1995 ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val);1996 if (ret) {1997 ath10k_warn(ar, "failed to enable btcoex: %zd\n", ret);1998 ret = count;1999 goto exit;2000 }2001 } else {2002 ath10k_info(ar, "restarting firmware due to btcoex change");2003 ath10k_core_start_recovery(ar);2004 }2005 2006 if (val)2007 set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);2008 else2009 clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);2010 2011 ret = count;2012 2013exit:2014 mutex_unlock(&ar->conf_mutex);2015 2016 return ret;2017}2018 2019static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,2020 size_t count, loff_t *ppos)2021{2022 char buf[32];2023 struct ath10k *ar = file->private_data;2024 int len = 0;2025 2026 mutex_lock(&ar->conf_mutex);2027 len = scnprintf(buf, sizeof(buf) - len, "%d\n",2028 test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags));2029 mutex_unlock(&ar->conf_mutex);2030 2031 return simple_read_from_buffer(ubuf, count, ppos, buf, len);2032}2033 2034static const struct file_operations fops_btcoex = {2035 .read = ath10k_read_btcoex,2036 .write = ath10k_write_btcoex,2037 .open = simple_open2038};2039 2040static ssize_t ath10k_write_enable_extd_tx_stats(struct file *file,2041 const char __user *ubuf,2042 size_t count, loff_t *ppos)2043{2044 struct ath10k *ar = file->private_data;2045 u32 filter;2046 int ret;2047 2048 if (kstrtouint_from_user(ubuf, count, 0, &filter))2049 return -EINVAL;2050 2051 mutex_lock(&ar->conf_mutex);2052 2053 if (ar->state != ATH10K_STATE_ON) {2054 ar->debug.enable_extd_tx_stats = filter;2055 ret = count;2056 goto out;2057 }2058 2059 if (filter == ar->debug.enable_extd_tx_stats) {2060 ret = count;2061 goto out;2062 }2063 2064 ar->debug.enable_extd_tx_stats = filter;2065 ret = count;2066 2067out:2068 mutex_unlock(&ar->conf_mutex);2069 return ret;2070}2071 2072static ssize_t ath10k_read_enable_extd_tx_stats(struct file *file,2073 char __user *ubuf,2074 size_t count, loff_t *ppos)2075 2076{2077 char buf[32];2078 struct ath10k *ar = file->private_data;2079 int len = 0;2080 2081 mutex_lock(&ar->conf_mutex);2082 len = scnprintf(buf, sizeof(buf) - len, "%08x\n",2083 ar->debug.enable_extd_tx_stats);2084 mutex_unlock(&ar->conf_mutex);2085 2086 return simple_read_from_buffer(ubuf, count, ppos, buf, len);2087}2088 2089static const struct file_operations fops_enable_extd_tx_stats = {2090 .read = ath10k_read_enable_extd_tx_stats,2091 .write = ath10k_write_enable_extd_tx_stats,2092 .open = simple_open2093};2094 2095static ssize_t ath10k_write_peer_stats(struct file *file,2096 const char __user *ubuf,2097 size_t count, loff_t *ppos)2098{2099 struct ath10k *ar = file->private_data;2100 ssize_t ret;2101 bool val;2102 2103 ret = kstrtobool_from_user(ubuf, count, &val);2104 if (ret)2105 return ret;2106 2107 mutex_lock(&ar->conf_mutex);2108 2109 if (ar->state != ATH10K_STATE_ON &&2110 ar->state != ATH10K_STATE_RESTARTED) {2111 ret = -ENETDOWN;2112 goto exit;2113 }2114 2115 if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) {2116 ret = count;2117 goto exit;2118 }2119 2120 if (val)2121 set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);2122 else2123 clear_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);2124 2125 ath10k_info(ar, "restarting firmware due to Peer stats change");2126 2127 ath10k_core_start_recovery(ar);2128 ret = count;2129 2130exit:2131 mutex_unlock(&ar->conf_mutex);2132 return ret;2133}2134 2135static ssize_t ath10k_read_peer_stats(struct file *file, char __user *ubuf,2136 size_t count, loff_t *ppos)2137 2138{2139 char buf[32];2140 struct ath10k *ar = file->private_data;2141 int len = 0;2142 2143 mutex_lock(&ar->conf_mutex);2144 len = scnprintf(buf, sizeof(buf) - len, "%d\n",2145 test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags));2146 mutex_unlock(&ar->conf_mutex);2147 2148 return simple_read_from_buffer(ubuf, count, ppos, buf, len);2149}2150 2151static const struct file_operations fops_peer_stats = {2152 .read = ath10k_read_peer_stats,2153 .write = ath10k_write_peer_stats,2154 .open = simple_open2155};2156 2157static ssize_t ath10k_debug_fw_checksums_read(struct file *file,2158 char __user *user_buf,2159 size_t count, loff_t *ppos)2160{2161 struct ath10k *ar = file->private_data;2162 size_t len = 0, buf_len = 4096;2163 ssize_t ret_cnt;2164 char *buf;2165 2166 buf = kzalloc(buf_len, GFP_KERNEL);2167 if (!buf)2168 return -ENOMEM;2169 2170 mutex_lock(&ar->conf_mutex);2171 2172 len += scnprintf(buf + len, buf_len - len,2173 "firmware-N.bin\t\t%08x\n",2174 crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data,2175 ar->normal_mode_fw.fw_file.firmware->size));2176 len += scnprintf(buf + len, buf_len - len,2177 "athwlan\t\t\t%08x\n",2178 crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data,2179 ar->normal_mode_fw.fw_file.firmware_len));2180 len += scnprintf(buf + len, buf_len - len,2181 "otp\t\t\t%08x\n",2182 crc32_le(0, ar->normal_mode_fw.fw_file.otp_data,2183 ar->normal_mode_fw.fw_file.otp_len));2184 len += scnprintf(buf + len, buf_len - len,2185 "codeswap\t\t%08x\n",2186 crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data,2187 ar->normal_mode_fw.fw_file.codeswap_len));2188 len += scnprintf(buf + len, buf_len - len,2189 "board-N.bin\t\t%08x\n",2190 crc32_le(0, ar->normal_mode_fw.board->data,2191 ar->normal_mode_fw.board->size));2192 len += scnprintf(buf + len, buf_len - len,2193 "board\t\t\t%08x\n",2194 crc32_le(0, ar->normal_mode_fw.board_data,2195 ar->normal_mode_fw.board_len));2196 2197 ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);2198 2199 mutex_unlock(&ar->conf_mutex);2200 2201 kfree(buf);2202 return ret_cnt;2203}2204 2205static const struct file_operations fops_fw_checksums = {2206 .read = ath10k_debug_fw_checksums_read,2207 .open = simple_open,2208 .owner = THIS_MODULE,2209 .llseek = default_llseek,2210};2211 2212static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file,2213 char __user *user_buf,2214 size_t count, loff_t *ppos)2215{2216 struct ath10k *ar = file->private_data;2217 char buf[32];2218 size_t len;2219 2220 len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask);2221 return simple_read_from_buffer(user_buf, count, ppos, buf, len);2222}2223 2224static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file,2225 const char __user *user_buf,2226 size_t count, loff_t *ppos)2227{2228 struct ath10k *ar = file->private_data;2229 ssize_t ret;2230 u32 mask;2231 2232 ret = kstrtoint_from_user(user_buf, count, 0, &mask);2233 if (ret)2234 return ret;2235 2236 ar->sta_tid_stats_mask = mask;2237 2238 return count;2239}2240 2241static const struct file_operations fops_sta_tid_stats_mask = {2242 .read = ath10k_sta_tid_stats_mask_read,2243 .write = ath10k_sta_tid_stats_mask_write,2244 .open = simple_open,2245 .owner = THIS_MODULE,2246 .llseek = default_llseek,2247};2248 2249static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)2250{2251 int ret;2252 unsigned long time_left;2253 2254 lockdep_assert_held(&ar->conf_mutex);2255 2256 reinit_completion(&ar->debug.tpc_complete);2257 2258 ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);2259 if (ret) {2260 ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);2261 return ret;2262 }2263 2264 time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,2265 1 * HZ);2266 if (time_left == 0)2267 return -ETIMEDOUT;2268 2269 return 0;2270}2271 2272static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)2273{2274 struct ath10k *ar = inode->i_private;2275 void *buf;2276 int ret;2277 2278 mutex_lock(&ar->conf_mutex);2279 2280 if (ar->state != ATH10K_STATE_ON) {2281 ret = -ENETDOWN;2282 goto err_unlock;2283 }2284 2285 buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);2286 if (!buf) {2287 ret = -ENOMEM;2288 goto err_unlock;2289 }2290 2291 ret = ath10k_debug_tpc_stats_final_request(ar);2292 if (ret) {2293 ath10k_warn(ar, "failed to request tpc stats final: %d\n",2294 ret);2295 goto err_free;2296 }2297 2298 ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);2299 file->private_data = buf;2300 2301 mutex_unlock(&ar->conf_mutex);2302 return 0;2303 2304err_free:2305 vfree(buf);2306 2307err_unlock:2308 mutex_unlock(&ar->conf_mutex);2309 return ret;2310}2311 2312static int ath10k_tpc_stats_final_release(struct inode *inode,2313 struct file *file)2314{2315 vfree(file->private_data);2316 2317 return 0;2318}2319 2320static ssize_t ath10k_tpc_stats_final_read(struct file *file,2321 char __user *user_buf,2322 size_t count, loff_t *ppos)2323{2324 const char *buf = file->private_data;2325 unsigned int len = strlen(buf);2326 2327 return simple_read_from_buffer(user_buf, count, ppos, buf, len);2328}2329 2330static const struct file_operations fops_tpc_stats_final = {2331 .open = ath10k_tpc_stats_final_open,2332 .release = ath10k_tpc_stats_final_release,2333 .read = ath10k_tpc_stats_final_read,2334 .owner = THIS_MODULE,2335 .llseek = default_llseek,2336};2337 2338static ssize_t ath10k_write_warm_hw_reset(struct file *file,2339 const char __user *user_buf,2340 size_t count, loff_t *ppos)2341{2342 struct ath10k *ar = file->private_data;2343 int ret;2344 bool val;2345 2346 if (kstrtobool_from_user(user_buf, count, &val))2347 return -EFAULT;2348 2349 if (!val)2350 return -EINVAL;2351 2352 mutex_lock(&ar->conf_mutex);2353 2354 if (ar->state != ATH10K_STATE_ON) {2355 ret = -ENETDOWN;2356 goto exit;2357 }2358 2359 ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pdev_reset,2360 WMI_RST_MODE_WARM_RESET);2361 2362 if (ret) {2363 ath10k_warn(ar, "failed to enable warm hw reset: %d\n", ret);2364 goto exit;2365 }2366 2367 ret = count;2368 2369exit:2370 mutex_unlock(&ar->conf_mutex);2371 return ret;2372}2373 2374static const struct file_operations fops_warm_hw_reset = {2375 .write = ath10k_write_warm_hw_reset,2376 .open = simple_open,2377 .owner = THIS_MODULE,2378 .llseek = default_llseek,2379};2380 2381static void ath10k_peer_ps_state_disable(void *data,2382 struct ieee80211_sta *sta)2383{2384 struct ath10k *ar = data;2385 struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;2386 2387 spin_lock_bh(&ar->data_lock);2388 arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;2389 spin_unlock_bh(&ar->data_lock);2390}2391 2392static ssize_t ath10k_write_ps_state_enable(struct file *file,2393 const char __user *user_buf,2394 size_t count, loff_t *ppos)2395{2396 struct ath10k *ar = file->private_data;2397 int ret;2398 u32 param;2399 u8 ps_state_enable;2400 2401 if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))2402 return -EINVAL;2403 2404 if (ps_state_enable > 1)2405 return -EINVAL;2406 2407 mutex_lock(&ar->conf_mutex);2408 2409 if (ar->ps_state_enable == ps_state_enable) {2410 ret = count;2411 goto exit;2412 }2413 2414 param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable;2415 ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable);2416 if (ret) {2417 ath10k_warn(ar, "failed to enable ps_state_enable: %d\n",2418 ret);2419 goto exit;2420 }2421 ar->ps_state_enable = ps_state_enable;2422 2423 if (!ar->ps_state_enable)2424 ieee80211_iterate_stations_atomic(ar->hw,2425 ath10k_peer_ps_state_disable,2426 ar);2427 2428 ret = count;2429 2430exit:2431 mutex_unlock(&ar->conf_mutex);2432 2433 return ret;2434}2435 2436static ssize_t ath10k_read_ps_state_enable(struct file *file,2437 char __user *user_buf,2438 size_t count, loff_t *ppos)2439{2440 struct ath10k *ar = file->private_data;2441 int len = 0;2442 char buf[32];2443 2444 mutex_lock(&ar->conf_mutex);2445 len = scnprintf(buf, sizeof(buf) - len, "%d\n",2446 ar->ps_state_enable);2447 mutex_unlock(&ar->conf_mutex);2448 2449 return simple_read_from_buffer(user_buf, count, ppos, buf, len);2450}2451 2452static const struct file_operations fops_ps_state_enable = {2453 .read = ath10k_read_ps_state_enable,2454 .write = ath10k_write_ps_state_enable,2455 .open = simple_open,2456 .owner = THIS_MODULE,2457 .llseek = default_llseek,2458};2459 2460static ssize_t ath10k_write_reset_htt_stats(struct file *file,2461 const char __user *user_buf,2462 size_t count, loff_t *ppos)2463{2464 struct ath10k *ar = file->private_data;2465 unsigned long reset;2466 int ret;2467 2468 ret = kstrtoul_from_user(user_buf, count, 0, &reset);2469 if (ret)2470 return ret;2471 2472 if (reset == 0 || reset > 0x1ffff)2473 return -EINVAL;2474 2475 mutex_lock(&ar->conf_mutex);2476 2477 ar->debug.reset_htt_stats = reset;2478 2479 ret = ath10k_debug_htt_stats_req(ar);2480 if (ret)2481 goto out;2482 2483 ar->debug.reset_htt_stats = 0;2484 ret = count;2485 2486out:2487 mutex_unlock(&ar->conf_mutex);2488 return ret;2489}2490 2491static const struct file_operations fops_reset_htt_stats = {2492 .write = ath10k_write_reset_htt_stats,2493 .owner = THIS_MODULE,2494 .open = simple_open,2495 .llseek = default_llseek,2496};2497 2498int ath10k_debug_create(struct ath10k *ar)2499{2500 ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);2501 if (!ar->debug.cal_data)2502 return -ENOMEM;2503 2504 INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);2505 INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);2506 INIT_LIST_HEAD(&ar->debug.fw_stats.peers);2507 INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);2508 2509 return 0;2510}2511 2512void ath10k_debug_destroy(struct ath10k *ar)2513{2514 vfree(ar->debug.cal_data);2515 ar->debug.cal_data = NULL;2516 2517 ath10k_debug_fw_stats_reset(ar);2518 2519 kfree(ar->debug.tpc_stats);2520 kfree(ar->debug.tpc_stats_final);2521}2522 2523int ath10k_debug_register(struct ath10k *ar)2524{2525 ar->debug.debugfs_phy = debugfs_create_dir("ath10k",2526 ar->hw->wiphy->debugfsdir);2527 if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) {2528 if (IS_ERR(ar->debug.debugfs_phy))2529 return PTR_ERR(ar->debug.debugfs_phy);2530 2531 return -ENOMEM;2532 }2533 2534 INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,2535 ath10k_debug_htt_stats_dwork);2536 2537 init_completion(&ar->debug.tpc_complete);2538 init_completion(&ar->debug.fw_stats_complete);2539 2540 debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar,2541 &fops_fw_stats);2542 2543 debugfs_create_file("fw_reset_stats", 0400, ar->debug.debugfs_phy, ar,2544 &fops_fw_reset_stats);2545 2546 debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar,2547 &fops_wmi_services);2548 2549 debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar,2550 &fops_simulate_fw_crash);2551 2552 debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar,2553 &fops_reg_addr);2554 2555 debugfs_create_file("reg_value", 0600, ar->debug.debugfs_phy, ar,2556 &fops_reg_value);2557 2558 debugfs_create_file("mem_value", 0600, ar->debug.debugfs_phy, ar,2559 &fops_mem_value);2560 2561 debugfs_create_file("chip_id", 0400, ar->debug.debugfs_phy, ar,2562 &fops_chip_id);2563 2564 debugfs_create_file("htt_stats_mask", 0600, ar->debug.debugfs_phy, ar,2565 &fops_htt_stats_mask);2566 2567 debugfs_create_file("htt_max_amsdu_ampdu", 0600, ar->debug.debugfs_phy, ar,2568 &fops_htt_max_amsdu_ampdu);2569 2570 debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar,2571 &fops_fw_dbglog);2572 2573 if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,2574 ar->normal_mode_fw.fw_file.fw_features)) {2575 debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar,2576 &fops_cal_data);2577 2578 debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar,2579 &fops_nf_cal_period);2580 }2581 2582 debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar,2583 &fops_ani_enable);2584 2585 if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) {2586 debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy,2587 ar, &fops_simulate_radar);2588 2589 debugfs_create_bool("dfs_block_radar_events", 0200,2590 ar->debug.debugfs_phy,2591 &ar->dfs_block_radar_events);2592 2593 debugfs_create_file("dfs_stats", 0400, ar->debug.debugfs_phy, ar,2594 &fops_dfs_stats);2595 }2596 2597 debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar,2598 &fops_pktlog_filter);2599 2600 if (test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))2601 debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar,2602 &fops_quiet_period);2603 2604 debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar,2605 &fops_tpc_stats);2606 2607 if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))2608 debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar,2609 &fops_btcoex);2610 2611 if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {2612 debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar,2613 &fops_peer_stats);2614 2615 debugfs_create_file("enable_extd_tx_stats", 0644,2616 ar->debug.debugfs_phy, ar,2617 &fops_enable_extd_tx_stats);2618 }2619 2620 debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,2621 &fops_fw_checksums);2622 2623 if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS))2624 debugfs_create_file("sta_tid_stats_mask", 0600,2625 ar->debug.debugfs_phy,2626 ar, &fops_sta_tid_stats_mask);2627 2628 if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))2629 debugfs_create_file("tpc_stats_final", 0400,2630 ar->debug.debugfs_phy, ar,2631 &fops_tpc_stats_final);2632 2633 if (test_bit(WMI_SERVICE_RESET_CHIP, ar->wmi.svc_map))2634 debugfs_create_file("warm_hw_reset", 0600,2635 ar->debug.debugfs_phy, ar,2636 &fops_warm_hw_reset);2637 2638 debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,2639 &fops_ps_state_enable);2640 2641 debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar,2642 &fops_reset_htt_stats);2643 2644 return 0;2645}2646 2647void ath10k_debug_unregister(struct ath10k *ar)2648{2649 cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);2650}2651 2652#endif /* CONFIG_ATH10K_DEBUGFS */2653 2654#ifdef CONFIG_ATH10K_DEBUG2655void __ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,2656 const char *fmt, ...)2657{2658 struct va_format vaf;2659 va_list args;2660 2661 va_start(args, fmt);2662 2663 vaf.fmt = fmt;2664 vaf.va = &args;2665 2666 if (ath10k_debug_mask & mask)2667 dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);2668 2669 trace_ath10k_log_dbg(ar, mask, &vaf);2670 2671 va_end(args);2672}2673EXPORT_SYMBOL(__ath10k_dbg);2674 2675void ath10k_dbg_dump(struct ath10k *ar,2676 enum ath10k_debug_mask mask,2677 const char *msg, const char *prefix,2678 const void *buf, size_t len)2679{2680 char linebuf[256];2681 size_t linebuflen;2682 const void *ptr;2683 2684 if (ath10k_debug_mask & mask) {2685 if (msg)2686 __ath10k_dbg(ar, mask, "%s\n", msg);2687 2688 for (ptr = buf; (ptr - buf) < len; ptr += 16) {2689 linebuflen = 0;2690 linebuflen += scnprintf(linebuf + linebuflen,2691 sizeof(linebuf) - linebuflen,2692 "%s%08x: ",2693 (prefix ? prefix : ""),2694 (unsigned int)(ptr - buf));2695 hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,2696 linebuf + linebuflen,2697 sizeof(linebuf) - linebuflen, true);2698 dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);2699 }2700 }2701 2702 /* tracing code doesn't like null strings :/ */2703 trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "",2704 buf, len);2705}2706EXPORT_SYMBOL(ath10k_dbg_dump);2707 2708#endif /* CONFIG_ATH10K_DEBUG */2709