162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2005-2011 Atheros Communications Inc. 462306a36Sopenharmony_ci * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. 562306a36Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/debugfs.h> 1062306a36Sopenharmony_ci#include <linux/vmalloc.h> 1162306a36Sopenharmony_ci#include <linux/crc32.h> 1262306a36Sopenharmony_ci#include <linux/firmware.h> 1362306a36Sopenharmony_ci#include <linux/kstrtox.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "core.h" 1662306a36Sopenharmony_ci#include "debug.h" 1762306a36Sopenharmony_ci#include "hif.h" 1862306a36Sopenharmony_ci#include "wmi-ops.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* ms */ 2162306a36Sopenharmony_ci#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define ATH10K_DEBUG_CAL_DATA_LEN 12064 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_civoid ath10k_info(struct ath10k *ar, const char *fmt, ...) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct va_format vaf = { 2862306a36Sopenharmony_ci .fmt = fmt, 2962306a36Sopenharmony_ci }; 3062306a36Sopenharmony_ci va_list args; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci va_start(args, fmt); 3362306a36Sopenharmony_ci vaf.va = &args; 3462306a36Sopenharmony_ci dev_info(ar->dev, "%pV", &vaf); 3562306a36Sopenharmony_ci trace_ath10k_log_info(ar, &vaf); 3662306a36Sopenharmony_ci va_end(args); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ciEXPORT_SYMBOL(ath10k_info); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid ath10k_debug_print_hwfw_info(struct ath10k *ar) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci const struct firmware *firmware; 4362306a36Sopenharmony_ci char fw_features[128] = {}; 4462306a36Sopenharmony_ci u32 crc = 0; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x", 4962306a36Sopenharmony_ci ar->hw_params.name, 5062306a36Sopenharmony_ci ar->target_version, 5162306a36Sopenharmony_ci ar->bus_param.chip_id, 5262306a36Sopenharmony_ci ar->id.subsystem_vendor, ar->id.subsystem_device); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n", 5562306a36Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_DEBUG), 5662306a36Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_DEBUGFS), 5762306a36Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_TRACING), 5862306a36Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED), 5962306a36Sopenharmony_ci IS_ENABLED(CONFIG_NL80211_TESTMODE)); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci firmware = ar->normal_mode_fw.fw_file.firmware; 6262306a36Sopenharmony_ci if (firmware) 6362306a36Sopenharmony_ci crc = crc32_le(0, firmware->data, firmware->size); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n", 6662306a36Sopenharmony_ci ar->hw->wiphy->fw_version, 6762306a36Sopenharmony_ci ar->fw_api, 6862306a36Sopenharmony_ci fw_features, 6962306a36Sopenharmony_ci crc); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_civoid ath10k_debug_print_board_info(struct ath10k *ar) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci char boardinfo[100]; 7562306a36Sopenharmony_ci const struct firmware *board; 7662306a36Sopenharmony_ci u32 crc; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (ar->id.bmi_ids_valid) 7962306a36Sopenharmony_ci scnprintf(boardinfo, sizeof(boardinfo), "%d:%d", 8062306a36Sopenharmony_ci ar->id.bmi_chip_id, ar->id.bmi_board_id); 8162306a36Sopenharmony_ci else 8262306a36Sopenharmony_ci scnprintf(boardinfo, sizeof(boardinfo), "N/A"); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci board = ar->normal_mode_fw.board; 8562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(board)) 8662306a36Sopenharmony_ci crc = crc32_le(0, board->data, board->size); 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci crc = 0; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x", 9162306a36Sopenharmony_ci ar->bd_api, 9262306a36Sopenharmony_ci boardinfo, 9362306a36Sopenharmony_ci crc); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid ath10k_debug_print_boot_info(struct ath10k *ar) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n", 9962306a36Sopenharmony_ci ar->htt.target_version_major, 10062306a36Sopenharmony_ci ar->htt.target_version_minor, 10162306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.wmi_op_version, 10262306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.htt_op_version, 10362306a36Sopenharmony_ci ath10k_cal_mode_str(ar->cal_mode), 10462306a36Sopenharmony_ci ar->max_num_stations, 10562306a36Sopenharmony_ci test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), 10662306a36Sopenharmony_ci !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags)); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_civoid ath10k_print_driver_info(struct ath10k *ar) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci ath10k_debug_print_hwfw_info(ar); 11262306a36Sopenharmony_ci ath10k_debug_print_board_info(ar); 11362306a36Sopenharmony_ci ath10k_debug_print_boot_info(ar); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ciEXPORT_SYMBOL(ath10k_print_driver_info); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid ath10k_err(struct ath10k *ar, const char *fmt, ...) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct va_format vaf = { 12062306a36Sopenharmony_ci .fmt = fmt, 12162306a36Sopenharmony_ci }; 12262306a36Sopenharmony_ci va_list args; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci va_start(args, fmt); 12562306a36Sopenharmony_ci vaf.va = &args; 12662306a36Sopenharmony_ci dev_err(ar->dev, "%pV", &vaf); 12762306a36Sopenharmony_ci trace_ath10k_log_err(ar, &vaf); 12862306a36Sopenharmony_ci va_end(args); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ciEXPORT_SYMBOL(ath10k_err); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_civoid ath10k_warn(struct ath10k *ar, const char *fmt, ...) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct va_format vaf = { 13562306a36Sopenharmony_ci .fmt = fmt, 13662306a36Sopenharmony_ci }; 13762306a36Sopenharmony_ci va_list args; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci va_start(args, fmt); 14062306a36Sopenharmony_ci vaf.va = &args; 14162306a36Sopenharmony_ci dev_warn_ratelimited(ar->dev, "%pV", &vaf); 14262306a36Sopenharmony_ci trace_ath10k_log_warn(ar, &vaf); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci va_end(args); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ciEXPORT_SYMBOL(ath10k_warn); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#ifdef CONFIG_ATH10K_DEBUGFS 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic ssize_t ath10k_read_wmi_services(struct file *file, 15162306a36Sopenharmony_ci char __user *user_buf, 15262306a36Sopenharmony_ci size_t count, loff_t *ppos) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 15562306a36Sopenharmony_ci char *buf; 15662306a36Sopenharmony_ci size_t len = 0, buf_len = 8192; 15762306a36Sopenharmony_ci const char *name; 15862306a36Sopenharmony_ci ssize_t ret_cnt; 15962306a36Sopenharmony_ci bool enabled; 16062306a36Sopenharmony_ci int i; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 16362306a36Sopenharmony_ci if (!buf) 16462306a36Sopenharmony_ci return -ENOMEM; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 16962306a36Sopenharmony_ci for (i = 0; i < WMI_SERVICE_MAX; i++) { 17062306a36Sopenharmony_ci enabled = test_bit(i, ar->wmi.svc_map); 17162306a36Sopenharmony_ci name = wmi_service_name(i); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!name) { 17462306a36Sopenharmony_ci if (enabled) 17562306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 17662306a36Sopenharmony_ci "%-40s %s (bit %d)\n", 17762306a36Sopenharmony_ci "unknown", "enabled", i); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci continue; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 18362306a36Sopenharmony_ci "%-40s %s\n", 18462306a36Sopenharmony_ci name, enabled ? "enabled" : "-"); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci kfree(buf); 19362306a36Sopenharmony_ci return ret_cnt; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic const struct file_operations fops_wmi_services = { 19762306a36Sopenharmony_ci .read = ath10k_read_wmi_services, 19862306a36Sopenharmony_ci .open = simple_open, 19962306a36Sopenharmony_ci .owner = THIS_MODULE, 20062306a36Sopenharmony_ci .llseek = default_llseek, 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic void ath10k_fw_stats_pdevs_free(struct list_head *head) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct ath10k_fw_stats_pdev *i, *tmp; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 20862306a36Sopenharmony_ci list_del(&i->list); 20962306a36Sopenharmony_ci kfree(i); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic void ath10k_fw_stats_vdevs_free(struct list_head *head) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct ath10k_fw_stats_vdev *i, *tmp; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 21862306a36Sopenharmony_ci list_del(&i->list); 21962306a36Sopenharmony_ci kfree(i); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void ath10k_fw_stats_peers_free(struct list_head *head) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct ath10k_fw_stats_peer *i, *tmp; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 22862306a36Sopenharmony_ci list_del(&i->list); 22962306a36Sopenharmony_ci kfree(i); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void ath10k_fw_extd_stats_peers_free(struct list_head *head) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct ath10k_fw_extd_stats_peer *i, *tmp; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 23862306a36Sopenharmony_ci list_del(&i->list); 23962306a36Sopenharmony_ci kfree(i); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void ath10k_debug_fw_stats_reset(struct ath10k *ar) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 24662306a36Sopenharmony_ci ar->debug.fw_stats_done = false; 24762306a36Sopenharmony_ci ar->debug.fw_stats.extended = false; 24862306a36Sopenharmony_ci ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); 24962306a36Sopenharmony_ci ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); 25062306a36Sopenharmony_ci ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); 25162306a36Sopenharmony_ci ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd); 25262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_civoid ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct ath10k_fw_stats stats = {}; 25862306a36Sopenharmony_ci bool is_start, is_started, is_end; 25962306a36Sopenharmony_ci size_t num_peers; 26062306a36Sopenharmony_ci size_t num_vdevs; 26162306a36Sopenharmony_ci int ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci INIT_LIST_HEAD(&stats.pdevs); 26462306a36Sopenharmony_ci INIT_LIST_HEAD(&stats.vdevs); 26562306a36Sopenharmony_ci INIT_LIST_HEAD(&stats.peers); 26662306a36Sopenharmony_ci INIT_LIST_HEAD(&stats.peers_extd); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 26962306a36Sopenharmony_ci ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); 27062306a36Sopenharmony_ci if (ret) { 27162306a36Sopenharmony_ci ath10k_warn(ar, "failed to pull fw stats: %d\n", ret); 27262306a36Sopenharmony_ci goto free; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Stat data may exceed htc-wmi buffer limit. In such case firmware 27662306a36Sopenharmony_ci * splits the stats data and delivers it in a ping-pong fashion of 27762306a36Sopenharmony_ci * request cmd-update event. 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * However there is no explicit end-of-data. Instead start-of-data is 28062306a36Sopenharmony_ci * used as an implicit one. This works as follows: 28162306a36Sopenharmony_ci * a) discard stat update events until one with pdev stats is 28262306a36Sopenharmony_ci * delivered - this skips session started at end of (b) 28362306a36Sopenharmony_ci * b) consume stat update events until another one with pdev stats is 28462306a36Sopenharmony_ci * delivered which is treated as end-of-data and is itself discarded 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci if (ath10k_peer_stats_enabled(ar)) 28762306a36Sopenharmony_ci ath10k_sta_update_rx_duration(ar, &stats); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (ar->debug.fw_stats_done) { 29062306a36Sopenharmony_ci if (!ath10k_peer_stats_enabled(ar)) 29162306a36Sopenharmony_ci ath10k_warn(ar, "received unsolicited stats update event\n"); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci goto free; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci num_peers = list_count_nodes(&ar->debug.fw_stats.peers); 29762306a36Sopenharmony_ci num_vdevs = list_count_nodes(&ar->debug.fw_stats.vdevs); 29862306a36Sopenharmony_ci is_start = (list_empty(&ar->debug.fw_stats.pdevs) && 29962306a36Sopenharmony_ci !list_empty(&stats.pdevs)); 30062306a36Sopenharmony_ci is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && 30162306a36Sopenharmony_ci !list_empty(&stats.pdevs)); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (is_start) 30462306a36Sopenharmony_ci list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (is_end) 30762306a36Sopenharmony_ci ar->debug.fw_stats_done = true; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (stats.extended) 31062306a36Sopenharmony_ci ar->debug.fw_stats.extended = true; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci is_started = !list_empty(&ar->debug.fw_stats.pdevs); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (is_started && !is_end) { 31562306a36Sopenharmony_ci if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) { 31662306a36Sopenharmony_ci /* Although this is unlikely impose a sane limit to 31762306a36Sopenharmony_ci * prevent firmware from DoS-ing the host. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); 32062306a36Sopenharmony_ci ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd); 32162306a36Sopenharmony_ci ath10k_warn(ar, "dropping fw peer stats\n"); 32262306a36Sopenharmony_ci goto free; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (num_vdevs >= BITS_PER_LONG) { 32662306a36Sopenharmony_ci ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); 32762306a36Sopenharmony_ci ath10k_warn(ar, "dropping fw vdev stats\n"); 32862306a36Sopenharmony_ci goto free; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!list_empty(&stats.peers)) 33262306a36Sopenharmony_ci list_splice_tail_init(&stats.peers_extd, 33362306a36Sopenharmony_ci &ar->debug.fw_stats.peers_extd); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); 33662306a36Sopenharmony_ci list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci complete(&ar->debug.fw_stats_complete); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cifree: 34262306a36Sopenharmony_ci /* In some cases lists have been spliced and cleared. Free up 34362306a36Sopenharmony_ci * resources if that is not the case. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci ath10k_fw_stats_pdevs_free(&stats.pdevs); 34662306a36Sopenharmony_ci ath10k_fw_stats_vdevs_free(&stats.vdevs); 34762306a36Sopenharmony_ci ath10k_fw_stats_peers_free(&stats.peers); 34862306a36Sopenharmony_ci ath10k_fw_extd_stats_peers_free(&stats.peers_extd); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ciint ath10k_debug_fw_stats_request(struct ath10k *ar) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci unsigned long timeout, time_left; 35662306a36Sopenharmony_ci int ret; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(1 * HZ); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci ath10k_debug_fw_stats_reset(ar); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci for (;;) { 36562306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 36662306a36Sopenharmony_ci return -ETIMEDOUT; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci reinit_completion(&ar->debug.fw_stats_complete); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci ath10k_warn(ar, "could not request stats (%d)\n", ret); 37362306a36Sopenharmony_ci return ret; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci time_left = 37762306a36Sopenharmony_ci wait_for_completion_timeout(&ar->debug.fw_stats_complete, 37862306a36Sopenharmony_ci 1 * HZ); 37962306a36Sopenharmony_ci if (!time_left) 38062306a36Sopenharmony_ci return -ETIMEDOUT; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 38362306a36Sopenharmony_ci if (ar->debug.fw_stats_done) { 38462306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return 0; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int ath10k_fw_stats_open(struct inode *inode, struct file *file) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct ath10k *ar = inode->i_private; 39662306a36Sopenharmony_ci void *buf = NULL; 39762306a36Sopenharmony_ci int ret; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 40262306a36Sopenharmony_ci ret = -ENETDOWN; 40362306a36Sopenharmony_ci goto err_unlock; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE); 40762306a36Sopenharmony_ci if (!buf) { 40862306a36Sopenharmony_ci ret = -ENOMEM; 40962306a36Sopenharmony_ci goto err_unlock; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ret = ath10k_debug_fw_stats_request(ar); 41362306a36Sopenharmony_ci if (ret) { 41462306a36Sopenharmony_ci ath10k_warn(ar, "failed to request fw stats: %d\n", ret); 41562306a36Sopenharmony_ci goto err_free; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf); 41962306a36Sopenharmony_ci if (ret) { 42062306a36Sopenharmony_ci ath10k_warn(ar, "failed to fill fw stats: %d\n", ret); 42162306a36Sopenharmony_ci goto err_free; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci file->private_data = buf; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cierr_free: 43062306a36Sopenharmony_ci vfree(buf); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cierr_unlock: 43362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 43462306a36Sopenharmony_ci return ret; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int ath10k_fw_stats_release(struct inode *inode, struct file *file) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci vfree(file->private_data); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf, 44562306a36Sopenharmony_ci size_t count, loff_t *ppos) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci const char *buf = file->private_data; 44862306a36Sopenharmony_ci size_t len = strlen(buf); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic const struct file_operations fops_fw_stats = { 45462306a36Sopenharmony_ci .open = ath10k_fw_stats_open, 45562306a36Sopenharmony_ci .release = ath10k_fw_stats_release, 45662306a36Sopenharmony_ci .read = ath10k_fw_stats_read, 45762306a36Sopenharmony_ci .owner = THIS_MODULE, 45862306a36Sopenharmony_ci .llseek = default_llseek, 45962306a36Sopenharmony_ci}; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic ssize_t ath10k_debug_fw_reset_stats_read(struct file *file, 46262306a36Sopenharmony_ci char __user *user_buf, 46362306a36Sopenharmony_ci size_t count, loff_t *ppos) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 46662306a36Sopenharmony_ci int ret; 46762306a36Sopenharmony_ci size_t len = 0, buf_len = 500; 46862306a36Sopenharmony_ci char *buf; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci buf = kmalloc(buf_len, GFP_KERNEL); 47162306a36Sopenharmony_ci if (!buf) 47262306a36Sopenharmony_ci return -ENOMEM; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 47762306a36Sopenharmony_ci "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter); 47862306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 47962306a36Sopenharmony_ci "fw_warm_reset_counter\t\t%d\n", 48062306a36Sopenharmony_ci ar->stats.fw_warm_reset_counter); 48162306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 48262306a36Sopenharmony_ci "fw_cold_reset_counter\t\t%d\n", 48362306a36Sopenharmony_ci ar->stats.fw_cold_reset_counter); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci kfree(buf); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return ret; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic const struct file_operations fops_fw_reset_stats = { 49562306a36Sopenharmony_ci .open = simple_open, 49662306a36Sopenharmony_ci .read = ath10k_debug_fw_reset_stats_read, 49762306a36Sopenharmony_ci .owner = THIS_MODULE, 49862306a36Sopenharmony_ci .llseek = default_llseek, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* This is a clean assert crash in firmware. */ 50262306a36Sopenharmony_cistatic int ath10k_debug_fw_assert(struct ath10k *ar) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct wmi_vdev_install_key_cmd *cmd; 50562306a36Sopenharmony_ci struct sk_buff *skb; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16); 50862306a36Sopenharmony_ci if (!skb) 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci cmd = (struct wmi_vdev_install_key_cmd *)skb->data; 51262306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* big enough number so that firmware asserts */ 51562306a36Sopenharmony_ci cmd->vdev_id = __cpu_to_le32(0x7ffe); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return ath10k_wmi_cmd_send(ar, skb, 51862306a36Sopenharmony_ci ar->wmi.cmd->vdev_install_key_cmdid); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic ssize_t ath10k_read_simulate_fw_crash(struct file *file, 52262306a36Sopenharmony_ci char __user *user_buf, 52362306a36Sopenharmony_ci size_t count, loff_t *ppos) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci const char buf[] = 52662306a36Sopenharmony_ci "To simulate firmware crash write one of the keywords to this file:\n" 52762306a36Sopenharmony_ci "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n" 52862306a36Sopenharmony_ci "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n" 52962306a36Sopenharmony_ci "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n" 53062306a36Sopenharmony_ci "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n"; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/* Simulate firmware crash: 53662306a36Sopenharmony_ci * 'soft': Call wmi command causing firmware hang. This firmware hang is 53762306a36Sopenharmony_ci * recoverable by warm firmware reset. 53862306a36Sopenharmony_ci * 'hard': Force firmware crash by setting any vdev parameter for not allowed 53962306a36Sopenharmony_ci * vdev id. This is hard firmware crash because it is recoverable only by cold 54062306a36Sopenharmony_ci * firmware reset. 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_cistatic ssize_t ath10k_write_simulate_fw_crash(struct file *file, 54362306a36Sopenharmony_ci const char __user *user_buf, 54462306a36Sopenharmony_ci size_t count, loff_t *ppos) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 54762306a36Sopenharmony_ci char buf[32] = {0}; 54862306a36Sopenharmony_ci ssize_t rc; 54962306a36Sopenharmony_ci int ret; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* filter partial writes and invalid commands */ 55262306a36Sopenharmony_ci if (*ppos != 0 || count >= sizeof(buf) || count == 0) 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); 55662306a36Sopenharmony_ci if (rc < 0) 55762306a36Sopenharmony_ci return rc; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* drop the possible '\n' from the end */ 56062306a36Sopenharmony_ci if (buf[*ppos - 1] == '\n') 56162306a36Sopenharmony_ci buf[*ppos - 1] = '\0'; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 56662306a36Sopenharmony_ci ar->state != ATH10K_STATE_RESTARTED) { 56762306a36Sopenharmony_ci ret = -ENETDOWN; 56862306a36Sopenharmony_ci goto exit; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (!strcmp(buf, "soft")) { 57262306a36Sopenharmony_ci ath10k_info(ar, "simulating soft firmware crash\n"); 57362306a36Sopenharmony_ci ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); 57462306a36Sopenharmony_ci } else if (!strcmp(buf, "hard")) { 57562306a36Sopenharmony_ci ath10k_info(ar, "simulating hard firmware crash\n"); 57662306a36Sopenharmony_ci /* 0x7fff is vdev id, and it is always out of range for all 57762306a36Sopenharmony_ci * firmware variants in order to force a firmware crash. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, 0x7fff, 58062306a36Sopenharmony_ci ar->wmi.vdev_param->rts_threshold, 58162306a36Sopenharmony_ci 0); 58262306a36Sopenharmony_ci } else if (!strcmp(buf, "assert")) { 58362306a36Sopenharmony_ci ath10k_info(ar, "simulating firmware assert crash\n"); 58462306a36Sopenharmony_ci ret = ath10k_debug_fw_assert(ar); 58562306a36Sopenharmony_ci } else if (!strcmp(buf, "hw-restart")) { 58662306a36Sopenharmony_ci ath10k_info(ar, "user requested hw restart\n"); 58762306a36Sopenharmony_ci ath10k_core_start_recovery(ar); 58862306a36Sopenharmony_ci ret = 0; 58962306a36Sopenharmony_ci } else { 59062306a36Sopenharmony_ci ret = -EINVAL; 59162306a36Sopenharmony_ci goto exit; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (ret) { 59562306a36Sopenharmony_ci ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret); 59662306a36Sopenharmony_ci goto exit; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci ret = count; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciexit: 60262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 60362306a36Sopenharmony_ci return ret; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic const struct file_operations fops_simulate_fw_crash = { 60762306a36Sopenharmony_ci .read = ath10k_read_simulate_fw_crash, 60862306a36Sopenharmony_ci .write = ath10k_write_simulate_fw_crash, 60962306a36Sopenharmony_ci .open = simple_open, 61062306a36Sopenharmony_ci .owner = THIS_MODULE, 61162306a36Sopenharmony_ci .llseek = default_llseek, 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf, 61562306a36Sopenharmony_ci size_t count, loff_t *ppos) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 61862306a36Sopenharmony_ci size_t len; 61962306a36Sopenharmony_ci char buf[50]; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->bus_param.chip_id); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic const struct file_operations fops_chip_id = { 62762306a36Sopenharmony_ci .read = ath10k_read_chip_id, 62862306a36Sopenharmony_ci .open = simple_open, 62962306a36Sopenharmony_ci .owner = THIS_MODULE, 63062306a36Sopenharmony_ci .llseek = default_llseek, 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic ssize_t ath10k_reg_addr_read(struct file *file, 63462306a36Sopenharmony_ci char __user *user_buf, 63562306a36Sopenharmony_ci size_t count, loff_t *ppos) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 63862306a36Sopenharmony_ci u8 buf[32]; 63962306a36Sopenharmony_ci size_t len = 0; 64062306a36Sopenharmony_ci u32 reg_addr; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 64362306a36Sopenharmony_ci reg_addr = ar->debug.reg_addr; 64462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic ssize_t ath10k_reg_addr_write(struct file *file, 65262306a36Sopenharmony_ci const char __user *user_buf, 65362306a36Sopenharmony_ci size_t count, loff_t *ppos) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 65662306a36Sopenharmony_ci u32 reg_addr; 65762306a36Sopenharmony_ci int ret; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ret = kstrtou32_from_user(user_buf, count, 0, ®_addr); 66062306a36Sopenharmony_ci if (ret) 66162306a36Sopenharmony_ci return ret; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!IS_ALIGNED(reg_addr, 4)) 66462306a36Sopenharmony_ci return -EFAULT; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 66762306a36Sopenharmony_ci ar->debug.reg_addr = reg_addr; 66862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return count; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic const struct file_operations fops_reg_addr = { 67462306a36Sopenharmony_ci .read = ath10k_reg_addr_read, 67562306a36Sopenharmony_ci .write = ath10k_reg_addr_write, 67662306a36Sopenharmony_ci .open = simple_open, 67762306a36Sopenharmony_ci .owner = THIS_MODULE, 67862306a36Sopenharmony_ci .llseek = default_llseek, 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic ssize_t ath10k_reg_value_read(struct file *file, 68262306a36Sopenharmony_ci char __user *user_buf, 68362306a36Sopenharmony_ci size_t count, loff_t *ppos) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 68662306a36Sopenharmony_ci u8 buf[48]; 68762306a36Sopenharmony_ci size_t len; 68862306a36Sopenharmony_ci u32 reg_addr, reg_val; 68962306a36Sopenharmony_ci int ret; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 69462306a36Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 69562306a36Sopenharmony_ci ret = -ENETDOWN; 69662306a36Sopenharmony_ci goto exit; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci reg_addr = ar->debug.reg_addr; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci reg_val = ath10k_hif_read32(ar, reg_addr); 70262306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ciexit: 70762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return ret; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic ssize_t ath10k_reg_value_write(struct file *file, 71362306a36Sopenharmony_ci const char __user *user_buf, 71462306a36Sopenharmony_ci size_t count, loff_t *ppos) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 71762306a36Sopenharmony_ci u32 reg_addr, reg_val; 71862306a36Sopenharmony_ci int ret; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 72362306a36Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 72462306a36Sopenharmony_ci ret = -ENETDOWN; 72562306a36Sopenharmony_ci goto exit; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci reg_addr = ar->debug.reg_addr; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = kstrtou32_from_user(user_buf, count, 0, ®_val); 73162306a36Sopenharmony_ci if (ret) 73262306a36Sopenharmony_ci goto exit; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ath10k_hif_write32(ar, reg_addr, reg_val); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci ret = count; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ciexit: 73962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return ret; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic const struct file_operations fops_reg_value = { 74562306a36Sopenharmony_ci .read = ath10k_reg_value_read, 74662306a36Sopenharmony_ci .write = ath10k_reg_value_write, 74762306a36Sopenharmony_ci .open = simple_open, 74862306a36Sopenharmony_ci .owner = THIS_MODULE, 74962306a36Sopenharmony_ci .llseek = default_llseek, 75062306a36Sopenharmony_ci}; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic ssize_t ath10k_mem_value_read(struct file *file, 75362306a36Sopenharmony_ci char __user *user_buf, 75462306a36Sopenharmony_ci size_t count, loff_t *ppos) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 75762306a36Sopenharmony_ci u8 *buf; 75862306a36Sopenharmony_ci int ret; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (*ppos < 0) 76162306a36Sopenharmony_ci return -EINVAL; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (!count) 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci buf = vmalloc(count); 76962306a36Sopenharmony_ci if (!buf) { 77062306a36Sopenharmony_ci ret = -ENOMEM; 77162306a36Sopenharmony_ci goto exit; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 77562306a36Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 77662306a36Sopenharmony_ci ret = -ENETDOWN; 77762306a36Sopenharmony_ci goto exit; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci ret = ath10k_hif_diag_read(ar, *ppos, buf, count); 78162306a36Sopenharmony_ci if (ret) { 78262306a36Sopenharmony_ci ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n", 78362306a36Sopenharmony_ci (u32)(*ppos), ret); 78462306a36Sopenharmony_ci goto exit; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci ret = copy_to_user(user_buf, buf, count); 78862306a36Sopenharmony_ci if (ret) { 78962306a36Sopenharmony_ci ret = -EFAULT; 79062306a36Sopenharmony_ci goto exit; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci count -= ret; 79462306a36Sopenharmony_ci *ppos += count; 79562306a36Sopenharmony_ci ret = count; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ciexit: 79862306a36Sopenharmony_ci vfree(buf); 79962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return ret; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic ssize_t ath10k_mem_value_write(struct file *file, 80562306a36Sopenharmony_ci const char __user *user_buf, 80662306a36Sopenharmony_ci size_t count, loff_t *ppos) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 80962306a36Sopenharmony_ci u8 *buf; 81062306a36Sopenharmony_ci int ret; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (*ppos < 0) 81362306a36Sopenharmony_ci return -EINVAL; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (!count) 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci buf = vmalloc(count); 82162306a36Sopenharmony_ci if (!buf) { 82262306a36Sopenharmony_ci ret = -ENOMEM; 82362306a36Sopenharmony_ci goto exit; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 82762306a36Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 82862306a36Sopenharmony_ci ret = -ENETDOWN; 82962306a36Sopenharmony_ci goto exit; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci ret = copy_from_user(buf, user_buf, count); 83362306a36Sopenharmony_ci if (ret) { 83462306a36Sopenharmony_ci ret = -EFAULT; 83562306a36Sopenharmony_ci goto exit; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci ret = ath10k_hif_diag_write(ar, *ppos, buf, count); 83962306a36Sopenharmony_ci if (ret) { 84062306a36Sopenharmony_ci ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n", 84162306a36Sopenharmony_ci (u32)(*ppos), ret); 84262306a36Sopenharmony_ci goto exit; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci *ppos += count; 84662306a36Sopenharmony_ci ret = count; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ciexit: 84962306a36Sopenharmony_ci vfree(buf); 85062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci return ret; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic const struct file_operations fops_mem_value = { 85662306a36Sopenharmony_ci .read = ath10k_mem_value_read, 85762306a36Sopenharmony_ci .write = ath10k_mem_value_write, 85862306a36Sopenharmony_ci .open = simple_open, 85962306a36Sopenharmony_ci .owner = THIS_MODULE, 86062306a36Sopenharmony_ci .llseek = default_llseek, 86162306a36Sopenharmony_ci}; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic int ath10k_debug_htt_stats_req(struct ath10k *ar) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci u64 cookie; 86662306a36Sopenharmony_ci int ret; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (ar->debug.htt_stats_mask == 0) 87162306a36Sopenharmony_ci /* htt stats are disabled */ 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) 87562306a36Sopenharmony_ci return 0; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci cookie = get_jiffies_64(); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, 88062306a36Sopenharmony_ci ar->debug.reset_htt_stats, cookie); 88162306a36Sopenharmony_ci if (ret) { 88262306a36Sopenharmony_ci ath10k_warn(ar, "failed to send htt stats request: %d\n", ret); 88362306a36Sopenharmony_ci return ret; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork, 88762306a36Sopenharmony_ci msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL)); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return 0; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic void ath10k_debug_htt_stats_dwork(struct work_struct *work) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci struct ath10k *ar = container_of(work, struct ath10k, 89562306a36Sopenharmony_ci debug.htt_stats_dwork.work); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci ath10k_debug_htt_stats_req(ar); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic ssize_t ath10k_read_htt_stats_mask(struct file *file, 90562306a36Sopenharmony_ci char __user *user_buf, 90662306a36Sopenharmony_ci size_t count, loff_t *ppos) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 90962306a36Sopenharmony_ci char buf[32]; 91062306a36Sopenharmony_ci size_t len; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic ssize_t ath10k_write_htt_stats_mask(struct file *file, 91862306a36Sopenharmony_ci const char __user *user_buf, 91962306a36Sopenharmony_ci size_t count, loff_t *ppos) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 92262306a36Sopenharmony_ci unsigned long mask; 92362306a36Sopenharmony_ci int ret; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci ret = kstrtoul_from_user(user_buf, count, 0, &mask); 92662306a36Sopenharmony_ci if (ret) 92762306a36Sopenharmony_ci return ret; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* max 17 bit masks (for now) */ 93062306a36Sopenharmony_ci if (mask > HTT_STATS_BIT_MASK) 93162306a36Sopenharmony_ci return -E2BIG; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci ar->debug.htt_stats_mask = mask; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci ret = ath10k_debug_htt_stats_req(ar); 93862306a36Sopenharmony_ci if (ret) 93962306a36Sopenharmony_ci goto out; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ret = count; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ciout: 94462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return ret; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic const struct file_operations fops_htt_stats_mask = { 95062306a36Sopenharmony_ci .read = ath10k_read_htt_stats_mask, 95162306a36Sopenharmony_ci .write = ath10k_write_htt_stats_mask, 95262306a36Sopenharmony_ci .open = simple_open, 95362306a36Sopenharmony_ci .owner = THIS_MODULE, 95462306a36Sopenharmony_ci .llseek = default_llseek, 95562306a36Sopenharmony_ci}; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, 95862306a36Sopenharmony_ci char __user *user_buf, 95962306a36Sopenharmony_ci size_t count, loff_t *ppos) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 96262306a36Sopenharmony_ci char buf[64]; 96362306a36Sopenharmony_ci u8 amsdu, ampdu; 96462306a36Sopenharmony_ci size_t len; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci amsdu = ar->htt.max_num_amsdu; 96962306a36Sopenharmony_ci ampdu = ar->htt.max_num_ampdu; 97062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, 97862306a36Sopenharmony_ci const char __user *user_buf, 97962306a36Sopenharmony_ci size_t count, loff_t *ppos) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 98262306a36Sopenharmony_ci int res; 98362306a36Sopenharmony_ci char buf[64] = {0}; 98462306a36Sopenharmony_ci unsigned int amsdu, ampdu; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 98762306a36Sopenharmony_ci user_buf, count); 98862306a36Sopenharmony_ci if (res <= 0) 98962306a36Sopenharmony_ci return res; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci res = sscanf(buf, "%u %u", &amsdu, &du); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (res != 2) 99462306a36Sopenharmony_ci return -EINVAL; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu); 99962306a36Sopenharmony_ci if (res) 100062306a36Sopenharmony_ci goto out; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci res = count; 100362306a36Sopenharmony_ci ar->htt.max_num_amsdu = amsdu; 100462306a36Sopenharmony_ci ar->htt.max_num_ampdu = ampdu; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ciout: 100762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 100862306a36Sopenharmony_ci return res; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic const struct file_operations fops_htt_max_amsdu_ampdu = { 101262306a36Sopenharmony_ci .read = ath10k_read_htt_max_amsdu_ampdu, 101362306a36Sopenharmony_ci .write = ath10k_write_htt_max_amsdu_ampdu, 101462306a36Sopenharmony_ci .open = simple_open, 101562306a36Sopenharmony_ci .owner = THIS_MODULE, 101662306a36Sopenharmony_ci .llseek = default_llseek, 101762306a36Sopenharmony_ci}; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic ssize_t ath10k_read_fw_dbglog(struct file *file, 102062306a36Sopenharmony_ci char __user *user_buf, 102162306a36Sopenharmony_ci size_t count, loff_t *ppos) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 102462306a36Sopenharmony_ci size_t len; 102562306a36Sopenharmony_ci char buf[96]; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%16llx %u\n", 102862306a36Sopenharmony_ci ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic ssize_t ath10k_write_fw_dbglog(struct file *file, 103462306a36Sopenharmony_ci const char __user *user_buf, 103562306a36Sopenharmony_ci size_t count, loff_t *ppos) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 103862306a36Sopenharmony_ci int ret; 103962306a36Sopenharmony_ci char buf[96] = {0}; 104062306a36Sopenharmony_ci unsigned int log_level; 104162306a36Sopenharmony_ci u64 mask; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 104462306a36Sopenharmony_ci user_buf, count); 104562306a36Sopenharmony_ci if (ret <= 0) 104662306a36Sopenharmony_ci return ret; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci ret = sscanf(buf, "%llx %u", &mask, &log_level); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (!ret) 105162306a36Sopenharmony_ci return -EINVAL; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (ret == 1) 105462306a36Sopenharmony_ci /* default if user did not specify */ 105562306a36Sopenharmony_ci log_level = ATH10K_DBGLOG_LEVEL_WARN; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci ar->debug.fw_dbglog_mask = mask; 106062306a36Sopenharmony_ci ar->debug.fw_dbglog_level = log_level; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (ar->state == ATH10K_STATE_ON) { 106362306a36Sopenharmony_ci ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, 106462306a36Sopenharmony_ci ar->debug.fw_dbglog_level); 106562306a36Sopenharmony_ci if (ret) { 106662306a36Sopenharmony_ci ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", 106762306a36Sopenharmony_ci ret); 106862306a36Sopenharmony_ci goto exit; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci ret = count; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ciexit: 107562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci return ret; 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci/* TODO: Would be nice to always support ethtool stats, would need to 108162306a36Sopenharmony_ci * move the stats storage out of ath10k_debug, or always have ath10k_debug 108262306a36Sopenharmony_ci * struct available.. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci/* This generally corresponds to the debugfs fw_stats file */ 108662306a36Sopenharmony_cistatic const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { 108762306a36Sopenharmony_ci "tx_pkts_nic", 108862306a36Sopenharmony_ci "tx_bytes_nic", 108962306a36Sopenharmony_ci "rx_pkts_nic", 109062306a36Sopenharmony_ci "rx_bytes_nic", 109162306a36Sopenharmony_ci "d_noise_floor", 109262306a36Sopenharmony_ci "d_cycle_count", 109362306a36Sopenharmony_ci "d_phy_error", 109462306a36Sopenharmony_ci "d_rts_bad", 109562306a36Sopenharmony_ci "d_rts_good", 109662306a36Sopenharmony_ci "d_tx_power", /* in .5 dbM I think */ 109762306a36Sopenharmony_ci "d_rx_crc_err", /* fcs_bad */ 109862306a36Sopenharmony_ci "d_rx_crc_err_drop", /* frame with FCS error, dropped late in kernel */ 109962306a36Sopenharmony_ci "d_no_beacon", 110062306a36Sopenharmony_ci "d_tx_mpdus_queued", 110162306a36Sopenharmony_ci "d_tx_msdu_queued", 110262306a36Sopenharmony_ci "d_tx_msdu_dropped", 110362306a36Sopenharmony_ci "d_local_enqued", 110462306a36Sopenharmony_ci "d_local_freed", 110562306a36Sopenharmony_ci "d_tx_ppdu_hw_queued", 110662306a36Sopenharmony_ci "d_tx_ppdu_reaped", 110762306a36Sopenharmony_ci "d_tx_fifo_underrun", 110862306a36Sopenharmony_ci "d_tx_ppdu_abort", 110962306a36Sopenharmony_ci "d_tx_mpdu_requeued", 111062306a36Sopenharmony_ci "d_tx_excessive_retries", 111162306a36Sopenharmony_ci "d_tx_hw_rate", 111262306a36Sopenharmony_ci "d_tx_dropped_sw_retries", 111362306a36Sopenharmony_ci "d_tx_illegal_rate", 111462306a36Sopenharmony_ci "d_tx_continuous_xretries", 111562306a36Sopenharmony_ci "d_tx_timeout", 111662306a36Sopenharmony_ci "d_tx_mpdu_txop_limit", 111762306a36Sopenharmony_ci "d_pdev_resets", 111862306a36Sopenharmony_ci "d_rx_mid_ppdu_route_change", 111962306a36Sopenharmony_ci "d_rx_status", 112062306a36Sopenharmony_ci "d_rx_extra_frags_ring0", 112162306a36Sopenharmony_ci "d_rx_extra_frags_ring1", 112262306a36Sopenharmony_ci "d_rx_extra_frags_ring2", 112362306a36Sopenharmony_ci "d_rx_extra_frags_ring3", 112462306a36Sopenharmony_ci "d_rx_msdu_htt", 112562306a36Sopenharmony_ci "d_rx_mpdu_htt", 112662306a36Sopenharmony_ci "d_rx_msdu_stack", 112762306a36Sopenharmony_ci "d_rx_mpdu_stack", 112862306a36Sopenharmony_ci "d_rx_phy_err", 112962306a36Sopenharmony_ci "d_rx_phy_err_drops", 113062306a36Sopenharmony_ci "d_rx_mpdu_errors", /* FCS, MIC, ENC */ 113162306a36Sopenharmony_ci "d_fw_crash_count", 113262306a36Sopenharmony_ci "d_fw_warm_reset_count", 113362306a36Sopenharmony_ci "d_fw_cold_reset_count", 113462306a36Sopenharmony_ci}; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats) 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_civoid ath10k_debug_get_et_strings(struct ieee80211_hw *hw, 113962306a36Sopenharmony_ci struct ieee80211_vif *vif, 114062306a36Sopenharmony_ci u32 sset, u8 *data) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci if (sset == ETH_SS_STATS) 114362306a36Sopenharmony_ci memcpy(data, ath10k_gstrings_stats, 114462306a36Sopenharmony_ci sizeof(ath10k_gstrings_stats)); 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ciint ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, 114862306a36Sopenharmony_ci struct ieee80211_vif *vif, int sset) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci if (sset == ETH_SS_STATS) 115162306a36Sopenharmony_ci return ATH10K_SSTATS_LEN; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci return 0; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_civoid ath10k_debug_get_et_stats(struct ieee80211_hw *hw, 115762306a36Sopenharmony_ci struct ieee80211_vif *vif, 115862306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 116162306a36Sopenharmony_ci static const struct ath10k_fw_stats_pdev zero_stats = {}; 116262306a36Sopenharmony_ci const struct ath10k_fw_stats_pdev *pdev_stats; 116362306a36Sopenharmony_ci int i = 0, ret; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (ar->state == ATH10K_STATE_ON) { 116862306a36Sopenharmony_ci ret = ath10k_debug_fw_stats_request(ar); 116962306a36Sopenharmony_ci if (ret) { 117062306a36Sopenharmony_ci /* just print a warning and try to use older results */ 117162306a36Sopenharmony_ci ath10k_warn(ar, 117262306a36Sopenharmony_ci "failed to get fw stats for ethtool: %d\n", 117362306a36Sopenharmony_ci ret); 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs, 117862306a36Sopenharmony_ci struct ath10k_fw_stats_pdev, 117962306a36Sopenharmony_ci list); 118062306a36Sopenharmony_ci if (!pdev_stats) { 118162306a36Sopenharmony_ci /* no results available so just return zeroes */ 118262306a36Sopenharmony_ci pdev_stats = &zero_stats; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */ 118862306a36Sopenharmony_ci data[i++] = 0; /* tx bytes */ 118962306a36Sopenharmony_ci data[i++] = pdev_stats->htt_mpdus; 119062306a36Sopenharmony_ci data[i++] = 0; /* rx bytes */ 119162306a36Sopenharmony_ci data[i++] = pdev_stats->ch_noise_floor; 119262306a36Sopenharmony_ci data[i++] = pdev_stats->cycle_count; 119362306a36Sopenharmony_ci data[i++] = pdev_stats->phy_err_count; 119462306a36Sopenharmony_ci data[i++] = pdev_stats->rts_bad; 119562306a36Sopenharmony_ci data[i++] = pdev_stats->rts_good; 119662306a36Sopenharmony_ci data[i++] = pdev_stats->chan_tx_power; 119762306a36Sopenharmony_ci data[i++] = pdev_stats->fcs_bad; 119862306a36Sopenharmony_ci data[i++] = ar->stats.rx_crc_err_drop; 119962306a36Sopenharmony_ci data[i++] = pdev_stats->no_beacons; 120062306a36Sopenharmony_ci data[i++] = pdev_stats->mpdu_enqued; 120162306a36Sopenharmony_ci data[i++] = pdev_stats->msdu_enqued; 120262306a36Sopenharmony_ci data[i++] = pdev_stats->wmm_drop; 120362306a36Sopenharmony_ci data[i++] = pdev_stats->local_enqued; 120462306a36Sopenharmony_ci data[i++] = pdev_stats->local_freed; 120562306a36Sopenharmony_ci data[i++] = pdev_stats->hw_queued; 120662306a36Sopenharmony_ci data[i++] = pdev_stats->hw_reaped; 120762306a36Sopenharmony_ci data[i++] = pdev_stats->underrun; 120862306a36Sopenharmony_ci data[i++] = pdev_stats->tx_abort; 120962306a36Sopenharmony_ci data[i++] = pdev_stats->mpdus_requeued; 121062306a36Sopenharmony_ci data[i++] = pdev_stats->tx_ko; 121162306a36Sopenharmony_ci data[i++] = pdev_stats->data_rc; 121262306a36Sopenharmony_ci data[i++] = pdev_stats->sw_retry_failure; 121362306a36Sopenharmony_ci data[i++] = pdev_stats->illgl_rate_phy_err; 121462306a36Sopenharmony_ci data[i++] = pdev_stats->pdev_cont_xretry; 121562306a36Sopenharmony_ci data[i++] = pdev_stats->pdev_tx_timeout; 121662306a36Sopenharmony_ci data[i++] = pdev_stats->txop_ovf; 121762306a36Sopenharmony_ci data[i++] = pdev_stats->pdev_resets; 121862306a36Sopenharmony_ci data[i++] = pdev_stats->mid_ppdu_route_change; 121962306a36Sopenharmony_ci data[i++] = pdev_stats->status_rcvd; 122062306a36Sopenharmony_ci data[i++] = pdev_stats->r0_frags; 122162306a36Sopenharmony_ci data[i++] = pdev_stats->r1_frags; 122262306a36Sopenharmony_ci data[i++] = pdev_stats->r2_frags; 122362306a36Sopenharmony_ci data[i++] = pdev_stats->r3_frags; 122462306a36Sopenharmony_ci data[i++] = pdev_stats->htt_msdus; 122562306a36Sopenharmony_ci data[i++] = pdev_stats->htt_mpdus; 122662306a36Sopenharmony_ci data[i++] = pdev_stats->loc_msdus; 122762306a36Sopenharmony_ci data[i++] = pdev_stats->loc_mpdus; 122862306a36Sopenharmony_ci data[i++] = pdev_stats->phy_errs; 122962306a36Sopenharmony_ci data[i++] = pdev_stats->phy_err_drop; 123062306a36Sopenharmony_ci data[i++] = pdev_stats->mpdu_errs; 123162306a36Sopenharmony_ci data[i++] = ar->stats.fw_crash_counter; 123262306a36Sopenharmony_ci data[i++] = ar->stats.fw_warm_reset_counter; 123362306a36Sopenharmony_ci data[i++] = ar->stats.fw_cold_reset_counter; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci WARN_ON(i != ATH10K_SSTATS_LEN); 124062306a36Sopenharmony_ci} 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic const struct file_operations fops_fw_dbglog = { 124362306a36Sopenharmony_ci .read = ath10k_read_fw_dbglog, 124462306a36Sopenharmony_ci .write = ath10k_write_fw_dbglog, 124562306a36Sopenharmony_ci .open = simple_open, 124662306a36Sopenharmony_ci .owner = THIS_MODULE, 124762306a36Sopenharmony_ci .llseek = default_llseek, 124862306a36Sopenharmony_ci}; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic int ath10k_debug_cal_data_fetch(struct ath10k *ar) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci u32 hi_addr; 125362306a36Sopenharmony_ci __le32 addr; 125462306a36Sopenharmony_ci int ret; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN)) 125962306a36Sopenharmony_ci return -EINVAL; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (ar->hw_params.cal_data_len == 0) 126262306a36Sopenharmony_ci return -EOPNOTSUPP; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci hi_addr = host_interest_item_address(HI_ITEM(hi_board_data)); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr)); 126762306a36Sopenharmony_ci if (ret) { 126862306a36Sopenharmony_ci ath10k_warn(ar, "failed to read hi_board_data address: %d\n", 126962306a36Sopenharmony_ci ret); 127062306a36Sopenharmony_ci return ret; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data, 127462306a36Sopenharmony_ci ar->hw_params.cal_data_len); 127562306a36Sopenharmony_ci if (ret) { 127662306a36Sopenharmony_ci ath10k_warn(ar, "failed to read calibration data: %d\n", ret); 127762306a36Sopenharmony_ci return ret; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return 0; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct ath10k *ar = inode->i_private; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (ar->state == ATH10K_STATE_ON || 129062306a36Sopenharmony_ci ar->state == ATH10K_STATE_UTF) { 129162306a36Sopenharmony_ci ath10k_debug_cal_data_fetch(ar); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci file->private_data = ar; 129562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci return 0; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic ssize_t ath10k_debug_cal_data_read(struct file *file, 130162306a36Sopenharmony_ci char __user *user_buf, 130262306a36Sopenharmony_ci size_t count, loff_t *ppos) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci count = simple_read_from_buffer(user_buf, count, ppos, 130962306a36Sopenharmony_ci ar->debug.cal_data, 131062306a36Sopenharmony_ci ar->hw_params.cal_data_len); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return count; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic ssize_t ath10k_write_ani_enable(struct file *file, 131862306a36Sopenharmony_ci const char __user *user_buf, 131962306a36Sopenharmony_ci size_t count, loff_t *ppos) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 132262306a36Sopenharmony_ci int ret; 132362306a36Sopenharmony_ci u8 enable; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci if (kstrtou8_from_user(user_buf, count, 0, &enable)) 132662306a36Sopenharmony_ci return -EINVAL; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci if (ar->ani_enabled == enable) { 133162306a36Sopenharmony_ci ret = count; 133262306a36Sopenharmony_ci goto exit; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable, 133662306a36Sopenharmony_ci enable); 133762306a36Sopenharmony_ci if (ret) { 133862306a36Sopenharmony_ci ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret); 133962306a36Sopenharmony_ci goto exit; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci ar->ani_enabled = enable; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci ret = count; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ciexit: 134662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return ret; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf, 135262306a36Sopenharmony_ci size_t count, loff_t *ppos) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 135562306a36Sopenharmony_ci size_t len; 135662306a36Sopenharmony_ci char buf[32]; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cistatic const struct file_operations fops_ani_enable = { 136462306a36Sopenharmony_ci .read = ath10k_read_ani_enable, 136562306a36Sopenharmony_ci .write = ath10k_write_ani_enable, 136662306a36Sopenharmony_ci .open = simple_open, 136762306a36Sopenharmony_ci .owner = THIS_MODULE, 136862306a36Sopenharmony_ci .llseek = default_llseek, 136962306a36Sopenharmony_ci}; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic const struct file_operations fops_cal_data = { 137262306a36Sopenharmony_ci .open = ath10k_debug_cal_data_open, 137362306a36Sopenharmony_ci .read = ath10k_debug_cal_data_read, 137462306a36Sopenharmony_ci .owner = THIS_MODULE, 137562306a36Sopenharmony_ci .llseek = default_llseek, 137662306a36Sopenharmony_ci}; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic ssize_t ath10k_read_nf_cal_period(struct file *file, 137962306a36Sopenharmony_ci char __user *user_buf, 138062306a36Sopenharmony_ci size_t count, loff_t *ppos) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 138362306a36Sopenharmony_ci size_t len; 138462306a36Sopenharmony_ci char buf[32]; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%d\n", ar->debug.nf_cal_period); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic ssize_t ath10k_write_nf_cal_period(struct file *file, 139262306a36Sopenharmony_ci const char __user *user_buf, 139362306a36Sopenharmony_ci size_t count, loff_t *ppos) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 139662306a36Sopenharmony_ci unsigned long period; 139762306a36Sopenharmony_ci int ret; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci ret = kstrtoul_from_user(user_buf, count, 0, &period); 140062306a36Sopenharmony_ci if (ret) 140162306a36Sopenharmony_ci return ret; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX) 140462306a36Sopenharmony_ci return -EINVAL; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* there's no way to switch back to the firmware default */ 140762306a36Sopenharmony_ci if (period == 0) 140862306a36Sopenharmony_ci return -EINVAL; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci ar->debug.nf_cal_period = period; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 141562306a36Sopenharmony_ci /* firmware is not running, nothing else to do */ 141662306a36Sopenharmony_ci ret = count; 141762306a36Sopenharmony_ci goto exit; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, 142162306a36Sopenharmony_ci ar->debug.nf_cal_period); 142262306a36Sopenharmony_ci if (ret) { 142362306a36Sopenharmony_ci ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n", 142462306a36Sopenharmony_ci ret); 142562306a36Sopenharmony_ci goto exit; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci ret = count; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ciexit: 143162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci return ret; 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic const struct file_operations fops_nf_cal_period = { 143762306a36Sopenharmony_ci .read = ath10k_read_nf_cal_period, 143862306a36Sopenharmony_ci .write = ath10k_write_nf_cal_period, 143962306a36Sopenharmony_ci .open = simple_open, 144062306a36Sopenharmony_ci .owner = THIS_MODULE, 144162306a36Sopenharmony_ci .llseek = default_llseek, 144262306a36Sopenharmony_ci}; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci#define ATH10K_TPC_CONFIG_BUF_SIZE (1024 * 1024) 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_cistatic int ath10k_debug_tpc_stats_request(struct ath10k *ar) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci int ret; 144962306a36Sopenharmony_ci unsigned long time_left; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci reinit_completion(&ar->debug.tpc_complete); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM); 145662306a36Sopenharmony_ci if (ret) { 145762306a36Sopenharmony_ci ath10k_warn(ar, "failed to request tpc config: %d\n", ret); 145862306a36Sopenharmony_ci return ret; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->debug.tpc_complete, 146262306a36Sopenharmony_ci 1 * HZ); 146362306a36Sopenharmony_ci if (time_left == 0) 146462306a36Sopenharmony_ci return -ETIMEDOUT; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci return 0; 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_civoid ath10k_debug_tpc_stats_process(struct ath10k *ar, 147062306a36Sopenharmony_ci struct ath10k_tpc_stats *tpc_stats) 147162306a36Sopenharmony_ci{ 147262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci kfree(ar->debug.tpc_stats); 147562306a36Sopenharmony_ci ar->debug.tpc_stats = tpc_stats; 147662306a36Sopenharmony_ci complete(&ar->debug.tpc_complete); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_civoid 148262306a36Sopenharmony_ciath10k_debug_tpc_stats_final_process(struct ath10k *ar, 148362306a36Sopenharmony_ci struct ath10k_tpc_stats_final *tpc_stats) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci kfree(ar->debug.tpc_stats_final); 148862306a36Sopenharmony_ci ar->debug.tpc_stats_final = tpc_stats; 148962306a36Sopenharmony_ci complete(&ar->debug.tpc_complete); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 149262306a36Sopenharmony_ci} 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_cistatic void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, 149562306a36Sopenharmony_ci unsigned int j, char *buf, size_t *len) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci int i; 149862306a36Sopenharmony_ci size_t buf_len; 149962306a36Sopenharmony_ci static const char table_str[][5] = { "CDD", 150062306a36Sopenharmony_ci "STBC", 150162306a36Sopenharmony_ci "TXBF" }; 150262306a36Sopenharmony_ci static const char pream_str[][6] = { "CCK", 150362306a36Sopenharmony_ci "OFDM", 150462306a36Sopenharmony_ci "HT20", 150562306a36Sopenharmony_ci "HT40", 150662306a36Sopenharmony_ci "VHT20", 150762306a36Sopenharmony_ci "VHT40", 150862306a36Sopenharmony_ci "VHT80", 150962306a36Sopenharmony_ci "HTCUP" }; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci buf_len = ATH10K_TPC_CONFIG_BUF_SIZE; 151262306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 151362306a36Sopenharmony_ci "********************************\n"); 151462306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 151562306a36Sopenharmony_ci "******************* %s POWER TABLE ****************\n", 151662306a36Sopenharmony_ci table_str[j]); 151762306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 151862306a36Sopenharmony_ci "********************************\n"); 151962306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 152062306a36Sopenharmony_ci "No. Preamble Rate_code "); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci for (i = 0; i < tpc_stats->num_tx_chain; i++) 152362306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 152462306a36Sopenharmony_ci "tpc_value%d ", i); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, "\n"); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci for (i = 0; i < tpc_stats->rate_max; i++) { 152962306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 153062306a36Sopenharmony_ci "%8d %s 0x%2x %s\n", i, 153162306a36Sopenharmony_ci pream_str[tpc_stats->tpc_table[j].pream_idx[i]], 153262306a36Sopenharmony_ci tpc_stats->tpc_table[j].rate_code[i], 153362306a36Sopenharmony_ci tpc_stats->tpc_table[j].tpc_value[i]); 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 153762306a36Sopenharmony_ci "***********************************\n"); 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic void ath10k_tpc_stats_fill(struct ath10k *ar, 154162306a36Sopenharmony_ci struct ath10k_tpc_stats *tpc_stats, 154262306a36Sopenharmony_ci char *buf) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci int j; 154562306a36Sopenharmony_ci size_t len, buf_len; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci len = 0; 154862306a36Sopenharmony_ci buf_len = ATH10K_TPC_CONFIG_BUF_SIZE; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci if (!tpc_stats) { 155362306a36Sopenharmony_ci ath10k_warn(ar, "failed to get tpc stats\n"); 155462306a36Sopenharmony_ci goto unlock; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); 155862306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 155962306a36Sopenharmony_ci "*************************************\n"); 156062306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 156162306a36Sopenharmony_ci "TPC config for channel %4d mode %d\n", 156262306a36Sopenharmony_ci tpc_stats->chan_freq, 156362306a36Sopenharmony_ci tpc_stats->phy_mode); 156462306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 156562306a36Sopenharmony_ci "*************************************\n"); 156662306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 156762306a36Sopenharmony_ci "CTL = 0x%2x Reg. Domain = %2d\n", 156862306a36Sopenharmony_ci tpc_stats->ctl, 156962306a36Sopenharmony_ci tpc_stats->reg_domain); 157062306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 157162306a36Sopenharmony_ci "Antenna Gain = %2d Reg. Max Antenna Gain = %2d\n", 157262306a36Sopenharmony_ci tpc_stats->twice_antenna_gain, 157362306a36Sopenharmony_ci tpc_stats->twice_antenna_reduction); 157462306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 157562306a36Sopenharmony_ci "Power Limit = %2d Reg. Max Power = %2d\n", 157662306a36Sopenharmony_ci tpc_stats->power_limit, 157762306a36Sopenharmony_ci tpc_stats->twice_max_rd_power / 2); 157862306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 157962306a36Sopenharmony_ci "Num tx chains = %2d Num supported rates = %2d\n", 158062306a36Sopenharmony_ci tpc_stats->num_tx_chain, 158162306a36Sopenharmony_ci tpc_stats->rate_max); 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci for (j = 0; j < WMI_TPC_FLAG; j++) { 158462306a36Sopenharmony_ci switch (j) { 158562306a36Sopenharmony_ci case WMI_TPC_TABLE_TYPE_CDD: 158662306a36Sopenharmony_ci if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { 158762306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 158862306a36Sopenharmony_ci "CDD not supported\n"); 158962306a36Sopenharmony_ci break; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci ath10k_tpc_stats_print(tpc_stats, j, buf, &len); 159362306a36Sopenharmony_ci break; 159462306a36Sopenharmony_ci case WMI_TPC_TABLE_TYPE_STBC: 159562306a36Sopenharmony_ci if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { 159662306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 159762306a36Sopenharmony_ci "STBC not supported\n"); 159862306a36Sopenharmony_ci break; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci ath10k_tpc_stats_print(tpc_stats, j, buf, &len); 160262306a36Sopenharmony_ci break; 160362306a36Sopenharmony_ci case WMI_TPC_TABLE_TYPE_TXBF: 160462306a36Sopenharmony_ci if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { 160562306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 160662306a36Sopenharmony_ci "TXBF not supported\n***************************\n"); 160762306a36Sopenharmony_ci break; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci ath10k_tpc_stats_print(tpc_stats, j, buf, &len); 161162306a36Sopenharmony_ci break; 161262306a36Sopenharmony_ci default: 161362306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 161462306a36Sopenharmony_ci "Invalid Type\n"); 161562306a36Sopenharmony_ci break; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ciunlock: 162062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (len >= buf_len) 162362306a36Sopenharmony_ci buf[len - 1] = 0; 162462306a36Sopenharmony_ci else 162562306a36Sopenharmony_ci buf[len] = 0; 162662306a36Sopenharmony_ci} 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistatic int ath10k_tpc_stats_open(struct inode *inode, struct file *file) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci struct ath10k *ar = inode->i_private; 163162306a36Sopenharmony_ci void *buf = NULL; 163262306a36Sopenharmony_ci int ret; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 163762306a36Sopenharmony_ci ret = -ENETDOWN; 163862306a36Sopenharmony_ci goto err_unlock; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE); 164262306a36Sopenharmony_ci if (!buf) { 164362306a36Sopenharmony_ci ret = -ENOMEM; 164462306a36Sopenharmony_ci goto err_unlock; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci ret = ath10k_debug_tpc_stats_request(ar); 164862306a36Sopenharmony_ci if (ret) { 164962306a36Sopenharmony_ci ath10k_warn(ar, "failed to request tpc config stats: %d\n", 165062306a36Sopenharmony_ci ret); 165162306a36Sopenharmony_ci goto err_free; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf); 165562306a36Sopenharmony_ci file->private_data = buf; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 165862306a36Sopenharmony_ci return 0; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_cierr_free: 166162306a36Sopenharmony_ci vfree(buf); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_cierr_unlock: 166462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 166562306a36Sopenharmony_ci return ret; 166662306a36Sopenharmony_ci} 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_cistatic int ath10k_tpc_stats_release(struct inode *inode, struct file *file) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci vfree(file->private_data); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci return 0; 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf, 167662306a36Sopenharmony_ci size_t count, loff_t *ppos) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci const char *buf = file->private_data; 167962306a36Sopenharmony_ci size_t len = strlen(buf); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 168262306a36Sopenharmony_ci} 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_cistatic const struct file_operations fops_tpc_stats = { 168562306a36Sopenharmony_ci .open = ath10k_tpc_stats_open, 168662306a36Sopenharmony_ci .release = ath10k_tpc_stats_release, 168762306a36Sopenharmony_ci .read = ath10k_tpc_stats_read, 168862306a36Sopenharmony_ci .owner = THIS_MODULE, 168962306a36Sopenharmony_ci .llseek = default_llseek, 169062306a36Sopenharmony_ci}; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ciint ath10k_debug_start(struct ath10k *ar) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci int ret; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci ret = ath10k_debug_htt_stats_req(ar); 169962306a36Sopenharmony_ci if (ret) 170062306a36Sopenharmony_ci /* continue normally anyway, this isn't serious */ 170162306a36Sopenharmony_ci ath10k_warn(ar, "failed to start htt stats workqueue: %d\n", 170262306a36Sopenharmony_ci ret); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (ar->debug.fw_dbglog_mask) { 170562306a36Sopenharmony_ci ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, 170662306a36Sopenharmony_ci ATH10K_DBGLOG_LEVEL_WARN); 170762306a36Sopenharmony_ci if (ret) 170862306a36Sopenharmony_ci /* not serious */ 170962306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable dbglog during start: %d", 171062306a36Sopenharmony_ci ret); 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci if (ar->pktlog_filter) { 171462306a36Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_enable(ar, 171562306a36Sopenharmony_ci ar->pktlog_filter); 171662306a36Sopenharmony_ci if (ret) 171762306a36Sopenharmony_ci /* not serious */ 171862306a36Sopenharmony_ci ath10k_warn(ar, 171962306a36Sopenharmony_ci "failed to enable pktlog filter %x: %d\n", 172062306a36Sopenharmony_ci ar->pktlog_filter, ret); 172162306a36Sopenharmony_ci } else { 172262306a36Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_disable(ar); 172362306a36Sopenharmony_ci if (ret) 172462306a36Sopenharmony_ci /* not serious */ 172562306a36Sopenharmony_ci ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci if (ar->debug.nf_cal_period && 172962306a36Sopenharmony_ci !test_bit(ATH10K_FW_FEATURE_NON_BMI, 173062306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features)) { 173162306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, 173262306a36Sopenharmony_ci ar->wmi.pdev_param->cal_period, 173362306a36Sopenharmony_ci ar->debug.nf_cal_period); 173462306a36Sopenharmony_ci if (ret) 173562306a36Sopenharmony_ci /* not serious */ 173662306a36Sopenharmony_ci ath10k_warn(ar, "cal period cfg failed from debug start: %d\n", 173762306a36Sopenharmony_ci ret); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci return ret; 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_civoid ath10k_debug_stop(struct ath10k *ar) 174462306a36Sopenharmony_ci{ 174562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, 174862306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features)) 174962306a36Sopenharmony_ci ath10k_debug_cal_data_fetch(ar); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci /* Must not use _sync to avoid deadlock, we do that in 175262306a36Sopenharmony_ci * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid 175362306a36Sopenharmony_ci * warning from del_timer(). 175462306a36Sopenharmony_ci */ 175562306a36Sopenharmony_ci if (ar->debug.htt_stats_mask != 0) 175662306a36Sopenharmony_ci cancel_delayed_work(&ar->debug.htt_stats_dwork); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci ath10k_wmi_pdev_pktlog_disable(ar); 175962306a36Sopenharmony_ci} 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_cistatic ssize_t ath10k_write_simulate_radar(struct file *file, 176262306a36Sopenharmony_ci const char __user *user_buf, 176362306a36Sopenharmony_ci size_t count, loff_t *ppos) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 176662306a36Sopenharmony_ci struct ath10k_vif *arvif; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci /* Just check for the first vif alone, as all the vifs will be 176962306a36Sopenharmony_ci * sharing the same channel and if the channel is disabled, all the 177062306a36Sopenharmony_ci * vifs will share the same 'is_started' state. 177162306a36Sopenharmony_ci */ 177262306a36Sopenharmony_ci arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); 177362306a36Sopenharmony_ci if (!arvif->is_started) 177462306a36Sopenharmony_ci return -EINVAL; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci ieee80211_radar_detected(ar->hw); 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci return count; 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic const struct file_operations fops_simulate_radar = { 178262306a36Sopenharmony_ci .write = ath10k_write_simulate_radar, 178362306a36Sopenharmony_ci .open = simple_open, 178462306a36Sopenharmony_ci .owner = THIS_MODULE, 178562306a36Sopenharmony_ci .llseek = default_llseek, 178662306a36Sopenharmony_ci}; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci#define ATH10K_DFS_STAT(s, p) (\ 178962306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ 179062306a36Sopenharmony_ci ar->debug.dfs_stats.p)) 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci#define ATH10K_DFS_POOL_STAT(s, p) (\ 179362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ 179462306a36Sopenharmony_ci ar->debug.dfs_pool_stats.p)) 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_cistatic ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf, 179762306a36Sopenharmony_ci size_t count, loff_t *ppos) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci int retval = 0, len = 0; 180062306a36Sopenharmony_ci const int size = 8000; 180162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 180262306a36Sopenharmony_ci char *buf; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci buf = kzalloc(size, GFP_KERNEL); 180562306a36Sopenharmony_ci if (buf == NULL) 180662306a36Sopenharmony_ci return -ENOMEM; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (!ar->dfs_detector) { 180962306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "DFS not enabled\n"); 181062306a36Sopenharmony_ci goto exit; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci ar->debug.dfs_pool_stats = 181462306a36Sopenharmony_ci ar->dfs_detector->get_stats(ar->dfs_detector); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n"); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci ATH10K_DFS_STAT("reported phy errors", phy_errors); 181962306a36Sopenharmony_ci ATH10K_DFS_STAT("pulse events reported", pulses_total); 182062306a36Sopenharmony_ci ATH10K_DFS_STAT("DFS pulses detected", pulses_detected); 182162306a36Sopenharmony_ci ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded); 182262306a36Sopenharmony_ci ATH10K_DFS_STAT("Radars detected", radar_detected); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "Global Pool statistics:\n"); 182562306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pool references", pool_reference); 182662306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated); 182762306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error); 182862306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used); 182962306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated); 183062306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error); 183162306a36Sopenharmony_ci ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ciexit: 183462306a36Sopenharmony_ci if (len > size) 183562306a36Sopenharmony_ci len = size; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 183862306a36Sopenharmony_ci kfree(buf); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci return retval; 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic const struct file_operations fops_dfs_stats = { 184462306a36Sopenharmony_ci .read = ath10k_read_dfs_stats, 184562306a36Sopenharmony_ci .open = simple_open, 184662306a36Sopenharmony_ci .owner = THIS_MODULE, 184762306a36Sopenharmony_ci .llseek = default_llseek, 184862306a36Sopenharmony_ci}; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_cistatic ssize_t ath10k_write_pktlog_filter(struct file *file, 185162306a36Sopenharmony_ci const char __user *ubuf, 185262306a36Sopenharmony_ci size_t count, loff_t *ppos) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 185562306a36Sopenharmony_ci u32 filter; 185662306a36Sopenharmony_ci int ret; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (kstrtouint_from_user(ubuf, count, 0, &filter)) 185962306a36Sopenharmony_ci return -EINVAL; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 186462306a36Sopenharmony_ci ar->pktlog_filter = filter; 186562306a36Sopenharmony_ci ret = count; 186662306a36Sopenharmony_ci goto out; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (filter == ar->pktlog_filter) { 187062306a36Sopenharmony_ci ret = count; 187162306a36Sopenharmony_ci goto out; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci if (filter) { 187562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_enable(ar, filter); 187662306a36Sopenharmony_ci if (ret) { 187762306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n", 187862306a36Sopenharmony_ci ar->pktlog_filter, ret); 187962306a36Sopenharmony_ci goto out; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci } else { 188262306a36Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_disable(ar); 188362306a36Sopenharmony_ci if (ret) { 188462306a36Sopenharmony_ci ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); 188562306a36Sopenharmony_ci goto out; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci ar->pktlog_filter = filter; 189062306a36Sopenharmony_ci ret = count; 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ciout: 189362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 189462306a36Sopenharmony_ci return ret; 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf, 189862306a36Sopenharmony_ci size_t count, loff_t *ppos) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci char buf[32]; 190162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 190262306a36Sopenharmony_ci int len = 0; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 190562306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%08x\n", 190662306a36Sopenharmony_ci ar->pktlog_filter); 190762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_cistatic const struct file_operations fops_pktlog_filter = { 191362306a36Sopenharmony_ci .read = ath10k_read_pktlog_filter, 191462306a36Sopenharmony_ci .write = ath10k_write_pktlog_filter, 191562306a36Sopenharmony_ci .open = simple_open 191662306a36Sopenharmony_ci}; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic ssize_t ath10k_write_quiet_period(struct file *file, 191962306a36Sopenharmony_ci const char __user *ubuf, 192062306a36Sopenharmony_ci size_t count, loff_t *ppos) 192162306a36Sopenharmony_ci{ 192262306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 192362306a36Sopenharmony_ci u32 period; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci if (kstrtouint_from_user(ubuf, count, 0, &period)) 192662306a36Sopenharmony_ci return -EINVAL; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (period < ATH10K_QUIET_PERIOD_MIN) { 192962306a36Sopenharmony_ci ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n", 193062306a36Sopenharmony_ci period); 193162306a36Sopenharmony_ci return -EINVAL; 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 193462306a36Sopenharmony_ci ar->thermal.quiet_period = period; 193562306a36Sopenharmony_ci ath10k_thermal_set_throttling(ar); 193662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci return count; 193962306a36Sopenharmony_ci} 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_cistatic ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf, 194262306a36Sopenharmony_ci size_t count, loff_t *ppos) 194362306a36Sopenharmony_ci{ 194462306a36Sopenharmony_ci char buf[32]; 194562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 194662306a36Sopenharmony_ci int len = 0; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 194962306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 195062306a36Sopenharmony_ci ar->thermal.quiet_period); 195162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic const struct file_operations fops_quiet_period = { 195762306a36Sopenharmony_ci .read = ath10k_read_quiet_period, 195862306a36Sopenharmony_ci .write = ath10k_write_quiet_period, 195962306a36Sopenharmony_ci .open = simple_open 196062306a36Sopenharmony_ci}; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_cistatic ssize_t ath10k_write_btcoex(struct file *file, 196362306a36Sopenharmony_ci const char __user *ubuf, 196462306a36Sopenharmony_ci size_t count, loff_t *ppos) 196562306a36Sopenharmony_ci{ 196662306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 196762306a36Sopenharmony_ci char buf[32]; 196862306a36Sopenharmony_ci size_t buf_size; 196962306a36Sopenharmony_ci int ret; 197062306a36Sopenharmony_ci bool val; 197162306a36Sopenharmony_ci u32 pdev_param; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci buf_size = min(count, (sizeof(buf) - 1)); 197462306a36Sopenharmony_ci if (copy_from_user(buf, ubuf, buf_size)) 197562306a36Sopenharmony_ci return -EFAULT; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci buf[buf_size] = '\0'; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci if (kstrtobool(buf, &val) != 0) 198062306a36Sopenharmony_ci return -EINVAL; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci if (!ar->coex_support) 198362306a36Sopenharmony_ci return -EOPNOTSUPP; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 198862306a36Sopenharmony_ci ar->state != ATH10K_STATE_RESTARTED) { 198962306a36Sopenharmony_ci ret = -ENETDOWN; 199062306a36Sopenharmony_ci goto exit; 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) { 199462306a36Sopenharmony_ci ret = count; 199562306a36Sopenharmony_ci goto exit; 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci pdev_param = ar->wmi.pdev_param->enable_btcoex; 199962306a36Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, 200062306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 200162306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val); 200262306a36Sopenharmony_ci if (ret) { 200362306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable btcoex: %d\n", ret); 200462306a36Sopenharmony_ci ret = count; 200562306a36Sopenharmony_ci goto exit; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci } else { 200862306a36Sopenharmony_ci ath10k_info(ar, "restarting firmware due to btcoex change"); 200962306a36Sopenharmony_ci ath10k_core_start_recovery(ar); 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci if (val) 201362306a36Sopenharmony_ci set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); 201462306a36Sopenharmony_ci else 201562306a36Sopenharmony_ci clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci ret = count; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ciexit: 202062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci return ret; 202362306a36Sopenharmony_ci} 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_cistatic ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf, 202662306a36Sopenharmony_ci size_t count, loff_t *ppos) 202762306a36Sopenharmony_ci{ 202862306a36Sopenharmony_ci char buf[32]; 202962306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 203062306a36Sopenharmony_ci int len = 0; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 203362306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 203462306a36Sopenharmony_ci test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags)); 203562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 203862306a36Sopenharmony_ci} 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_cistatic const struct file_operations fops_btcoex = { 204162306a36Sopenharmony_ci .read = ath10k_read_btcoex, 204262306a36Sopenharmony_ci .write = ath10k_write_btcoex, 204362306a36Sopenharmony_ci .open = simple_open 204462306a36Sopenharmony_ci}; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_cistatic ssize_t ath10k_write_enable_extd_tx_stats(struct file *file, 204762306a36Sopenharmony_ci const char __user *ubuf, 204862306a36Sopenharmony_ci size_t count, loff_t *ppos) 204962306a36Sopenharmony_ci{ 205062306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 205162306a36Sopenharmony_ci u32 filter; 205262306a36Sopenharmony_ci int ret; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci if (kstrtouint_from_user(ubuf, count, 0, &filter)) 205562306a36Sopenharmony_ci return -EINVAL; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 206062306a36Sopenharmony_ci ar->debug.enable_extd_tx_stats = filter; 206162306a36Sopenharmony_ci ret = count; 206262306a36Sopenharmony_ci goto out; 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci if (filter == ar->debug.enable_extd_tx_stats) { 206662306a36Sopenharmony_ci ret = count; 206762306a36Sopenharmony_ci goto out; 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci ar->debug.enable_extd_tx_stats = filter; 207162306a36Sopenharmony_ci ret = count; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ciout: 207462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 207562306a36Sopenharmony_ci return ret; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic ssize_t ath10k_read_enable_extd_tx_stats(struct file *file, 207962306a36Sopenharmony_ci char __user *ubuf, 208062306a36Sopenharmony_ci size_t count, loff_t *ppos) 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci{ 208362306a36Sopenharmony_ci char buf[32]; 208462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 208562306a36Sopenharmony_ci int len = 0; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 208862306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%08x\n", 208962306a36Sopenharmony_ci ar->debug.enable_extd_tx_stats); 209062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_cistatic const struct file_operations fops_enable_extd_tx_stats = { 209662306a36Sopenharmony_ci .read = ath10k_read_enable_extd_tx_stats, 209762306a36Sopenharmony_ci .write = ath10k_write_enable_extd_tx_stats, 209862306a36Sopenharmony_ci .open = simple_open 209962306a36Sopenharmony_ci}; 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_cistatic ssize_t ath10k_write_peer_stats(struct file *file, 210262306a36Sopenharmony_ci const char __user *ubuf, 210362306a36Sopenharmony_ci size_t count, loff_t *ppos) 210462306a36Sopenharmony_ci{ 210562306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 210662306a36Sopenharmony_ci char buf[32]; 210762306a36Sopenharmony_ci size_t buf_size; 210862306a36Sopenharmony_ci int ret; 210962306a36Sopenharmony_ci bool val; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci buf_size = min(count, (sizeof(buf) - 1)); 211262306a36Sopenharmony_ci if (copy_from_user(buf, ubuf, buf_size)) 211362306a36Sopenharmony_ci return -EFAULT; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci buf[buf_size] = '\0'; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci if (kstrtobool(buf, &val) != 0) 211862306a36Sopenharmony_ci return -EINVAL; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 212362306a36Sopenharmony_ci ar->state != ATH10K_STATE_RESTARTED) { 212462306a36Sopenharmony_ci ret = -ENETDOWN; 212562306a36Sopenharmony_ci goto exit; 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) { 212962306a36Sopenharmony_ci ret = count; 213062306a36Sopenharmony_ci goto exit; 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci if (val) 213462306a36Sopenharmony_ci set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags); 213562306a36Sopenharmony_ci else 213662306a36Sopenharmony_ci clear_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags); 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci ath10k_info(ar, "restarting firmware due to Peer stats change"); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci ath10k_core_start_recovery(ar); 214162306a36Sopenharmony_ci ret = count; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ciexit: 214462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 214562306a36Sopenharmony_ci return ret; 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_cistatic ssize_t ath10k_read_peer_stats(struct file *file, char __user *ubuf, 214962306a36Sopenharmony_ci size_t count, loff_t *ppos) 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci char buf[32]; 215362306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 215462306a36Sopenharmony_ci int len = 0; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 215762306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 215862306a36Sopenharmony_ci test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags)); 215962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 216262306a36Sopenharmony_ci} 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_cistatic const struct file_operations fops_peer_stats = { 216562306a36Sopenharmony_ci .read = ath10k_read_peer_stats, 216662306a36Sopenharmony_ci .write = ath10k_write_peer_stats, 216762306a36Sopenharmony_ci .open = simple_open 216862306a36Sopenharmony_ci}; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_cistatic ssize_t ath10k_debug_fw_checksums_read(struct file *file, 217162306a36Sopenharmony_ci char __user *user_buf, 217262306a36Sopenharmony_ci size_t count, loff_t *ppos) 217362306a36Sopenharmony_ci{ 217462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 217562306a36Sopenharmony_ci size_t len = 0, buf_len = 4096; 217662306a36Sopenharmony_ci ssize_t ret_cnt; 217762306a36Sopenharmony_ci char *buf; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 218062306a36Sopenharmony_ci if (!buf) 218162306a36Sopenharmony_ci return -ENOMEM; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 218662306a36Sopenharmony_ci "firmware-N.bin\t\t%08x\n", 218762306a36Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data, 218862306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.firmware->size)); 218962306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 219062306a36Sopenharmony_ci "athwlan\t\t\t%08x\n", 219162306a36Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data, 219262306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.firmware_len)); 219362306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 219462306a36Sopenharmony_ci "otp\t\t\t%08x\n", 219562306a36Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.otp_data, 219662306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.otp_len)); 219762306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 219862306a36Sopenharmony_ci "codeswap\t\t%08x\n", 219962306a36Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data, 220062306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.codeswap_len)); 220162306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 220262306a36Sopenharmony_ci "board-N.bin\t\t%08x\n", 220362306a36Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.board->data, 220462306a36Sopenharmony_ci ar->normal_mode_fw.board->size)); 220562306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 220662306a36Sopenharmony_ci "board\t\t\t%08x\n", 220762306a36Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.board_data, 220862306a36Sopenharmony_ci ar->normal_mode_fw.board_len)); 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci kfree(buf); 221562306a36Sopenharmony_ci return ret_cnt; 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_cistatic const struct file_operations fops_fw_checksums = { 221962306a36Sopenharmony_ci .read = ath10k_debug_fw_checksums_read, 222062306a36Sopenharmony_ci .open = simple_open, 222162306a36Sopenharmony_ci .owner = THIS_MODULE, 222262306a36Sopenharmony_ci .llseek = default_llseek, 222362306a36Sopenharmony_ci}; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_cistatic ssize_t ath10k_sta_tid_stats_mask_read(struct file *file, 222662306a36Sopenharmony_ci char __user *user_buf, 222762306a36Sopenharmony_ci size_t count, loff_t *ppos) 222862306a36Sopenharmony_ci{ 222962306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 223062306a36Sopenharmony_ci char buf[32]; 223162306a36Sopenharmony_ci size_t len; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask); 223462306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 223562306a36Sopenharmony_ci} 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_cistatic ssize_t ath10k_sta_tid_stats_mask_write(struct file *file, 223862306a36Sopenharmony_ci const char __user *user_buf, 223962306a36Sopenharmony_ci size_t count, loff_t *ppos) 224062306a36Sopenharmony_ci{ 224162306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 224262306a36Sopenharmony_ci char buf[32]; 224362306a36Sopenharmony_ci ssize_t len; 224462306a36Sopenharmony_ci u32 mask; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci len = min(count, sizeof(buf) - 1); 224762306a36Sopenharmony_ci if (copy_from_user(buf, user_buf, len)) 224862306a36Sopenharmony_ci return -EFAULT; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci buf[len] = '\0'; 225162306a36Sopenharmony_ci if (kstrtoint(buf, 0, &mask)) 225262306a36Sopenharmony_ci return -EINVAL; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci ar->sta_tid_stats_mask = mask; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci return len; 225762306a36Sopenharmony_ci} 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_cistatic const struct file_operations fops_sta_tid_stats_mask = { 226062306a36Sopenharmony_ci .read = ath10k_sta_tid_stats_mask_read, 226162306a36Sopenharmony_ci .write = ath10k_sta_tid_stats_mask_write, 226262306a36Sopenharmony_ci .open = simple_open, 226362306a36Sopenharmony_ci .owner = THIS_MODULE, 226462306a36Sopenharmony_ci .llseek = default_llseek, 226562306a36Sopenharmony_ci}; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_cistatic int ath10k_debug_tpc_stats_final_request(struct ath10k *ar) 226862306a36Sopenharmony_ci{ 226962306a36Sopenharmony_ci int ret; 227062306a36Sopenharmony_ci unsigned long time_left; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci reinit_completion(&ar->debug.tpc_complete); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM); 227762306a36Sopenharmony_ci if (ret) { 227862306a36Sopenharmony_ci ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret); 227962306a36Sopenharmony_ci return ret; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->debug.tpc_complete, 228362306a36Sopenharmony_ci 1 * HZ); 228462306a36Sopenharmony_ci if (time_left == 0) 228562306a36Sopenharmony_ci return -ETIMEDOUT; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci return 0; 228862306a36Sopenharmony_ci} 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_cistatic int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci struct ath10k *ar = inode->i_private; 229362306a36Sopenharmony_ci void *buf; 229462306a36Sopenharmony_ci int ret; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 229962306a36Sopenharmony_ci ret = -ENETDOWN; 230062306a36Sopenharmony_ci goto err_unlock; 230162306a36Sopenharmony_ci } 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE); 230462306a36Sopenharmony_ci if (!buf) { 230562306a36Sopenharmony_ci ret = -ENOMEM; 230662306a36Sopenharmony_ci goto err_unlock; 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci ret = ath10k_debug_tpc_stats_final_request(ar); 231062306a36Sopenharmony_ci if (ret) { 231162306a36Sopenharmony_ci ath10k_warn(ar, "failed to request tpc stats final: %d\n", 231262306a36Sopenharmony_ci ret); 231362306a36Sopenharmony_ci goto err_free; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf); 231762306a36Sopenharmony_ci file->private_data = buf; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 232062306a36Sopenharmony_ci return 0; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_cierr_free: 232362306a36Sopenharmony_ci vfree(buf); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_cierr_unlock: 232662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 232762306a36Sopenharmony_ci return ret; 232862306a36Sopenharmony_ci} 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_cistatic int ath10k_tpc_stats_final_release(struct inode *inode, 233162306a36Sopenharmony_ci struct file *file) 233262306a36Sopenharmony_ci{ 233362306a36Sopenharmony_ci vfree(file->private_data); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci return 0; 233662306a36Sopenharmony_ci} 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_cistatic ssize_t ath10k_tpc_stats_final_read(struct file *file, 233962306a36Sopenharmony_ci char __user *user_buf, 234062306a36Sopenharmony_ci size_t count, loff_t *ppos) 234162306a36Sopenharmony_ci{ 234262306a36Sopenharmony_ci const char *buf = file->private_data; 234362306a36Sopenharmony_ci unsigned int len = strlen(buf); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 234662306a36Sopenharmony_ci} 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_cistatic const struct file_operations fops_tpc_stats_final = { 234962306a36Sopenharmony_ci .open = ath10k_tpc_stats_final_open, 235062306a36Sopenharmony_ci .release = ath10k_tpc_stats_final_release, 235162306a36Sopenharmony_ci .read = ath10k_tpc_stats_final_read, 235262306a36Sopenharmony_ci .owner = THIS_MODULE, 235362306a36Sopenharmony_ci .llseek = default_llseek, 235462306a36Sopenharmony_ci}; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_cistatic ssize_t ath10k_write_warm_hw_reset(struct file *file, 235762306a36Sopenharmony_ci const char __user *user_buf, 235862306a36Sopenharmony_ci size_t count, loff_t *ppos) 235962306a36Sopenharmony_ci{ 236062306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 236162306a36Sopenharmony_ci int ret; 236262306a36Sopenharmony_ci bool val; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci if (kstrtobool_from_user(user_buf, count, &val)) 236562306a36Sopenharmony_ci return -EFAULT; 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci if (!val) 236862306a36Sopenharmony_ci return -EINVAL; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 237362306a36Sopenharmony_ci ret = -ENETDOWN; 237462306a36Sopenharmony_ci goto exit; 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pdev_reset, 237862306a36Sopenharmony_ci WMI_RST_MODE_WARM_RESET); 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci if (ret) { 238162306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable warm hw reset: %d\n", ret); 238262306a36Sopenharmony_ci goto exit; 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci ret = count; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ciexit: 238862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 238962306a36Sopenharmony_ci return ret; 239062306a36Sopenharmony_ci} 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_cistatic const struct file_operations fops_warm_hw_reset = { 239362306a36Sopenharmony_ci .write = ath10k_write_warm_hw_reset, 239462306a36Sopenharmony_ci .open = simple_open, 239562306a36Sopenharmony_ci .owner = THIS_MODULE, 239662306a36Sopenharmony_ci .llseek = default_llseek, 239762306a36Sopenharmony_ci}; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_cistatic void ath10k_peer_ps_state_disable(void *data, 240062306a36Sopenharmony_ci struct ieee80211_sta *sta) 240162306a36Sopenharmony_ci{ 240262306a36Sopenharmony_ci struct ath10k *ar = data; 240362306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 240662306a36Sopenharmony_ci arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; 240762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 240862306a36Sopenharmony_ci} 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_cistatic ssize_t ath10k_write_ps_state_enable(struct file *file, 241162306a36Sopenharmony_ci const char __user *user_buf, 241262306a36Sopenharmony_ci size_t count, loff_t *ppos) 241362306a36Sopenharmony_ci{ 241462306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 241562306a36Sopenharmony_ci int ret; 241662306a36Sopenharmony_ci u32 param; 241762306a36Sopenharmony_ci u8 ps_state_enable; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable)) 242062306a36Sopenharmony_ci return -EINVAL; 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci if (ps_state_enable > 1) 242362306a36Sopenharmony_ci return -EINVAL; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci if (ar->ps_state_enable == ps_state_enable) { 242862306a36Sopenharmony_ci ret = count; 242962306a36Sopenharmony_ci goto exit; 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable; 243362306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable); 243462306a36Sopenharmony_ci if (ret) { 243562306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable ps_state_enable: %d\n", 243662306a36Sopenharmony_ci ret); 243762306a36Sopenharmony_ci goto exit; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci ar->ps_state_enable = ps_state_enable; 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (!ar->ps_state_enable) 244262306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 244362306a36Sopenharmony_ci ath10k_peer_ps_state_disable, 244462306a36Sopenharmony_ci ar); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci ret = count; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ciexit: 244962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci return ret; 245262306a36Sopenharmony_ci} 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_cistatic ssize_t ath10k_read_ps_state_enable(struct file *file, 245562306a36Sopenharmony_ci char __user *user_buf, 245662306a36Sopenharmony_ci size_t count, loff_t *ppos) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 245962306a36Sopenharmony_ci int len = 0; 246062306a36Sopenharmony_ci char buf[32]; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 246362306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 246462306a36Sopenharmony_ci ar->ps_state_enable); 246562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 246862306a36Sopenharmony_ci} 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_cistatic const struct file_operations fops_ps_state_enable = { 247162306a36Sopenharmony_ci .read = ath10k_read_ps_state_enable, 247262306a36Sopenharmony_ci .write = ath10k_write_ps_state_enable, 247362306a36Sopenharmony_ci .open = simple_open, 247462306a36Sopenharmony_ci .owner = THIS_MODULE, 247562306a36Sopenharmony_ci .llseek = default_llseek, 247662306a36Sopenharmony_ci}; 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_cistatic ssize_t ath10k_write_reset_htt_stats(struct file *file, 247962306a36Sopenharmony_ci const char __user *user_buf, 248062306a36Sopenharmony_ci size_t count, loff_t *ppos) 248162306a36Sopenharmony_ci{ 248262306a36Sopenharmony_ci struct ath10k *ar = file->private_data; 248362306a36Sopenharmony_ci unsigned long reset; 248462306a36Sopenharmony_ci int ret; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci ret = kstrtoul_from_user(user_buf, count, 0, &reset); 248762306a36Sopenharmony_ci if (ret) 248862306a36Sopenharmony_ci return ret; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci if (reset == 0 || reset > 0x1ffff) 249162306a36Sopenharmony_ci return -EINVAL; 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci ar->debug.reset_htt_stats = reset; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci ret = ath10k_debug_htt_stats_req(ar); 249862306a36Sopenharmony_ci if (ret) 249962306a36Sopenharmony_ci goto out; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci ar->debug.reset_htt_stats = 0; 250262306a36Sopenharmony_ci ret = count; 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ciout: 250562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 250662306a36Sopenharmony_ci return ret; 250762306a36Sopenharmony_ci} 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_cistatic const struct file_operations fops_reset_htt_stats = { 251062306a36Sopenharmony_ci .write = ath10k_write_reset_htt_stats, 251162306a36Sopenharmony_ci .owner = THIS_MODULE, 251262306a36Sopenharmony_ci .open = simple_open, 251362306a36Sopenharmony_ci .llseek = default_llseek, 251462306a36Sopenharmony_ci}; 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ciint ath10k_debug_create(struct ath10k *ar) 251762306a36Sopenharmony_ci{ 251862306a36Sopenharmony_ci ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); 251962306a36Sopenharmony_ci if (!ar->debug.cal_data) 252062306a36Sopenharmony_ci return -ENOMEM; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); 252362306a36Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); 252462306a36Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.peers); 252562306a36Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci return 0; 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_civoid ath10k_debug_destroy(struct ath10k *ar) 253162306a36Sopenharmony_ci{ 253262306a36Sopenharmony_ci vfree(ar->debug.cal_data); 253362306a36Sopenharmony_ci ar->debug.cal_data = NULL; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci ath10k_debug_fw_stats_reset(ar); 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci kfree(ar->debug.tpc_stats); 253862306a36Sopenharmony_ci kfree(ar->debug.tpc_stats_final); 253962306a36Sopenharmony_ci} 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ciint ath10k_debug_register(struct ath10k *ar) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci ar->debug.debugfs_phy = debugfs_create_dir("ath10k", 254462306a36Sopenharmony_ci ar->hw->wiphy->debugfsdir); 254562306a36Sopenharmony_ci if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) { 254662306a36Sopenharmony_ci if (IS_ERR(ar->debug.debugfs_phy)) 254762306a36Sopenharmony_ci return PTR_ERR(ar->debug.debugfs_phy); 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci return -ENOMEM; 255062306a36Sopenharmony_ci } 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, 255362306a36Sopenharmony_ci ath10k_debug_htt_stats_dwork); 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci init_completion(&ar->debug.tpc_complete); 255662306a36Sopenharmony_ci init_completion(&ar->debug.fw_stats_complete); 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar, 255962306a36Sopenharmony_ci &fops_fw_stats); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci debugfs_create_file("fw_reset_stats", 0400, ar->debug.debugfs_phy, ar, 256262306a36Sopenharmony_ci &fops_fw_reset_stats); 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar, 256562306a36Sopenharmony_ci &fops_wmi_services); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar, 256862306a36Sopenharmony_ci &fops_simulate_fw_crash); 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar, 257162306a36Sopenharmony_ci &fops_reg_addr); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci debugfs_create_file("reg_value", 0600, ar->debug.debugfs_phy, ar, 257462306a36Sopenharmony_ci &fops_reg_value); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci debugfs_create_file("mem_value", 0600, ar->debug.debugfs_phy, ar, 257762306a36Sopenharmony_ci &fops_mem_value); 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci debugfs_create_file("chip_id", 0400, ar->debug.debugfs_phy, ar, 258062306a36Sopenharmony_ci &fops_chip_id); 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci debugfs_create_file("htt_stats_mask", 0600, ar->debug.debugfs_phy, ar, 258362306a36Sopenharmony_ci &fops_htt_stats_mask); 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci debugfs_create_file("htt_max_amsdu_ampdu", 0600, ar->debug.debugfs_phy, ar, 258662306a36Sopenharmony_ci &fops_htt_max_amsdu_ampdu); 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar, 258962306a36Sopenharmony_ci &fops_fw_dbglog); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, 259262306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features)) { 259362306a36Sopenharmony_ci debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, 259462306a36Sopenharmony_ci &fops_cal_data); 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, 259762306a36Sopenharmony_ci &fops_nf_cal_period); 259862306a36Sopenharmony_ci } 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar, 260162306a36Sopenharmony_ci &fops_ani_enable); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { 260462306a36Sopenharmony_ci debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy, 260562306a36Sopenharmony_ci ar, &fops_simulate_radar); 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci debugfs_create_bool("dfs_block_radar_events", 0200, 260862306a36Sopenharmony_ci ar->debug.debugfs_phy, 260962306a36Sopenharmony_ci &ar->dfs_block_radar_events); 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci debugfs_create_file("dfs_stats", 0400, ar->debug.debugfs_phy, ar, 261262306a36Sopenharmony_ci &fops_dfs_stats); 261362306a36Sopenharmony_ci } 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar, 261662306a36Sopenharmony_ci &fops_pktlog_filter); 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map)) 261962306a36Sopenharmony_ci debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar, 262062306a36Sopenharmony_ci &fops_quiet_period); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar, 262362306a36Sopenharmony_ci &fops_tpc_stats); 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map)) 262662306a36Sopenharmony_ci debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar, 262762306a36Sopenharmony_ci &fops_btcoex); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { 263062306a36Sopenharmony_ci debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar, 263162306a36Sopenharmony_ci &fops_peer_stats); 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci debugfs_create_file("enable_extd_tx_stats", 0644, 263462306a36Sopenharmony_ci ar->debug.debugfs_phy, ar, 263562306a36Sopenharmony_ci &fops_enable_extd_tx_stats); 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar, 263962306a36Sopenharmony_ci &fops_fw_checksums); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS)) 264262306a36Sopenharmony_ci debugfs_create_file("sta_tid_stats_mask", 0600, 264362306a36Sopenharmony_ci ar->debug.debugfs_phy, 264462306a36Sopenharmony_ci ar, &fops_sta_tid_stats_mask); 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map)) 264762306a36Sopenharmony_ci debugfs_create_file("tpc_stats_final", 0400, 264862306a36Sopenharmony_ci ar->debug.debugfs_phy, ar, 264962306a36Sopenharmony_ci &fops_tpc_stats_final); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_RESET_CHIP, ar->wmi.svc_map)) 265262306a36Sopenharmony_ci debugfs_create_file("warm_hw_reset", 0600, 265362306a36Sopenharmony_ci ar->debug.debugfs_phy, ar, 265462306a36Sopenharmony_ci &fops_warm_hw_reset); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar, 265762306a36Sopenharmony_ci &fops_ps_state_enable); 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar, 266062306a36Sopenharmony_ci &fops_reset_htt_stats); 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci return 0; 266362306a36Sopenharmony_ci} 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_civoid ath10k_debug_unregister(struct ath10k *ar) 266662306a36Sopenharmony_ci{ 266762306a36Sopenharmony_ci cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); 266862306a36Sopenharmony_ci} 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci#endif /* CONFIG_ATH10K_DEBUGFS */ 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci#ifdef CONFIG_ATH10K_DEBUG 267362306a36Sopenharmony_civoid __ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask, 267462306a36Sopenharmony_ci const char *fmt, ...) 267562306a36Sopenharmony_ci{ 267662306a36Sopenharmony_ci struct va_format vaf; 267762306a36Sopenharmony_ci va_list args; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci va_start(args, fmt); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci vaf.fmt = fmt; 268262306a36Sopenharmony_ci vaf.va = &args; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci if (ath10k_debug_mask & mask) 268562306a36Sopenharmony_ci dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci trace_ath10k_log_dbg(ar, mask, &vaf); 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci va_end(args); 269062306a36Sopenharmony_ci} 269162306a36Sopenharmony_ciEXPORT_SYMBOL(__ath10k_dbg); 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_civoid ath10k_dbg_dump(struct ath10k *ar, 269462306a36Sopenharmony_ci enum ath10k_debug_mask mask, 269562306a36Sopenharmony_ci const char *msg, const char *prefix, 269662306a36Sopenharmony_ci const void *buf, size_t len) 269762306a36Sopenharmony_ci{ 269862306a36Sopenharmony_ci char linebuf[256]; 269962306a36Sopenharmony_ci size_t linebuflen; 270062306a36Sopenharmony_ci const void *ptr; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci if (ath10k_debug_mask & mask) { 270362306a36Sopenharmony_ci if (msg) 270462306a36Sopenharmony_ci __ath10k_dbg(ar, mask, "%s\n", msg); 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci for (ptr = buf; (ptr - buf) < len; ptr += 16) { 270762306a36Sopenharmony_ci linebuflen = 0; 270862306a36Sopenharmony_ci linebuflen += scnprintf(linebuf + linebuflen, 270962306a36Sopenharmony_ci sizeof(linebuf) - linebuflen, 271062306a36Sopenharmony_ci "%s%08x: ", 271162306a36Sopenharmony_ci (prefix ? prefix : ""), 271262306a36Sopenharmony_ci (unsigned int)(ptr - buf)); 271362306a36Sopenharmony_ci hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1, 271462306a36Sopenharmony_ci linebuf + linebuflen, 271562306a36Sopenharmony_ci sizeof(linebuf) - linebuflen, true); 271662306a36Sopenharmony_ci dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf); 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci } 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci /* tracing code doesn't like null strings :/ */ 272162306a36Sopenharmony_ci trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "", 272262306a36Sopenharmony_ci buf, len); 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ciEXPORT_SYMBOL(ath10k_dbg_dump); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci#endif /* CONFIG_ATH10K_DEBUG */ 2727