18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2005-2011 Atheros Communications Inc. 48c2ecf20Sopenharmony_ci * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. 58c2ecf20Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 118c2ecf20Sopenharmony_ci#include <linux/crc32.h> 128c2ecf20Sopenharmony_ci#include <linux/firmware.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "core.h" 158c2ecf20Sopenharmony_ci#include "debug.h" 168c2ecf20Sopenharmony_ci#include "hif.h" 178c2ecf20Sopenharmony_ci#include "wmi-ops.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* ms */ 208c2ecf20Sopenharmony_ci#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define ATH10K_DEBUG_CAL_DATA_LEN 12064 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_civoid ath10k_info(struct ath10k *ar, const char *fmt, ...) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct va_format vaf = { 278c2ecf20Sopenharmony_ci .fmt = fmt, 288c2ecf20Sopenharmony_ci }; 298c2ecf20Sopenharmony_ci va_list args; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci va_start(args, fmt); 328c2ecf20Sopenharmony_ci vaf.va = &args; 338c2ecf20Sopenharmony_ci dev_info(ar->dev, "%pV", &vaf); 348c2ecf20Sopenharmony_ci trace_ath10k_log_info(ar, &vaf); 358c2ecf20Sopenharmony_ci va_end(args); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath10k_info); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid ath10k_debug_print_hwfw_info(struct ath10k *ar) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci const struct firmware *firmware; 428c2ecf20Sopenharmony_ci char fw_features[128] = {}; 438c2ecf20Sopenharmony_ci u32 crc = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x", 488c2ecf20Sopenharmony_ci ar->hw_params.name, 498c2ecf20Sopenharmony_ci ar->target_version, 508c2ecf20Sopenharmony_ci ar->bus_param.chip_id, 518c2ecf20Sopenharmony_ci ar->id.subsystem_vendor, ar->id.subsystem_device); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n", 548c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_DEBUG), 558c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_DEBUGFS), 568c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_TRACING), 578c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED), 588c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_NL80211_TESTMODE)); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci firmware = ar->normal_mode_fw.fw_file.firmware; 618c2ecf20Sopenharmony_ci if (firmware) 628c2ecf20Sopenharmony_ci crc = crc32_le(0, firmware->data, firmware->size); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n", 658c2ecf20Sopenharmony_ci ar->hw->wiphy->fw_version, 668c2ecf20Sopenharmony_ci ar->fw_api, 678c2ecf20Sopenharmony_ci fw_features, 688c2ecf20Sopenharmony_ci crc); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid ath10k_debug_print_board_info(struct ath10k *ar) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci char boardinfo[100]; 748c2ecf20Sopenharmony_ci const struct firmware *board; 758c2ecf20Sopenharmony_ci u32 crc; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (ar->id.bmi_ids_valid) 788c2ecf20Sopenharmony_ci scnprintf(boardinfo, sizeof(boardinfo), "%d:%d", 798c2ecf20Sopenharmony_ci ar->id.bmi_chip_id, ar->id.bmi_board_id); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci scnprintf(boardinfo, sizeof(boardinfo), "N/A"); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci board = ar->normal_mode_fw.board; 848c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(board)) 858c2ecf20Sopenharmony_ci crc = crc32_le(0, board->data, board->size); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci crc = 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x", 908c2ecf20Sopenharmony_ci ar->bd_api, 918c2ecf20Sopenharmony_ci boardinfo, 928c2ecf20Sopenharmony_ci crc); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_civoid ath10k_debug_print_boot_info(struct ath10k *ar) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n", 988c2ecf20Sopenharmony_ci ar->htt.target_version_major, 998c2ecf20Sopenharmony_ci ar->htt.target_version_minor, 1008c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.wmi_op_version, 1018c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.htt_op_version, 1028c2ecf20Sopenharmony_ci ath10k_cal_mode_str(ar->cal_mode), 1038c2ecf20Sopenharmony_ci ar->max_num_stations, 1048c2ecf20Sopenharmony_ci test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), 1058c2ecf20Sopenharmony_ci !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags)); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_civoid ath10k_print_driver_info(struct ath10k *ar) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci ath10k_debug_print_hwfw_info(ar); 1118c2ecf20Sopenharmony_ci ath10k_debug_print_board_info(ar); 1128c2ecf20Sopenharmony_ci ath10k_debug_print_boot_info(ar); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath10k_print_driver_info); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid ath10k_err(struct ath10k *ar, const char *fmt, ...) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct va_format vaf = { 1198c2ecf20Sopenharmony_ci .fmt = fmt, 1208c2ecf20Sopenharmony_ci }; 1218c2ecf20Sopenharmony_ci va_list args; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci va_start(args, fmt); 1248c2ecf20Sopenharmony_ci vaf.va = &args; 1258c2ecf20Sopenharmony_ci dev_err(ar->dev, "%pV", &vaf); 1268c2ecf20Sopenharmony_ci trace_ath10k_log_err(ar, &vaf); 1278c2ecf20Sopenharmony_ci va_end(args); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath10k_err); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid ath10k_warn(struct ath10k *ar, const char *fmt, ...) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct va_format vaf = { 1348c2ecf20Sopenharmony_ci .fmt = fmt, 1358c2ecf20Sopenharmony_ci }; 1368c2ecf20Sopenharmony_ci va_list args; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci va_start(args, fmt); 1398c2ecf20Sopenharmony_ci vaf.va = &args; 1408c2ecf20Sopenharmony_ci dev_warn_ratelimited(ar->dev, "%pV", &vaf); 1418c2ecf20Sopenharmony_ci trace_ath10k_log_warn(ar, &vaf); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci va_end(args); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath10k_warn); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH10K_DEBUGFS 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_wmi_services(struct file *file, 1508c2ecf20Sopenharmony_ci char __user *user_buf, 1518c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 1548c2ecf20Sopenharmony_ci char *buf; 1558c2ecf20Sopenharmony_ci size_t len = 0, buf_len = 8192; 1568c2ecf20Sopenharmony_ci const char *name; 1578c2ecf20Sopenharmony_ci ssize_t ret_cnt; 1588c2ecf20Sopenharmony_ci bool enabled; 1598c2ecf20Sopenharmony_ci int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 1628c2ecf20Sopenharmony_ci if (!buf) 1638c2ecf20Sopenharmony_ci return -ENOMEM; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 1688c2ecf20Sopenharmony_ci for (i = 0; i < WMI_SERVICE_MAX; i++) { 1698c2ecf20Sopenharmony_ci enabled = test_bit(i, ar->wmi.svc_map); 1708c2ecf20Sopenharmony_ci name = wmi_service_name(i); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (!name) { 1738c2ecf20Sopenharmony_ci if (enabled) 1748c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 1758c2ecf20Sopenharmony_ci "%-40s %s (bit %d)\n", 1768c2ecf20Sopenharmony_ci "unknown", "enabled", i); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci continue; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 1828c2ecf20Sopenharmony_ci "%-40s %s\n", 1838c2ecf20Sopenharmony_ci name, enabled ? "enabled" : "-"); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci kfree(buf); 1928c2ecf20Sopenharmony_ci return ret_cnt; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const struct file_operations fops_wmi_services = { 1968c2ecf20Sopenharmony_ci .read = ath10k_read_wmi_services, 1978c2ecf20Sopenharmony_ci .open = simple_open, 1988c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1998c2ecf20Sopenharmony_ci .llseek = default_llseek, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void ath10k_fw_stats_pdevs_free(struct list_head *head) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct ath10k_fw_stats_pdev *i, *tmp; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 2078c2ecf20Sopenharmony_ci list_del(&i->list); 2088c2ecf20Sopenharmony_ci kfree(i); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void ath10k_fw_stats_vdevs_free(struct list_head *head) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct ath10k_fw_stats_vdev *i, *tmp; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 2178c2ecf20Sopenharmony_ci list_del(&i->list); 2188c2ecf20Sopenharmony_ci kfree(i); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void ath10k_fw_stats_peers_free(struct list_head *head) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct ath10k_fw_stats_peer *i, *tmp; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 2278c2ecf20Sopenharmony_ci list_del(&i->list); 2288c2ecf20Sopenharmony_ci kfree(i); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void ath10k_fw_extd_stats_peers_free(struct list_head *head) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct ath10k_fw_extd_stats_peer *i, *tmp; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci list_for_each_entry_safe(i, tmp, head, list) { 2378c2ecf20Sopenharmony_ci list_del(&i->list); 2388c2ecf20Sopenharmony_ci kfree(i); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void ath10k_debug_fw_stats_reset(struct ath10k *ar) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 2458c2ecf20Sopenharmony_ci ar->debug.fw_stats_done = false; 2468c2ecf20Sopenharmony_ci ar->debug.fw_stats.extended = false; 2478c2ecf20Sopenharmony_ci ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); 2488c2ecf20Sopenharmony_ci ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); 2498c2ecf20Sopenharmony_ci ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); 2508c2ecf20Sopenharmony_ci ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd); 2518c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct ath10k_fw_stats stats = {}; 2578c2ecf20Sopenharmony_ci bool is_start, is_started, is_end; 2588c2ecf20Sopenharmony_ci size_t num_peers; 2598c2ecf20Sopenharmony_ci size_t num_vdevs; 2608c2ecf20Sopenharmony_ci int ret; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&stats.pdevs); 2638c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&stats.vdevs); 2648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&stats.peers); 2658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&stats.peers_extd); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 2688c2ecf20Sopenharmony_ci ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); 2698c2ecf20Sopenharmony_ci if (ret) { 2708c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to pull fw stats: %d\n", ret); 2718c2ecf20Sopenharmony_ci goto free; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* Stat data may exceed htc-wmi buffer limit. In such case firmware 2758c2ecf20Sopenharmony_ci * splits the stats data and delivers it in a ping-pong fashion of 2768c2ecf20Sopenharmony_ci * request cmd-update event. 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * However there is no explicit end-of-data. Instead start-of-data is 2798c2ecf20Sopenharmony_ci * used as an implicit one. This works as follows: 2808c2ecf20Sopenharmony_ci * a) discard stat update events until one with pdev stats is 2818c2ecf20Sopenharmony_ci * delivered - this skips session started at end of (b) 2828c2ecf20Sopenharmony_ci * b) consume stat update events until another one with pdev stats is 2838c2ecf20Sopenharmony_ci * delivered which is treated as end-of-data and is itself discarded 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci if (ath10k_peer_stats_enabled(ar)) 2868c2ecf20Sopenharmony_ci ath10k_sta_update_rx_duration(ar, &stats); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (ar->debug.fw_stats_done) { 2898c2ecf20Sopenharmony_ci if (!ath10k_peer_stats_enabled(ar)) 2908c2ecf20Sopenharmony_ci ath10k_warn(ar, "received unsolicited stats update event\n"); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci goto free; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers); 2968c2ecf20Sopenharmony_ci num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); 2978c2ecf20Sopenharmony_ci is_start = (list_empty(&ar->debug.fw_stats.pdevs) && 2988c2ecf20Sopenharmony_ci !list_empty(&stats.pdevs)); 2998c2ecf20Sopenharmony_ci is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && 3008c2ecf20Sopenharmony_ci !list_empty(&stats.pdevs)); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (is_start) 3038c2ecf20Sopenharmony_ci list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (is_end) 3068c2ecf20Sopenharmony_ci ar->debug.fw_stats_done = true; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (stats.extended) 3098c2ecf20Sopenharmony_ci ar->debug.fw_stats.extended = true; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci is_started = !list_empty(&ar->debug.fw_stats.pdevs); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (is_started && !is_end) { 3148c2ecf20Sopenharmony_ci if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) { 3158c2ecf20Sopenharmony_ci /* Although this is unlikely impose a sane limit to 3168c2ecf20Sopenharmony_ci * prevent firmware from DoS-ing the host. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers); 3198c2ecf20Sopenharmony_ci ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd); 3208c2ecf20Sopenharmony_ci ath10k_warn(ar, "dropping fw peer stats\n"); 3218c2ecf20Sopenharmony_ci goto free; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (num_vdevs >= BITS_PER_LONG) { 3258c2ecf20Sopenharmony_ci ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs); 3268c2ecf20Sopenharmony_ci ath10k_warn(ar, "dropping fw vdev stats\n"); 3278c2ecf20Sopenharmony_ci goto free; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (!list_empty(&stats.peers)) 3318c2ecf20Sopenharmony_ci list_splice_tail_init(&stats.peers_extd, 3328c2ecf20Sopenharmony_ci &ar->debug.fw_stats.peers_extd); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); 3358c2ecf20Sopenharmony_ci list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci complete(&ar->debug.fw_stats_complete); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cifree: 3418c2ecf20Sopenharmony_ci /* In some cases lists have been spliced and cleared. Free up 3428c2ecf20Sopenharmony_ci * resources if that is not the case. 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ci ath10k_fw_stats_pdevs_free(&stats.pdevs); 3458c2ecf20Sopenharmony_ci ath10k_fw_stats_vdevs_free(&stats.vdevs); 3468c2ecf20Sopenharmony_ci ath10k_fw_stats_peers_free(&stats.peers); 3478c2ecf20Sopenharmony_ci ath10k_fw_extd_stats_peers_free(&stats.peers_extd); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciint ath10k_debug_fw_stats_request(struct ath10k *ar) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci unsigned long timeout, time_left; 3558c2ecf20Sopenharmony_ci int ret; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(1 * HZ); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ath10k_debug_fw_stats_reset(ar); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci for (;;) { 3648c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 3658c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci reinit_completion(&ar->debug.fw_stats_complete); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask); 3708c2ecf20Sopenharmony_ci if (ret) { 3718c2ecf20Sopenharmony_ci ath10k_warn(ar, "could not request stats (%d)\n", ret); 3728c2ecf20Sopenharmony_ci return ret; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci time_left = 3768c2ecf20Sopenharmony_ci wait_for_completion_timeout(&ar->debug.fw_stats_complete, 3778c2ecf20Sopenharmony_ci 1 * HZ); 3788c2ecf20Sopenharmony_ci if (!time_left) 3798c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 3828c2ecf20Sopenharmony_ci if (ar->debug.fw_stats_done) { 3838c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int ath10k_fw_stats_open(struct inode *inode, struct file *file) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct ath10k *ar = inode->i_private; 3958c2ecf20Sopenharmony_ci void *buf = NULL; 3968c2ecf20Sopenharmony_ci int ret; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 4018c2ecf20Sopenharmony_ci ret = -ENETDOWN; 4028c2ecf20Sopenharmony_ci goto err_unlock; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE); 4068c2ecf20Sopenharmony_ci if (!buf) { 4078c2ecf20Sopenharmony_ci ret = -ENOMEM; 4088c2ecf20Sopenharmony_ci goto err_unlock; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ret = ath10k_debug_fw_stats_request(ar); 4128c2ecf20Sopenharmony_ci if (ret) { 4138c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request fw stats: %d\n", ret); 4148c2ecf20Sopenharmony_ci goto err_free; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf); 4188c2ecf20Sopenharmony_ci if (ret) { 4198c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to fill fw stats: %d\n", ret); 4208c2ecf20Sopenharmony_ci goto err_free; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci file->private_data = buf; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cierr_free: 4298c2ecf20Sopenharmony_ci vfree(buf); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cierr_unlock: 4328c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4338c2ecf20Sopenharmony_ci return ret; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int ath10k_fw_stats_release(struct inode *inode, struct file *file) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci vfree(file->private_data); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf, 4448c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci const char *buf = file->private_data; 4478c2ecf20Sopenharmony_ci size_t len = strlen(buf); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic const struct file_operations fops_fw_stats = { 4538c2ecf20Sopenharmony_ci .open = ath10k_fw_stats_open, 4548c2ecf20Sopenharmony_ci .release = ath10k_fw_stats_release, 4558c2ecf20Sopenharmony_ci .read = ath10k_fw_stats_read, 4568c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4578c2ecf20Sopenharmony_ci .llseek = default_llseek, 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic ssize_t ath10k_debug_fw_reset_stats_read(struct file *file, 4618c2ecf20Sopenharmony_ci char __user *user_buf, 4628c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 4658c2ecf20Sopenharmony_ci int ret; 4668c2ecf20Sopenharmony_ci size_t len = 0, buf_len = 500; 4678c2ecf20Sopenharmony_ci char *buf; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci buf = kmalloc(buf_len, GFP_KERNEL); 4708c2ecf20Sopenharmony_ci if (!buf) 4718c2ecf20Sopenharmony_ci return -ENOMEM; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 4768c2ecf20Sopenharmony_ci "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter); 4778c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 4788c2ecf20Sopenharmony_ci "fw_warm_reset_counter\t\t%d\n", 4798c2ecf20Sopenharmony_ci ar->stats.fw_warm_reset_counter); 4808c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 4818c2ecf20Sopenharmony_ci "fw_cold_reset_counter\t\t%d\n", 4828c2ecf20Sopenharmony_ci ar->stats.fw_cold_reset_counter); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci kfree(buf); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return ret; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic const struct file_operations fops_fw_reset_stats = { 4948c2ecf20Sopenharmony_ci .open = simple_open, 4958c2ecf20Sopenharmony_ci .read = ath10k_debug_fw_reset_stats_read, 4968c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4978c2ecf20Sopenharmony_ci .llseek = default_llseek, 4988c2ecf20Sopenharmony_ci}; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/* This is a clean assert crash in firmware. */ 5018c2ecf20Sopenharmony_cistatic int ath10k_debug_fw_assert(struct ath10k *ar) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct wmi_vdev_install_key_cmd *cmd; 5048c2ecf20Sopenharmony_ci struct sk_buff *skb; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16); 5078c2ecf20Sopenharmony_ci if (!skb) 5088c2ecf20Sopenharmony_ci return -ENOMEM; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci cmd = (struct wmi_vdev_install_key_cmd *)skb->data; 5118c2ecf20Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* big enough number so that firmware asserts */ 5148c2ecf20Sopenharmony_ci cmd->vdev_id = __cpu_to_le32(0x7ffe); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return ath10k_wmi_cmd_send(ar, skb, 5178c2ecf20Sopenharmony_ci ar->wmi.cmd->vdev_install_key_cmdid); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_simulate_fw_crash(struct file *file, 5218c2ecf20Sopenharmony_ci char __user *user_buf, 5228c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci const char buf[] = 5258c2ecf20Sopenharmony_ci "To simulate firmware crash write one of the keywords to this file:\n" 5268c2ecf20Sopenharmony_ci "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n" 5278c2ecf20Sopenharmony_ci "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n" 5288c2ecf20Sopenharmony_ci "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n" 5298c2ecf20Sopenharmony_ci "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n"; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/* Simulate firmware crash: 5358c2ecf20Sopenharmony_ci * 'soft': Call wmi command causing firmware hang. This firmware hang is 5368c2ecf20Sopenharmony_ci * recoverable by warm firmware reset. 5378c2ecf20Sopenharmony_ci * 'hard': Force firmware crash by setting any vdev parameter for not allowed 5388c2ecf20Sopenharmony_ci * vdev id. This is hard firmware crash because it is recoverable only by cold 5398c2ecf20Sopenharmony_ci * firmware reset. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_simulate_fw_crash(struct file *file, 5428c2ecf20Sopenharmony_ci const char __user *user_buf, 5438c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 5468c2ecf20Sopenharmony_ci char buf[32] = {0}; 5478c2ecf20Sopenharmony_ci ssize_t rc; 5488c2ecf20Sopenharmony_ci int ret; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* filter partial writes and invalid commands */ 5518c2ecf20Sopenharmony_ci if (*ppos != 0 || count >= sizeof(buf) || count == 0) 5528c2ecf20Sopenharmony_ci return -EINVAL; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); 5558c2ecf20Sopenharmony_ci if (rc < 0) 5568c2ecf20Sopenharmony_ci return rc; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* drop the possible '\n' from the end */ 5598c2ecf20Sopenharmony_ci if (buf[*ppos - 1] == '\n') 5608c2ecf20Sopenharmony_ci buf[*ppos - 1] = '\0'; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 5658c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_RESTARTED) { 5668c2ecf20Sopenharmony_ci ret = -ENETDOWN; 5678c2ecf20Sopenharmony_ci goto exit; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!strcmp(buf, "soft")) { 5718c2ecf20Sopenharmony_ci ath10k_info(ar, "simulating soft firmware crash\n"); 5728c2ecf20Sopenharmony_ci ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0); 5738c2ecf20Sopenharmony_ci } else if (!strcmp(buf, "hard")) { 5748c2ecf20Sopenharmony_ci ath10k_info(ar, "simulating hard firmware crash\n"); 5758c2ecf20Sopenharmony_ci /* 0x7fff is vdev id, and it is always out of range for all 5768c2ecf20Sopenharmony_ci * firmware variants in order to force a firmware crash. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, 0x7fff, 5798c2ecf20Sopenharmony_ci ar->wmi.vdev_param->rts_threshold, 5808c2ecf20Sopenharmony_ci 0); 5818c2ecf20Sopenharmony_ci } else if (!strcmp(buf, "assert")) { 5828c2ecf20Sopenharmony_ci ath10k_info(ar, "simulating firmware assert crash\n"); 5838c2ecf20Sopenharmony_ci ret = ath10k_debug_fw_assert(ar); 5848c2ecf20Sopenharmony_ci } else if (!strcmp(buf, "hw-restart")) { 5858c2ecf20Sopenharmony_ci ath10k_info(ar, "user requested hw restart\n"); 5868c2ecf20Sopenharmony_ci queue_work(ar->workqueue, &ar->restart_work); 5878c2ecf20Sopenharmony_ci ret = 0; 5888c2ecf20Sopenharmony_ci } else { 5898c2ecf20Sopenharmony_ci ret = -EINVAL; 5908c2ecf20Sopenharmony_ci goto exit; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (ret) { 5948c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret); 5958c2ecf20Sopenharmony_ci goto exit; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = count; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ciexit: 6018c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6028c2ecf20Sopenharmony_ci return ret; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic const struct file_operations fops_simulate_fw_crash = { 6068c2ecf20Sopenharmony_ci .read = ath10k_read_simulate_fw_crash, 6078c2ecf20Sopenharmony_ci .write = ath10k_write_simulate_fw_crash, 6088c2ecf20Sopenharmony_ci .open = simple_open, 6098c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6108c2ecf20Sopenharmony_ci .llseek = default_llseek, 6118c2ecf20Sopenharmony_ci}; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf, 6148c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 6178c2ecf20Sopenharmony_ci size_t len; 6188c2ecf20Sopenharmony_ci char buf[50]; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->bus_param.chip_id); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic const struct file_operations fops_chip_id = { 6268c2ecf20Sopenharmony_ci .read = ath10k_read_chip_id, 6278c2ecf20Sopenharmony_ci .open = simple_open, 6288c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6298c2ecf20Sopenharmony_ci .llseek = default_llseek, 6308c2ecf20Sopenharmony_ci}; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cistatic ssize_t ath10k_reg_addr_read(struct file *file, 6338c2ecf20Sopenharmony_ci char __user *user_buf, 6348c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 6378c2ecf20Sopenharmony_ci u8 buf[32]; 6388c2ecf20Sopenharmony_ci size_t len = 0; 6398c2ecf20Sopenharmony_ci u32 reg_addr; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 6428c2ecf20Sopenharmony_ci reg_addr = ar->debug.reg_addr; 6438c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic ssize_t ath10k_reg_addr_write(struct file *file, 6518c2ecf20Sopenharmony_ci const char __user *user_buf, 6528c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 6558c2ecf20Sopenharmony_ci u32 reg_addr; 6568c2ecf20Sopenharmony_ci int ret; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci ret = kstrtou32_from_user(user_buf, count, 0, ®_addr); 6598c2ecf20Sopenharmony_ci if (ret) 6608c2ecf20Sopenharmony_ci return ret; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (!IS_ALIGNED(reg_addr, 4)) 6638c2ecf20Sopenharmony_ci return -EFAULT; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 6668c2ecf20Sopenharmony_ci ar->debug.reg_addr = reg_addr; 6678c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return count; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic const struct file_operations fops_reg_addr = { 6738c2ecf20Sopenharmony_ci .read = ath10k_reg_addr_read, 6748c2ecf20Sopenharmony_ci .write = ath10k_reg_addr_write, 6758c2ecf20Sopenharmony_ci .open = simple_open, 6768c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6778c2ecf20Sopenharmony_ci .llseek = default_llseek, 6788c2ecf20Sopenharmony_ci}; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic ssize_t ath10k_reg_value_read(struct file *file, 6818c2ecf20Sopenharmony_ci char __user *user_buf, 6828c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 6858c2ecf20Sopenharmony_ci u8 buf[48]; 6868c2ecf20Sopenharmony_ci size_t len; 6878c2ecf20Sopenharmony_ci u32 reg_addr, reg_val; 6888c2ecf20Sopenharmony_ci int ret; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 6938c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 6948c2ecf20Sopenharmony_ci ret = -ENETDOWN; 6958c2ecf20Sopenharmony_ci goto exit; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci reg_addr = ar->debug.reg_addr; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci reg_val = ath10k_hif_read32(ar, reg_addr); 7018c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ciexit: 7068c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic ssize_t ath10k_reg_value_write(struct file *file, 7128c2ecf20Sopenharmony_ci const char __user *user_buf, 7138c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 7168c2ecf20Sopenharmony_ci u32 reg_addr, reg_val; 7178c2ecf20Sopenharmony_ci int ret; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 7228c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 7238c2ecf20Sopenharmony_ci ret = -ENETDOWN; 7248c2ecf20Sopenharmony_ci goto exit; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci reg_addr = ar->debug.reg_addr; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ret = kstrtou32_from_user(user_buf, count, 0, ®_val); 7308c2ecf20Sopenharmony_ci if (ret) 7318c2ecf20Sopenharmony_ci goto exit; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci ath10k_hif_write32(ar, reg_addr, reg_val); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci ret = count; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ciexit: 7388c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci return ret; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic const struct file_operations fops_reg_value = { 7448c2ecf20Sopenharmony_ci .read = ath10k_reg_value_read, 7458c2ecf20Sopenharmony_ci .write = ath10k_reg_value_write, 7468c2ecf20Sopenharmony_ci .open = simple_open, 7478c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7488c2ecf20Sopenharmony_ci .llseek = default_llseek, 7498c2ecf20Sopenharmony_ci}; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic ssize_t ath10k_mem_value_read(struct file *file, 7528c2ecf20Sopenharmony_ci char __user *user_buf, 7538c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 7568c2ecf20Sopenharmony_ci u8 *buf; 7578c2ecf20Sopenharmony_ci int ret; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (*ppos < 0) 7608c2ecf20Sopenharmony_ci return -EINVAL; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (!count) 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci buf = vmalloc(count); 7688c2ecf20Sopenharmony_ci if (!buf) { 7698c2ecf20Sopenharmony_ci ret = -ENOMEM; 7708c2ecf20Sopenharmony_ci goto exit; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 7748c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 7758c2ecf20Sopenharmony_ci ret = -ENETDOWN; 7768c2ecf20Sopenharmony_ci goto exit; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci ret = ath10k_hif_diag_read(ar, *ppos, buf, count); 7808c2ecf20Sopenharmony_ci if (ret) { 7818c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n", 7828c2ecf20Sopenharmony_ci (u32)(*ppos), ret); 7838c2ecf20Sopenharmony_ci goto exit; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci ret = copy_to_user(user_buf, buf, count); 7878c2ecf20Sopenharmony_ci if (ret) { 7888c2ecf20Sopenharmony_ci ret = -EFAULT; 7898c2ecf20Sopenharmony_ci goto exit; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci count -= ret; 7938c2ecf20Sopenharmony_ci *ppos += count; 7948c2ecf20Sopenharmony_ci ret = count; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ciexit: 7978c2ecf20Sopenharmony_ci vfree(buf); 7988c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return ret; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic ssize_t ath10k_mem_value_write(struct file *file, 8048c2ecf20Sopenharmony_ci const char __user *user_buf, 8058c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 8088c2ecf20Sopenharmony_ci u8 *buf; 8098c2ecf20Sopenharmony_ci int ret; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (*ppos < 0) 8128c2ecf20Sopenharmony_ci return -EINVAL; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (!count) 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci buf = vmalloc(count); 8208c2ecf20Sopenharmony_ci if (!buf) { 8218c2ecf20Sopenharmony_ci ret = -ENOMEM; 8228c2ecf20Sopenharmony_ci goto exit; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 8268c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_UTF) { 8278c2ecf20Sopenharmony_ci ret = -ENETDOWN; 8288c2ecf20Sopenharmony_ci goto exit; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci ret = copy_from_user(buf, user_buf, count); 8328c2ecf20Sopenharmony_ci if (ret) { 8338c2ecf20Sopenharmony_ci ret = -EFAULT; 8348c2ecf20Sopenharmony_ci goto exit; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci ret = ath10k_hif_diag_write(ar, *ppos, buf, count); 8388c2ecf20Sopenharmony_ci if (ret) { 8398c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n", 8408c2ecf20Sopenharmony_ci (u32)(*ppos), ret); 8418c2ecf20Sopenharmony_ci goto exit; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci *ppos += count; 8458c2ecf20Sopenharmony_ci ret = count; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ciexit: 8488c2ecf20Sopenharmony_ci vfree(buf); 8498c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic const struct file_operations fops_mem_value = { 8558c2ecf20Sopenharmony_ci .read = ath10k_mem_value_read, 8568c2ecf20Sopenharmony_ci .write = ath10k_mem_value_write, 8578c2ecf20Sopenharmony_ci .open = simple_open, 8588c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8598c2ecf20Sopenharmony_ci .llseek = default_llseek, 8608c2ecf20Sopenharmony_ci}; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic int ath10k_debug_htt_stats_req(struct ath10k *ar) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci u64 cookie; 8658c2ecf20Sopenharmony_ci int ret; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (ar->debug.htt_stats_mask == 0) 8708c2ecf20Sopenharmony_ci /* htt stats are disabled */ 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci cookie = get_jiffies_64(); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask, 8798c2ecf20Sopenharmony_ci ar->debug.reset_htt_stats, cookie); 8808c2ecf20Sopenharmony_ci if (ret) { 8818c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send htt stats request: %d\n", ret); 8828c2ecf20Sopenharmony_ci return ret; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork, 8868c2ecf20Sopenharmony_ci msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL)); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci return 0; 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic void ath10k_debug_htt_stats_dwork(struct work_struct *work) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct ath10k *ar = container_of(work, struct ath10k, 8948c2ecf20Sopenharmony_ci debug.htt_stats_dwork.work); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci ath10k_debug_htt_stats_req(ar); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_htt_stats_mask(struct file *file, 9048c2ecf20Sopenharmony_ci char __user *user_buf, 9058c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 9088c2ecf20Sopenharmony_ci char buf[32]; 9098c2ecf20Sopenharmony_ci size_t len; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_htt_stats_mask(struct file *file, 9178c2ecf20Sopenharmony_ci const char __user *user_buf, 9188c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 9218c2ecf20Sopenharmony_ci unsigned long mask; 9228c2ecf20Sopenharmony_ci int ret; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci ret = kstrtoul_from_user(user_buf, count, 0, &mask); 9258c2ecf20Sopenharmony_ci if (ret) 9268c2ecf20Sopenharmony_ci return ret; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* max 17 bit masks (for now) */ 9298c2ecf20Sopenharmony_ci if (mask > HTT_STATS_BIT_MASK) 9308c2ecf20Sopenharmony_ci return -E2BIG; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci ar->debug.htt_stats_mask = mask; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci ret = ath10k_debug_htt_stats_req(ar); 9378c2ecf20Sopenharmony_ci if (ret) 9388c2ecf20Sopenharmony_ci goto out; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci ret = count; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ciout: 9438c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return ret; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic const struct file_operations fops_htt_stats_mask = { 9498c2ecf20Sopenharmony_ci .read = ath10k_read_htt_stats_mask, 9508c2ecf20Sopenharmony_ci .write = ath10k_write_htt_stats_mask, 9518c2ecf20Sopenharmony_ci .open = simple_open, 9528c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9538c2ecf20Sopenharmony_ci .llseek = default_llseek, 9548c2ecf20Sopenharmony_ci}; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, 9578c2ecf20Sopenharmony_ci char __user *user_buf, 9588c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 9618c2ecf20Sopenharmony_ci char buf[64]; 9628c2ecf20Sopenharmony_ci u8 amsdu, ampdu; 9638c2ecf20Sopenharmony_ci size_t len; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci amsdu = ar->htt.max_num_amsdu; 9688c2ecf20Sopenharmony_ci ampdu = ar->htt.max_num_ampdu; 9698c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, 9778c2ecf20Sopenharmony_ci const char __user *user_buf, 9788c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 9818c2ecf20Sopenharmony_ci int res; 9828c2ecf20Sopenharmony_ci char buf[64] = {0}; 9838c2ecf20Sopenharmony_ci unsigned int amsdu, ampdu; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 9868c2ecf20Sopenharmony_ci user_buf, count); 9878c2ecf20Sopenharmony_ci if (res <= 0) 9888c2ecf20Sopenharmony_ci return res; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci res = sscanf(buf, "%u %u", &amsdu, &du); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (res != 2) 9938c2ecf20Sopenharmony_ci return -EINVAL; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu); 9988c2ecf20Sopenharmony_ci if (res) 9998c2ecf20Sopenharmony_ci goto out; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci res = count; 10028c2ecf20Sopenharmony_ci ar->htt.max_num_amsdu = amsdu; 10038c2ecf20Sopenharmony_ci ar->htt.max_num_ampdu = ampdu; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ciout: 10068c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 10078c2ecf20Sopenharmony_ci return res; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic const struct file_operations fops_htt_max_amsdu_ampdu = { 10118c2ecf20Sopenharmony_ci .read = ath10k_read_htt_max_amsdu_ampdu, 10128c2ecf20Sopenharmony_ci .write = ath10k_write_htt_max_amsdu_ampdu, 10138c2ecf20Sopenharmony_ci .open = simple_open, 10148c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10158c2ecf20Sopenharmony_ci .llseek = default_llseek, 10168c2ecf20Sopenharmony_ci}; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_fw_dbglog(struct file *file, 10198c2ecf20Sopenharmony_ci char __user *user_buf, 10208c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 10238c2ecf20Sopenharmony_ci size_t len; 10248c2ecf20Sopenharmony_ci char buf[96]; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%16llx %u\n", 10278c2ecf20Sopenharmony_ci ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_fw_dbglog(struct file *file, 10338c2ecf20Sopenharmony_ci const char __user *user_buf, 10348c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 10378c2ecf20Sopenharmony_ci int ret; 10388c2ecf20Sopenharmony_ci char buf[96] = {0}; 10398c2ecf20Sopenharmony_ci unsigned int log_level; 10408c2ecf20Sopenharmony_ci u64 mask; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 10438c2ecf20Sopenharmony_ci user_buf, count); 10448c2ecf20Sopenharmony_ci if (ret <= 0) 10458c2ecf20Sopenharmony_ci return ret; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci ret = sscanf(buf, "%llx %u", &mask, &log_level); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (!ret) 10508c2ecf20Sopenharmony_ci return -EINVAL; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (ret == 1) 10538c2ecf20Sopenharmony_ci /* default if user did not specify */ 10548c2ecf20Sopenharmony_ci log_level = ATH10K_DBGLOG_LEVEL_WARN; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci ar->debug.fw_dbglog_mask = mask; 10598c2ecf20Sopenharmony_ci ar->debug.fw_dbglog_level = log_level; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (ar->state == ATH10K_STATE_ON) { 10628c2ecf20Sopenharmony_ci ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, 10638c2ecf20Sopenharmony_ci ar->debug.fw_dbglog_level); 10648c2ecf20Sopenharmony_ci if (ret) { 10658c2ecf20Sopenharmony_ci ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n", 10668c2ecf20Sopenharmony_ci ret); 10678c2ecf20Sopenharmony_ci goto exit; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ret = count; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ciexit: 10748c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci return ret; 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci/* TODO: Would be nice to always support ethtool stats, would need to 10808c2ecf20Sopenharmony_ci * move the stats storage out of ath10k_debug, or always have ath10k_debug 10818c2ecf20Sopenharmony_ci * struct available.. 10828c2ecf20Sopenharmony_ci */ 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci/* This generally cooresponds to the debugfs fw_stats file */ 10858c2ecf20Sopenharmony_cistatic const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { 10868c2ecf20Sopenharmony_ci "tx_pkts_nic", 10878c2ecf20Sopenharmony_ci "tx_bytes_nic", 10888c2ecf20Sopenharmony_ci "rx_pkts_nic", 10898c2ecf20Sopenharmony_ci "rx_bytes_nic", 10908c2ecf20Sopenharmony_ci "d_noise_floor", 10918c2ecf20Sopenharmony_ci "d_cycle_count", 10928c2ecf20Sopenharmony_ci "d_phy_error", 10938c2ecf20Sopenharmony_ci "d_rts_bad", 10948c2ecf20Sopenharmony_ci "d_rts_good", 10958c2ecf20Sopenharmony_ci "d_tx_power", /* in .5 dbM I think */ 10968c2ecf20Sopenharmony_ci "d_rx_crc_err", /* fcs_bad */ 10978c2ecf20Sopenharmony_ci "d_rx_crc_err_drop", /* frame with FCS error, dropped late in kernel */ 10988c2ecf20Sopenharmony_ci "d_no_beacon", 10998c2ecf20Sopenharmony_ci "d_tx_mpdus_queued", 11008c2ecf20Sopenharmony_ci "d_tx_msdu_queued", 11018c2ecf20Sopenharmony_ci "d_tx_msdu_dropped", 11028c2ecf20Sopenharmony_ci "d_local_enqued", 11038c2ecf20Sopenharmony_ci "d_local_freed", 11048c2ecf20Sopenharmony_ci "d_tx_ppdu_hw_queued", 11058c2ecf20Sopenharmony_ci "d_tx_ppdu_reaped", 11068c2ecf20Sopenharmony_ci "d_tx_fifo_underrun", 11078c2ecf20Sopenharmony_ci "d_tx_ppdu_abort", 11088c2ecf20Sopenharmony_ci "d_tx_mpdu_requed", 11098c2ecf20Sopenharmony_ci "d_tx_excessive_retries", 11108c2ecf20Sopenharmony_ci "d_tx_hw_rate", 11118c2ecf20Sopenharmony_ci "d_tx_dropped_sw_retries", 11128c2ecf20Sopenharmony_ci "d_tx_illegal_rate", 11138c2ecf20Sopenharmony_ci "d_tx_continuous_xretries", 11148c2ecf20Sopenharmony_ci "d_tx_timeout", 11158c2ecf20Sopenharmony_ci "d_tx_mpdu_txop_limit", 11168c2ecf20Sopenharmony_ci "d_pdev_resets", 11178c2ecf20Sopenharmony_ci "d_rx_mid_ppdu_route_change", 11188c2ecf20Sopenharmony_ci "d_rx_status", 11198c2ecf20Sopenharmony_ci "d_rx_extra_frags_ring0", 11208c2ecf20Sopenharmony_ci "d_rx_extra_frags_ring1", 11218c2ecf20Sopenharmony_ci "d_rx_extra_frags_ring2", 11228c2ecf20Sopenharmony_ci "d_rx_extra_frags_ring3", 11238c2ecf20Sopenharmony_ci "d_rx_msdu_htt", 11248c2ecf20Sopenharmony_ci "d_rx_mpdu_htt", 11258c2ecf20Sopenharmony_ci "d_rx_msdu_stack", 11268c2ecf20Sopenharmony_ci "d_rx_mpdu_stack", 11278c2ecf20Sopenharmony_ci "d_rx_phy_err", 11288c2ecf20Sopenharmony_ci "d_rx_phy_err_drops", 11298c2ecf20Sopenharmony_ci "d_rx_mpdu_errors", /* FCS, MIC, ENC */ 11308c2ecf20Sopenharmony_ci "d_fw_crash_count", 11318c2ecf20Sopenharmony_ci "d_fw_warm_reset_count", 11328c2ecf20Sopenharmony_ci "d_fw_cold_reset_count", 11338c2ecf20Sopenharmony_ci}; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats) 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_civoid ath10k_debug_get_et_strings(struct ieee80211_hw *hw, 11388c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 11398c2ecf20Sopenharmony_ci u32 sset, u8 *data) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci if (sset == ETH_SS_STATS) 11428c2ecf20Sopenharmony_ci memcpy(data, ath10k_gstrings_stats, 11438c2ecf20Sopenharmony_ci sizeof(ath10k_gstrings_stats)); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ciint ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, 11478c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, int sset) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci if (sset == ETH_SS_STATS) 11508c2ecf20Sopenharmony_ci return ATH10K_SSTATS_LEN; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return 0; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_civoid ath10k_debug_get_et_stats(struct ieee80211_hw *hw, 11568c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 11578c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct ath10k *ar = hw->priv; 11608c2ecf20Sopenharmony_ci static const struct ath10k_fw_stats_pdev zero_stats = {}; 11618c2ecf20Sopenharmony_ci const struct ath10k_fw_stats_pdev *pdev_stats; 11628c2ecf20Sopenharmony_ci int i = 0, ret; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (ar->state == ATH10K_STATE_ON) { 11678c2ecf20Sopenharmony_ci ret = ath10k_debug_fw_stats_request(ar); 11688c2ecf20Sopenharmony_ci if (ret) { 11698c2ecf20Sopenharmony_ci /* just print a warning and try to use older results */ 11708c2ecf20Sopenharmony_ci ath10k_warn(ar, 11718c2ecf20Sopenharmony_ci "failed to get fw stats for ethtool: %d\n", 11728c2ecf20Sopenharmony_ci ret); 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs, 11778c2ecf20Sopenharmony_ci struct ath10k_fw_stats_pdev, 11788c2ecf20Sopenharmony_ci list); 11798c2ecf20Sopenharmony_ci if (!pdev_stats) { 11808c2ecf20Sopenharmony_ci /* no results available so just return zeroes */ 11818c2ecf20Sopenharmony_ci pdev_stats = &zero_stats; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */ 11878c2ecf20Sopenharmony_ci data[i++] = 0; /* tx bytes */ 11888c2ecf20Sopenharmony_ci data[i++] = pdev_stats->htt_mpdus; 11898c2ecf20Sopenharmony_ci data[i++] = 0; /* rx bytes */ 11908c2ecf20Sopenharmony_ci data[i++] = pdev_stats->ch_noise_floor; 11918c2ecf20Sopenharmony_ci data[i++] = pdev_stats->cycle_count; 11928c2ecf20Sopenharmony_ci data[i++] = pdev_stats->phy_err_count; 11938c2ecf20Sopenharmony_ci data[i++] = pdev_stats->rts_bad; 11948c2ecf20Sopenharmony_ci data[i++] = pdev_stats->rts_good; 11958c2ecf20Sopenharmony_ci data[i++] = pdev_stats->chan_tx_power; 11968c2ecf20Sopenharmony_ci data[i++] = pdev_stats->fcs_bad; 11978c2ecf20Sopenharmony_ci data[i++] = ar->stats.rx_crc_err_drop; 11988c2ecf20Sopenharmony_ci data[i++] = pdev_stats->no_beacons; 11998c2ecf20Sopenharmony_ci data[i++] = pdev_stats->mpdu_enqued; 12008c2ecf20Sopenharmony_ci data[i++] = pdev_stats->msdu_enqued; 12018c2ecf20Sopenharmony_ci data[i++] = pdev_stats->wmm_drop; 12028c2ecf20Sopenharmony_ci data[i++] = pdev_stats->local_enqued; 12038c2ecf20Sopenharmony_ci data[i++] = pdev_stats->local_freed; 12048c2ecf20Sopenharmony_ci data[i++] = pdev_stats->hw_queued; 12058c2ecf20Sopenharmony_ci data[i++] = pdev_stats->hw_reaped; 12068c2ecf20Sopenharmony_ci data[i++] = pdev_stats->underrun; 12078c2ecf20Sopenharmony_ci data[i++] = pdev_stats->tx_abort; 12088c2ecf20Sopenharmony_ci data[i++] = pdev_stats->mpdus_requed; 12098c2ecf20Sopenharmony_ci data[i++] = pdev_stats->tx_ko; 12108c2ecf20Sopenharmony_ci data[i++] = pdev_stats->data_rc; 12118c2ecf20Sopenharmony_ci data[i++] = pdev_stats->sw_retry_failure; 12128c2ecf20Sopenharmony_ci data[i++] = pdev_stats->illgl_rate_phy_err; 12138c2ecf20Sopenharmony_ci data[i++] = pdev_stats->pdev_cont_xretry; 12148c2ecf20Sopenharmony_ci data[i++] = pdev_stats->pdev_tx_timeout; 12158c2ecf20Sopenharmony_ci data[i++] = pdev_stats->txop_ovf; 12168c2ecf20Sopenharmony_ci data[i++] = pdev_stats->pdev_resets; 12178c2ecf20Sopenharmony_ci data[i++] = pdev_stats->mid_ppdu_route_change; 12188c2ecf20Sopenharmony_ci data[i++] = pdev_stats->status_rcvd; 12198c2ecf20Sopenharmony_ci data[i++] = pdev_stats->r0_frags; 12208c2ecf20Sopenharmony_ci data[i++] = pdev_stats->r1_frags; 12218c2ecf20Sopenharmony_ci data[i++] = pdev_stats->r2_frags; 12228c2ecf20Sopenharmony_ci data[i++] = pdev_stats->r3_frags; 12238c2ecf20Sopenharmony_ci data[i++] = pdev_stats->htt_msdus; 12248c2ecf20Sopenharmony_ci data[i++] = pdev_stats->htt_mpdus; 12258c2ecf20Sopenharmony_ci data[i++] = pdev_stats->loc_msdus; 12268c2ecf20Sopenharmony_ci data[i++] = pdev_stats->loc_mpdus; 12278c2ecf20Sopenharmony_ci data[i++] = pdev_stats->phy_errs; 12288c2ecf20Sopenharmony_ci data[i++] = pdev_stats->phy_err_drop; 12298c2ecf20Sopenharmony_ci data[i++] = pdev_stats->mpdu_errs; 12308c2ecf20Sopenharmony_ci data[i++] = ar->stats.fw_crash_counter; 12318c2ecf20Sopenharmony_ci data[i++] = ar->stats.fw_warm_reset_counter; 12328c2ecf20Sopenharmony_ci data[i++] = ar->stats.fw_cold_reset_counter; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci WARN_ON(i != ATH10K_SSTATS_LEN); 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic const struct file_operations fops_fw_dbglog = { 12428c2ecf20Sopenharmony_ci .read = ath10k_read_fw_dbglog, 12438c2ecf20Sopenharmony_ci .write = ath10k_write_fw_dbglog, 12448c2ecf20Sopenharmony_ci .open = simple_open, 12458c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12468c2ecf20Sopenharmony_ci .llseek = default_llseek, 12478c2ecf20Sopenharmony_ci}; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic int ath10k_debug_cal_data_fetch(struct ath10k *ar) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci u32 hi_addr; 12528c2ecf20Sopenharmony_ci __le32 addr; 12538c2ecf20Sopenharmony_ci int ret; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN)) 12588c2ecf20Sopenharmony_ci return -EINVAL; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (ar->hw_params.cal_data_len == 0) 12618c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci hi_addr = host_interest_item_address(HI_ITEM(hi_board_data)); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr)); 12668c2ecf20Sopenharmony_ci if (ret) { 12678c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to read hi_board_data address: %d\n", 12688c2ecf20Sopenharmony_ci ret); 12698c2ecf20Sopenharmony_ci return ret; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data, 12738c2ecf20Sopenharmony_ci ar->hw_params.cal_data_len); 12748c2ecf20Sopenharmony_ci if (ret) { 12758c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to read calibration data: %d\n", ret); 12768c2ecf20Sopenharmony_ci return ret; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct ath10k *ar = inode->i_private; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (ar->state == ATH10K_STATE_ON || 12898c2ecf20Sopenharmony_ci ar->state == ATH10K_STATE_UTF) { 12908c2ecf20Sopenharmony_ci ath10k_debug_cal_data_fetch(ar); 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci file->private_data = ar; 12948c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return 0; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic ssize_t ath10k_debug_cal_data_read(struct file *file, 13008c2ecf20Sopenharmony_ci char __user *user_buf, 13018c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci count = simple_read_from_buffer(user_buf, count, ppos, 13088c2ecf20Sopenharmony_ci ar->debug.cal_data, 13098c2ecf20Sopenharmony_ci ar->hw_params.cal_data_len); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci return count; 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_ani_enable(struct file *file, 13178c2ecf20Sopenharmony_ci const char __user *user_buf, 13188c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 13218c2ecf20Sopenharmony_ci int ret; 13228c2ecf20Sopenharmony_ci u8 enable; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (kstrtou8_from_user(user_buf, count, 0, &enable)) 13258c2ecf20Sopenharmony_ci return -EINVAL; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (ar->ani_enabled == enable) { 13308c2ecf20Sopenharmony_ci ret = count; 13318c2ecf20Sopenharmony_ci goto exit; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable, 13358c2ecf20Sopenharmony_ci enable); 13368c2ecf20Sopenharmony_ci if (ret) { 13378c2ecf20Sopenharmony_ci ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret); 13388c2ecf20Sopenharmony_ci goto exit; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci ar->ani_enabled = enable; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci ret = count; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ciexit: 13458c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return ret; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf, 13518c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 13548c2ecf20Sopenharmony_ci size_t len; 13558c2ecf20Sopenharmony_ci char buf[32]; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic const struct file_operations fops_ani_enable = { 13638c2ecf20Sopenharmony_ci .read = ath10k_read_ani_enable, 13648c2ecf20Sopenharmony_ci .write = ath10k_write_ani_enable, 13658c2ecf20Sopenharmony_ci .open = simple_open, 13668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 13678c2ecf20Sopenharmony_ci .llseek = default_llseek, 13688c2ecf20Sopenharmony_ci}; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic const struct file_operations fops_cal_data = { 13718c2ecf20Sopenharmony_ci .open = ath10k_debug_cal_data_open, 13728c2ecf20Sopenharmony_ci .read = ath10k_debug_cal_data_read, 13738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 13748c2ecf20Sopenharmony_ci .llseek = default_llseek, 13758c2ecf20Sopenharmony_ci}; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_nf_cal_period(struct file *file, 13788c2ecf20Sopenharmony_ci char __user *user_buf, 13798c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 13828c2ecf20Sopenharmony_ci size_t len; 13838c2ecf20Sopenharmony_ci char buf[32]; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%d\n", ar->debug.nf_cal_period); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_nf_cal_period(struct file *file, 13918c2ecf20Sopenharmony_ci const char __user *user_buf, 13928c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 13958c2ecf20Sopenharmony_ci unsigned long period; 13968c2ecf20Sopenharmony_ci int ret; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci ret = kstrtoul_from_user(user_buf, count, 0, &period); 13998c2ecf20Sopenharmony_ci if (ret) 14008c2ecf20Sopenharmony_ci return ret; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX) 14038c2ecf20Sopenharmony_ci return -EINVAL; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* there's no way to switch back to the firmware default */ 14068c2ecf20Sopenharmony_ci if (period == 0) 14078c2ecf20Sopenharmony_ci return -EINVAL; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci ar->debug.nf_cal_period = period; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 14148c2ecf20Sopenharmony_ci /* firmware is not running, nothing else to do */ 14158c2ecf20Sopenharmony_ci ret = count; 14168c2ecf20Sopenharmony_ci goto exit; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period, 14208c2ecf20Sopenharmony_ci ar->debug.nf_cal_period); 14218c2ecf20Sopenharmony_ci if (ret) { 14228c2ecf20Sopenharmony_ci ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n", 14238c2ecf20Sopenharmony_ci ret); 14248c2ecf20Sopenharmony_ci goto exit; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci ret = count; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ciexit: 14308c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci return ret; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic const struct file_operations fops_nf_cal_period = { 14368c2ecf20Sopenharmony_ci .read = ath10k_read_nf_cal_period, 14378c2ecf20Sopenharmony_ci .write = ath10k_write_nf_cal_period, 14388c2ecf20Sopenharmony_ci .open = simple_open, 14398c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 14408c2ecf20Sopenharmony_ci .llseek = default_llseek, 14418c2ecf20Sopenharmony_ci}; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci#define ATH10K_TPC_CONFIG_BUF_SIZE (1024 * 1024) 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic int ath10k_debug_tpc_stats_request(struct ath10k *ar) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci int ret; 14488c2ecf20Sopenharmony_ci unsigned long time_left; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci reinit_completion(&ar->debug.tpc_complete); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM); 14558c2ecf20Sopenharmony_ci if (ret) { 14568c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request tpc config: %d\n", ret); 14578c2ecf20Sopenharmony_ci return ret; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->debug.tpc_complete, 14618c2ecf20Sopenharmony_ci 1 * HZ); 14628c2ecf20Sopenharmony_ci if (time_left == 0) 14638c2ecf20Sopenharmony_ci return -ETIMEDOUT; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci return 0; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_civoid ath10k_debug_tpc_stats_process(struct ath10k *ar, 14698c2ecf20Sopenharmony_ci struct ath10k_tpc_stats *tpc_stats) 14708c2ecf20Sopenharmony_ci{ 14718c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci kfree(ar->debug.tpc_stats); 14748c2ecf20Sopenharmony_ci ar->debug.tpc_stats = tpc_stats; 14758c2ecf20Sopenharmony_ci complete(&ar->debug.tpc_complete); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 14788c2ecf20Sopenharmony_ci} 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_civoid 14818c2ecf20Sopenharmony_ciath10k_debug_tpc_stats_final_process(struct ath10k *ar, 14828c2ecf20Sopenharmony_ci struct ath10k_tpc_stats_final *tpc_stats) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci kfree(ar->debug.tpc_stats_final); 14878c2ecf20Sopenharmony_ci ar->debug.tpc_stats_final = tpc_stats; 14888c2ecf20Sopenharmony_ci complete(&ar->debug.tpc_complete); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, 14948c2ecf20Sopenharmony_ci unsigned int j, char *buf, size_t *len) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci int i; 14978c2ecf20Sopenharmony_ci size_t buf_len; 14988c2ecf20Sopenharmony_ci static const char table_str[][5] = { "CDD", 14998c2ecf20Sopenharmony_ci "STBC", 15008c2ecf20Sopenharmony_ci "TXBF" }; 15018c2ecf20Sopenharmony_ci static const char pream_str[][6] = { "CCK", 15028c2ecf20Sopenharmony_ci "OFDM", 15038c2ecf20Sopenharmony_ci "HT20", 15048c2ecf20Sopenharmony_ci "HT40", 15058c2ecf20Sopenharmony_ci "VHT20", 15068c2ecf20Sopenharmony_ci "VHT40", 15078c2ecf20Sopenharmony_ci "VHT80", 15088c2ecf20Sopenharmony_ci "HTCUP" }; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci buf_len = ATH10K_TPC_CONFIG_BUF_SIZE; 15118c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15128c2ecf20Sopenharmony_ci "********************************\n"); 15138c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15148c2ecf20Sopenharmony_ci "******************* %s POWER TABLE ****************\n", 15158c2ecf20Sopenharmony_ci table_str[j]); 15168c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15178c2ecf20Sopenharmony_ci "********************************\n"); 15188c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15198c2ecf20Sopenharmony_ci "No. Preamble Rate_code "); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci for (i = 0; i < tpc_stats->num_tx_chain; i++) 15228c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15238c2ecf20Sopenharmony_ci "tpc_value%d ", i); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, "\n"); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci for (i = 0; i < tpc_stats->rate_max; i++) { 15288c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15298c2ecf20Sopenharmony_ci "%8d %s 0x%2x %s\n", i, 15308c2ecf20Sopenharmony_ci pream_str[tpc_stats->tpc_table[j].pream_idx[i]], 15318c2ecf20Sopenharmony_ci tpc_stats->tpc_table[j].rate_code[i], 15328c2ecf20Sopenharmony_ci tpc_stats->tpc_table[j].tpc_value[i]); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci *len += scnprintf(buf + *len, buf_len - *len, 15368c2ecf20Sopenharmony_ci "***********************************\n"); 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_cistatic void ath10k_tpc_stats_fill(struct ath10k *ar, 15408c2ecf20Sopenharmony_ci struct ath10k_tpc_stats *tpc_stats, 15418c2ecf20Sopenharmony_ci char *buf) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci int j; 15448c2ecf20Sopenharmony_ci size_t len, buf_len; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci len = 0; 15478c2ecf20Sopenharmony_ci buf_len = ATH10K_TPC_CONFIG_BUF_SIZE; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (!tpc_stats) { 15528c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to get tpc stats\n"); 15538c2ecf20Sopenharmony_ci goto unlock; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); 15578c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15588c2ecf20Sopenharmony_ci "*************************************\n"); 15598c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15608c2ecf20Sopenharmony_ci "TPC config for channel %4d mode %d\n", 15618c2ecf20Sopenharmony_ci tpc_stats->chan_freq, 15628c2ecf20Sopenharmony_ci tpc_stats->phy_mode); 15638c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15648c2ecf20Sopenharmony_ci "*************************************\n"); 15658c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15668c2ecf20Sopenharmony_ci "CTL = 0x%2x Reg. Domain = %2d\n", 15678c2ecf20Sopenharmony_ci tpc_stats->ctl, 15688c2ecf20Sopenharmony_ci tpc_stats->reg_domain); 15698c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15708c2ecf20Sopenharmony_ci "Antenna Gain = %2d Reg. Max Antenna Gain = %2d\n", 15718c2ecf20Sopenharmony_ci tpc_stats->twice_antenna_gain, 15728c2ecf20Sopenharmony_ci tpc_stats->twice_antenna_reduction); 15738c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15748c2ecf20Sopenharmony_ci "Power Limit = %2d Reg. Max Power = %2d\n", 15758c2ecf20Sopenharmony_ci tpc_stats->power_limit, 15768c2ecf20Sopenharmony_ci tpc_stats->twice_max_rd_power / 2); 15778c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15788c2ecf20Sopenharmony_ci "Num tx chains = %2d Num supported rates = %2d\n", 15798c2ecf20Sopenharmony_ci tpc_stats->num_tx_chain, 15808c2ecf20Sopenharmony_ci tpc_stats->rate_max); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci for (j = 0; j < WMI_TPC_FLAG; j++) { 15838c2ecf20Sopenharmony_ci switch (j) { 15848c2ecf20Sopenharmony_ci case WMI_TPC_TABLE_TYPE_CDD: 15858c2ecf20Sopenharmony_ci if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { 15868c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15878c2ecf20Sopenharmony_ci "CDD not supported\n"); 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci ath10k_tpc_stats_print(tpc_stats, j, buf, &len); 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci case WMI_TPC_TABLE_TYPE_STBC: 15948c2ecf20Sopenharmony_ci if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { 15958c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 15968c2ecf20Sopenharmony_ci "STBC not supported\n"); 15978c2ecf20Sopenharmony_ci break; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci ath10k_tpc_stats_print(tpc_stats, j, buf, &len); 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci case WMI_TPC_TABLE_TYPE_TXBF: 16038c2ecf20Sopenharmony_ci if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) { 16048c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 16058c2ecf20Sopenharmony_ci "TXBF not supported\n***************************\n"); 16068c2ecf20Sopenharmony_ci break; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci ath10k_tpc_stats_print(tpc_stats, j, buf, &len); 16108c2ecf20Sopenharmony_ci break; 16118c2ecf20Sopenharmony_ci default: 16128c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 16138c2ecf20Sopenharmony_ci "Invalid Type\n"); 16148c2ecf20Sopenharmony_ci break; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ciunlock: 16198c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (len >= buf_len) 16228c2ecf20Sopenharmony_ci buf[len - 1] = 0; 16238c2ecf20Sopenharmony_ci else 16248c2ecf20Sopenharmony_ci buf[len] = 0; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_cistatic int ath10k_tpc_stats_open(struct inode *inode, struct file *file) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci struct ath10k *ar = inode->i_private; 16308c2ecf20Sopenharmony_ci void *buf = NULL; 16318c2ecf20Sopenharmony_ci int ret; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 16368c2ecf20Sopenharmony_ci ret = -ENETDOWN; 16378c2ecf20Sopenharmony_ci goto err_unlock; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE); 16418c2ecf20Sopenharmony_ci if (!buf) { 16428c2ecf20Sopenharmony_ci ret = -ENOMEM; 16438c2ecf20Sopenharmony_ci goto err_unlock; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci ret = ath10k_debug_tpc_stats_request(ar); 16478c2ecf20Sopenharmony_ci if (ret) { 16488c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request tpc config stats: %d\n", 16498c2ecf20Sopenharmony_ci ret); 16508c2ecf20Sopenharmony_ci goto err_free; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf); 16548c2ecf20Sopenharmony_ci file->private_data = buf; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 16578c2ecf20Sopenharmony_ci return 0; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cierr_free: 16608c2ecf20Sopenharmony_ci vfree(buf); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_cierr_unlock: 16638c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 16648c2ecf20Sopenharmony_ci return ret; 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cistatic int ath10k_tpc_stats_release(struct inode *inode, struct file *file) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci vfree(file->private_data); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci return 0; 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_cistatic ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf, 16758c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci const char *buf = file->private_data; 16788c2ecf20Sopenharmony_ci size_t len = strlen(buf); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_cistatic const struct file_operations fops_tpc_stats = { 16848c2ecf20Sopenharmony_ci .open = ath10k_tpc_stats_open, 16858c2ecf20Sopenharmony_ci .release = ath10k_tpc_stats_release, 16868c2ecf20Sopenharmony_ci .read = ath10k_tpc_stats_read, 16878c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 16888c2ecf20Sopenharmony_ci .llseek = default_llseek, 16898c2ecf20Sopenharmony_ci}; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ciint ath10k_debug_start(struct ath10k *ar) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci int ret; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci ret = ath10k_debug_htt_stats_req(ar); 16988c2ecf20Sopenharmony_ci if (ret) 16998c2ecf20Sopenharmony_ci /* continue normally anyway, this isn't serious */ 17008c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to start htt stats workqueue: %d\n", 17018c2ecf20Sopenharmony_ci ret); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci if (ar->debug.fw_dbglog_mask) { 17048c2ecf20Sopenharmony_ci ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask, 17058c2ecf20Sopenharmony_ci ATH10K_DBGLOG_LEVEL_WARN); 17068c2ecf20Sopenharmony_ci if (ret) 17078c2ecf20Sopenharmony_ci /* not serious */ 17088c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to enable dbglog during start: %d", 17098c2ecf20Sopenharmony_ci ret); 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (ar->pktlog_filter) { 17138c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_enable(ar, 17148c2ecf20Sopenharmony_ci ar->pktlog_filter); 17158c2ecf20Sopenharmony_ci if (ret) 17168c2ecf20Sopenharmony_ci /* not serious */ 17178c2ecf20Sopenharmony_ci ath10k_warn(ar, 17188c2ecf20Sopenharmony_ci "failed to enable pktlog filter %x: %d\n", 17198c2ecf20Sopenharmony_ci ar->pktlog_filter, ret); 17208c2ecf20Sopenharmony_ci } else { 17218c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_disable(ar); 17228c2ecf20Sopenharmony_ci if (ret) 17238c2ecf20Sopenharmony_ci /* not serious */ 17248c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (ar->debug.nf_cal_period && 17288c2ecf20Sopenharmony_ci !test_bit(ATH10K_FW_FEATURE_NON_BMI, 17298c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features)) { 17308c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, 17318c2ecf20Sopenharmony_ci ar->wmi.pdev_param->cal_period, 17328c2ecf20Sopenharmony_ci ar->debug.nf_cal_period); 17338c2ecf20Sopenharmony_ci if (ret) 17348c2ecf20Sopenharmony_ci /* not serious */ 17358c2ecf20Sopenharmony_ci ath10k_warn(ar, "cal period cfg failed from debug start: %d\n", 17368c2ecf20Sopenharmony_ci ret); 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci return ret; 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_civoid ath10k_debug_stop(struct ath10k *ar) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, 17478c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features)) 17488c2ecf20Sopenharmony_ci ath10k_debug_cal_data_fetch(ar); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci /* Must not use _sync to avoid deadlock, we do that in 17518c2ecf20Sopenharmony_ci * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid 17528c2ecf20Sopenharmony_ci * warning from del_timer(). 17538c2ecf20Sopenharmony_ci */ 17548c2ecf20Sopenharmony_ci if (ar->debug.htt_stats_mask != 0) 17558c2ecf20Sopenharmony_ci cancel_delayed_work(&ar->debug.htt_stats_dwork); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci ath10k_wmi_pdev_pktlog_disable(ar); 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_simulate_radar(struct file *file, 17618c2ecf20Sopenharmony_ci const char __user *user_buf, 17628c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 17638c2ecf20Sopenharmony_ci{ 17648c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 17658c2ecf20Sopenharmony_ci struct ath10k_vif *arvif; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci /* Just check for for the first vif alone, as all the vifs will be 17688c2ecf20Sopenharmony_ci * sharing the same channel and if the channel is disabled, all the 17698c2ecf20Sopenharmony_ci * vifs will share the same 'is_started' state. 17708c2ecf20Sopenharmony_ci */ 17718c2ecf20Sopenharmony_ci arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); 17728c2ecf20Sopenharmony_ci if (!arvif->is_started) 17738c2ecf20Sopenharmony_ci return -EINVAL; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci ieee80211_radar_detected(ar->hw); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci return count; 17788c2ecf20Sopenharmony_ci} 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_cistatic const struct file_operations fops_simulate_radar = { 17818c2ecf20Sopenharmony_ci .write = ath10k_write_simulate_radar, 17828c2ecf20Sopenharmony_ci .open = simple_open, 17838c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 17848c2ecf20Sopenharmony_ci .llseek = default_llseek, 17858c2ecf20Sopenharmony_ci}; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci#define ATH10K_DFS_STAT(s, p) (\ 17888c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ 17898c2ecf20Sopenharmony_ci ar->debug.dfs_stats.p)) 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci#define ATH10K_DFS_POOL_STAT(s, p) (\ 17928c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ 17938c2ecf20Sopenharmony_ci ar->debug.dfs_pool_stats.p)) 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf, 17968c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci int retval = 0, len = 0; 17998c2ecf20Sopenharmony_ci const int size = 8000; 18008c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 18018c2ecf20Sopenharmony_ci char *buf; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci buf = kzalloc(size, GFP_KERNEL); 18048c2ecf20Sopenharmony_ci if (buf == NULL) 18058c2ecf20Sopenharmony_ci return -ENOMEM; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (!ar->dfs_detector) { 18088c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "DFS not enabled\n"); 18098c2ecf20Sopenharmony_ci goto exit; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci ar->debug.dfs_pool_stats = 18138c2ecf20Sopenharmony_ci ar->dfs_detector->get_stats(ar->dfs_detector); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n"); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci ATH10K_DFS_STAT("reported phy errors", phy_errors); 18188c2ecf20Sopenharmony_ci ATH10K_DFS_STAT("pulse events reported", pulses_total); 18198c2ecf20Sopenharmony_ci ATH10K_DFS_STAT("DFS pulses detected", pulses_detected); 18208c2ecf20Sopenharmony_ci ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded); 18218c2ecf20Sopenharmony_ci ATH10K_DFS_STAT("Radars detected", radar_detected); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Global Pool statistics:\n"); 18248c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pool references", pool_reference); 18258c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated); 18268c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error); 18278c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used); 18288c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated); 18298c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error); 18308c2ecf20Sopenharmony_ci ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ciexit: 18338c2ecf20Sopenharmony_ci if (len > size) 18348c2ecf20Sopenharmony_ci len = size; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 18378c2ecf20Sopenharmony_ci kfree(buf); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci return retval; 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_cistatic const struct file_operations fops_dfs_stats = { 18438c2ecf20Sopenharmony_ci .read = ath10k_read_dfs_stats, 18448c2ecf20Sopenharmony_ci .open = simple_open, 18458c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 18468c2ecf20Sopenharmony_ci .llseek = default_llseek, 18478c2ecf20Sopenharmony_ci}; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_pktlog_filter(struct file *file, 18508c2ecf20Sopenharmony_ci const char __user *ubuf, 18518c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 18528c2ecf20Sopenharmony_ci{ 18538c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 18548c2ecf20Sopenharmony_ci u32 filter; 18558c2ecf20Sopenharmony_ci int ret; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci if (kstrtouint_from_user(ubuf, count, 0, &filter)) 18588c2ecf20Sopenharmony_ci return -EINVAL; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 18638c2ecf20Sopenharmony_ci ar->pktlog_filter = filter; 18648c2ecf20Sopenharmony_ci ret = count; 18658c2ecf20Sopenharmony_ci goto out; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (filter == ar->pktlog_filter) { 18698c2ecf20Sopenharmony_ci ret = count; 18708c2ecf20Sopenharmony_ci goto out; 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (filter) { 18748c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_enable(ar, filter); 18758c2ecf20Sopenharmony_ci if (ret) { 18768c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n", 18778c2ecf20Sopenharmony_ci ar->pktlog_filter, ret); 18788c2ecf20Sopenharmony_ci goto out; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci } else { 18818c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_disable(ar); 18828c2ecf20Sopenharmony_ci if (ret) { 18838c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); 18848c2ecf20Sopenharmony_ci goto out; 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci ar->pktlog_filter = filter; 18898c2ecf20Sopenharmony_ci ret = count; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ciout: 18928c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 18938c2ecf20Sopenharmony_ci return ret; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf, 18978c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci char buf[32]; 19008c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 19018c2ecf20Sopenharmony_ci int len = 0; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 19048c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%08x\n", 19058c2ecf20Sopenharmony_ci ar->pktlog_filter); 19068c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_cistatic const struct file_operations fops_pktlog_filter = { 19128c2ecf20Sopenharmony_ci .read = ath10k_read_pktlog_filter, 19138c2ecf20Sopenharmony_ci .write = ath10k_write_pktlog_filter, 19148c2ecf20Sopenharmony_ci .open = simple_open 19158c2ecf20Sopenharmony_ci}; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_quiet_period(struct file *file, 19188c2ecf20Sopenharmony_ci const char __user *ubuf, 19198c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 19228c2ecf20Sopenharmony_ci u32 period; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci if (kstrtouint_from_user(ubuf, count, 0, &period)) 19258c2ecf20Sopenharmony_ci return -EINVAL; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (period < ATH10K_QUIET_PERIOD_MIN) { 19288c2ecf20Sopenharmony_ci ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n", 19298c2ecf20Sopenharmony_ci period); 19308c2ecf20Sopenharmony_ci return -EINVAL; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 19338c2ecf20Sopenharmony_ci ar->thermal.quiet_period = period; 19348c2ecf20Sopenharmony_ci ath10k_thermal_set_throttling(ar); 19358c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci return count; 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf, 19418c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci char buf[32]; 19448c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 19458c2ecf20Sopenharmony_ci int len = 0; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 19488c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 19498c2ecf20Sopenharmony_ci ar->thermal.quiet_period); 19508c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic const struct file_operations fops_quiet_period = { 19568c2ecf20Sopenharmony_ci .read = ath10k_read_quiet_period, 19578c2ecf20Sopenharmony_ci .write = ath10k_write_quiet_period, 19588c2ecf20Sopenharmony_ci .open = simple_open 19598c2ecf20Sopenharmony_ci}; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_btcoex(struct file *file, 19628c2ecf20Sopenharmony_ci const char __user *ubuf, 19638c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 19668c2ecf20Sopenharmony_ci char buf[32]; 19678c2ecf20Sopenharmony_ci size_t buf_size; 19688c2ecf20Sopenharmony_ci int ret; 19698c2ecf20Sopenharmony_ci bool val; 19708c2ecf20Sopenharmony_ci u32 pdev_param; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci buf_size = min(count, (sizeof(buf) - 1)); 19738c2ecf20Sopenharmony_ci if (copy_from_user(buf, ubuf, buf_size)) 19748c2ecf20Sopenharmony_ci return -EFAULT; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci buf[buf_size] = '\0'; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (strtobool(buf, &val) != 0) 19798c2ecf20Sopenharmony_ci return -EINVAL; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci if (!ar->coex_support) 19828c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 19878c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_RESTARTED) { 19888c2ecf20Sopenharmony_ci ret = -ENETDOWN; 19898c2ecf20Sopenharmony_ci goto exit; 19908c2ecf20Sopenharmony_ci } 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) { 19938c2ecf20Sopenharmony_ci ret = count; 19948c2ecf20Sopenharmony_ci goto exit; 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci pdev_param = ar->wmi.pdev_param->enable_btcoex; 19988c2ecf20Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, 19998c2ecf20Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 20008c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val); 20018c2ecf20Sopenharmony_ci if (ret) { 20028c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to enable btcoex: %d\n", ret); 20038c2ecf20Sopenharmony_ci ret = count; 20048c2ecf20Sopenharmony_ci goto exit; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci } else { 20078c2ecf20Sopenharmony_ci ath10k_info(ar, "restarting firmware due to btcoex change"); 20088c2ecf20Sopenharmony_ci queue_work(ar->workqueue, &ar->restart_work); 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (val) 20128c2ecf20Sopenharmony_ci set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); 20138c2ecf20Sopenharmony_ci else 20148c2ecf20Sopenharmony_ci clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci ret = count; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ciexit: 20198c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci return ret; 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf, 20258c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 20268c2ecf20Sopenharmony_ci{ 20278c2ecf20Sopenharmony_ci char buf[32]; 20288c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 20298c2ecf20Sopenharmony_ci int len = 0; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 20328c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 20338c2ecf20Sopenharmony_ci test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags)); 20348c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 20378c2ecf20Sopenharmony_ci} 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_cistatic const struct file_operations fops_btcoex = { 20408c2ecf20Sopenharmony_ci .read = ath10k_read_btcoex, 20418c2ecf20Sopenharmony_ci .write = ath10k_write_btcoex, 20428c2ecf20Sopenharmony_ci .open = simple_open 20438c2ecf20Sopenharmony_ci}; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_enable_extd_tx_stats(struct file *file, 20468c2ecf20Sopenharmony_ci const char __user *ubuf, 20478c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 20508c2ecf20Sopenharmony_ci u32 filter; 20518c2ecf20Sopenharmony_ci int ret; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if (kstrtouint_from_user(ubuf, count, 0, &filter)) 20548c2ecf20Sopenharmony_ci return -EINVAL; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 20598c2ecf20Sopenharmony_ci ar->debug.enable_extd_tx_stats = filter; 20608c2ecf20Sopenharmony_ci ret = count; 20618c2ecf20Sopenharmony_ci goto out; 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci if (filter == ar->debug.enable_extd_tx_stats) { 20658c2ecf20Sopenharmony_ci ret = count; 20668c2ecf20Sopenharmony_ci goto out; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci ar->debug.enable_extd_tx_stats = filter; 20708c2ecf20Sopenharmony_ci ret = count; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ciout: 20738c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 20748c2ecf20Sopenharmony_ci return ret; 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_enable_extd_tx_stats(struct file *file, 20788c2ecf20Sopenharmony_ci char __user *ubuf, 20798c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci char buf[32]; 20838c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 20848c2ecf20Sopenharmony_ci int len = 0; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 20878c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%08x\n", 20888c2ecf20Sopenharmony_ci ar->debug.enable_extd_tx_stats); 20898c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_cistatic const struct file_operations fops_enable_extd_tx_stats = { 20958c2ecf20Sopenharmony_ci .read = ath10k_read_enable_extd_tx_stats, 20968c2ecf20Sopenharmony_ci .write = ath10k_write_enable_extd_tx_stats, 20978c2ecf20Sopenharmony_ci .open = simple_open 20988c2ecf20Sopenharmony_ci}; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_peer_stats(struct file *file, 21018c2ecf20Sopenharmony_ci const char __user *ubuf, 21028c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 21038c2ecf20Sopenharmony_ci{ 21048c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 21058c2ecf20Sopenharmony_ci char buf[32]; 21068c2ecf20Sopenharmony_ci size_t buf_size; 21078c2ecf20Sopenharmony_ci int ret; 21088c2ecf20Sopenharmony_ci bool val; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci buf_size = min(count, (sizeof(buf) - 1)); 21118c2ecf20Sopenharmony_ci if (copy_from_user(buf, ubuf, buf_size)) 21128c2ecf20Sopenharmony_ci return -EFAULT; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci buf[buf_size] = '\0'; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci if (strtobool(buf, &val) != 0) 21178c2ecf20Sopenharmony_ci return -EINVAL; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON && 21228c2ecf20Sopenharmony_ci ar->state != ATH10K_STATE_RESTARTED) { 21238c2ecf20Sopenharmony_ci ret = -ENETDOWN; 21248c2ecf20Sopenharmony_ci goto exit; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) { 21288c2ecf20Sopenharmony_ci ret = count; 21298c2ecf20Sopenharmony_ci goto exit; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (val) 21338c2ecf20Sopenharmony_ci set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags); 21348c2ecf20Sopenharmony_ci else 21358c2ecf20Sopenharmony_ci clear_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci ath10k_info(ar, "restarting firmware due to Peer stats change"); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci queue_work(ar->workqueue, &ar->restart_work); 21408c2ecf20Sopenharmony_ci ret = count; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ciexit: 21438c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 21448c2ecf20Sopenharmony_ci return ret; 21458c2ecf20Sopenharmony_ci} 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_peer_stats(struct file *file, char __user *ubuf, 21488c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci{ 21518c2ecf20Sopenharmony_ci char buf[32]; 21528c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 21538c2ecf20Sopenharmony_ci int len = 0; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 21568c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 21578c2ecf20Sopenharmony_ci test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags)); 21588c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 21618c2ecf20Sopenharmony_ci} 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_cistatic const struct file_operations fops_peer_stats = { 21648c2ecf20Sopenharmony_ci .read = ath10k_read_peer_stats, 21658c2ecf20Sopenharmony_ci .write = ath10k_write_peer_stats, 21668c2ecf20Sopenharmony_ci .open = simple_open 21678c2ecf20Sopenharmony_ci}; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_cistatic ssize_t ath10k_debug_fw_checksums_read(struct file *file, 21708c2ecf20Sopenharmony_ci char __user *user_buf, 21718c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 21728c2ecf20Sopenharmony_ci{ 21738c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 21748c2ecf20Sopenharmony_ci size_t len = 0, buf_len = 4096; 21758c2ecf20Sopenharmony_ci ssize_t ret_cnt; 21768c2ecf20Sopenharmony_ci char *buf; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 21798c2ecf20Sopenharmony_ci if (!buf) 21808c2ecf20Sopenharmony_ci return -ENOMEM; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 21858c2ecf20Sopenharmony_ci "firmware-N.bin\t\t%08x\n", 21868c2ecf20Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data, 21878c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.firmware->size)); 21888c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 21898c2ecf20Sopenharmony_ci "athwlan\t\t\t%08x\n", 21908c2ecf20Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data, 21918c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.firmware_len)); 21928c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 21938c2ecf20Sopenharmony_ci "otp\t\t\t%08x\n", 21948c2ecf20Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.otp_data, 21958c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.otp_len)); 21968c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 21978c2ecf20Sopenharmony_ci "codeswap\t\t%08x\n", 21988c2ecf20Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data, 21998c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.codeswap_len)); 22008c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 22018c2ecf20Sopenharmony_ci "board-N.bin\t\t%08x\n", 22028c2ecf20Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.board->data, 22038c2ecf20Sopenharmony_ci ar->normal_mode_fw.board->size)); 22048c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 22058c2ecf20Sopenharmony_ci "board\t\t\t%08x\n", 22068c2ecf20Sopenharmony_ci crc32_le(0, ar->normal_mode_fw.board_data, 22078c2ecf20Sopenharmony_ci ar->normal_mode_fw.board_len)); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci kfree(buf); 22148c2ecf20Sopenharmony_ci return ret_cnt; 22158c2ecf20Sopenharmony_ci} 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_cistatic const struct file_operations fops_fw_checksums = { 22188c2ecf20Sopenharmony_ci .read = ath10k_debug_fw_checksums_read, 22198c2ecf20Sopenharmony_ci .open = simple_open, 22208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 22218c2ecf20Sopenharmony_ci .llseek = default_llseek, 22228c2ecf20Sopenharmony_ci}; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cistatic ssize_t ath10k_sta_tid_stats_mask_read(struct file *file, 22258c2ecf20Sopenharmony_ci char __user *user_buf, 22268c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 22278c2ecf20Sopenharmony_ci{ 22288c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 22298c2ecf20Sopenharmony_ci char buf[32]; 22308c2ecf20Sopenharmony_ci size_t len; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask); 22338c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 22348c2ecf20Sopenharmony_ci} 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_cistatic ssize_t ath10k_sta_tid_stats_mask_write(struct file *file, 22378c2ecf20Sopenharmony_ci const char __user *user_buf, 22388c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 22418c2ecf20Sopenharmony_ci char buf[32]; 22428c2ecf20Sopenharmony_ci ssize_t len; 22438c2ecf20Sopenharmony_ci u32 mask; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci len = min(count, sizeof(buf) - 1); 22468c2ecf20Sopenharmony_ci if (copy_from_user(buf, user_buf, len)) 22478c2ecf20Sopenharmony_ci return -EFAULT; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci buf[len] = '\0'; 22508c2ecf20Sopenharmony_ci if (kstrtoint(buf, 0, &mask)) 22518c2ecf20Sopenharmony_ci return -EINVAL; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci ar->sta_tid_stats_mask = mask; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci return len; 22568c2ecf20Sopenharmony_ci} 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistatic const struct file_operations fops_sta_tid_stats_mask = { 22598c2ecf20Sopenharmony_ci .read = ath10k_sta_tid_stats_mask_read, 22608c2ecf20Sopenharmony_ci .write = ath10k_sta_tid_stats_mask_write, 22618c2ecf20Sopenharmony_ci .open = simple_open, 22628c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 22638c2ecf20Sopenharmony_ci .llseek = default_llseek, 22648c2ecf20Sopenharmony_ci}; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_cistatic int ath10k_debug_tpc_stats_final_request(struct ath10k *ar) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci int ret; 22698c2ecf20Sopenharmony_ci unsigned long time_left; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci reinit_completion(&ar->debug.tpc_complete); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM); 22768c2ecf20Sopenharmony_ci if (ret) { 22778c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret); 22788c2ecf20Sopenharmony_ci return ret; 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->debug.tpc_complete, 22828c2ecf20Sopenharmony_ci 1 * HZ); 22838c2ecf20Sopenharmony_ci if (time_left == 0) 22848c2ecf20Sopenharmony_ci return -ETIMEDOUT; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci return 0; 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_cistatic int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci struct ath10k *ar = inode->i_private; 22928c2ecf20Sopenharmony_ci void *buf; 22938c2ecf20Sopenharmony_ci int ret; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 22988c2ecf20Sopenharmony_ci ret = -ENETDOWN; 22998c2ecf20Sopenharmony_ci goto err_unlock; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE); 23038c2ecf20Sopenharmony_ci if (!buf) { 23048c2ecf20Sopenharmony_ci ret = -ENOMEM; 23058c2ecf20Sopenharmony_ci goto err_unlock; 23068c2ecf20Sopenharmony_ci } 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci ret = ath10k_debug_tpc_stats_final_request(ar); 23098c2ecf20Sopenharmony_ci if (ret) { 23108c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request tpc stats final: %d\n", 23118c2ecf20Sopenharmony_ci ret); 23128c2ecf20Sopenharmony_ci goto err_free; 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf); 23168c2ecf20Sopenharmony_ci file->private_data = buf; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 23198c2ecf20Sopenharmony_ci return 0; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_cierr_free: 23228c2ecf20Sopenharmony_ci vfree(buf); 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_cierr_unlock: 23258c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 23268c2ecf20Sopenharmony_ci return ret; 23278c2ecf20Sopenharmony_ci} 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_cistatic int ath10k_tpc_stats_final_release(struct inode *inode, 23308c2ecf20Sopenharmony_ci struct file *file) 23318c2ecf20Sopenharmony_ci{ 23328c2ecf20Sopenharmony_ci vfree(file->private_data); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci return 0; 23358c2ecf20Sopenharmony_ci} 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_cistatic ssize_t ath10k_tpc_stats_final_read(struct file *file, 23388c2ecf20Sopenharmony_ci char __user *user_buf, 23398c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci const char *buf = file->private_data; 23428c2ecf20Sopenharmony_ci unsigned int len = strlen(buf); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 23458c2ecf20Sopenharmony_ci} 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_cistatic const struct file_operations fops_tpc_stats_final = { 23488c2ecf20Sopenharmony_ci .open = ath10k_tpc_stats_final_open, 23498c2ecf20Sopenharmony_ci .release = ath10k_tpc_stats_final_release, 23508c2ecf20Sopenharmony_ci .read = ath10k_tpc_stats_final_read, 23518c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 23528c2ecf20Sopenharmony_ci .llseek = default_llseek, 23538c2ecf20Sopenharmony_ci}; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_warm_hw_reset(struct file *file, 23568c2ecf20Sopenharmony_ci const char __user *user_buf, 23578c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 23588c2ecf20Sopenharmony_ci{ 23598c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 23608c2ecf20Sopenharmony_ci int ret; 23618c2ecf20Sopenharmony_ci bool val; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci if (kstrtobool_from_user(user_buf, count, &val)) 23648c2ecf20Sopenharmony_ci return -EFAULT; 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci if (!val) 23678c2ecf20Sopenharmony_ci return -EINVAL; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 23728c2ecf20Sopenharmony_ci ret = -ENETDOWN; 23738c2ecf20Sopenharmony_ci goto exit; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pdev_reset, 23778c2ecf20Sopenharmony_ci WMI_RST_MODE_WARM_RESET); 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci if (ret) { 23808c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to enable warm hw reset: %d\n", ret); 23818c2ecf20Sopenharmony_ci goto exit; 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci ret = count; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ciexit: 23878c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 23888c2ecf20Sopenharmony_ci return ret; 23898c2ecf20Sopenharmony_ci} 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_cistatic const struct file_operations fops_warm_hw_reset = { 23928c2ecf20Sopenharmony_ci .write = ath10k_write_warm_hw_reset, 23938c2ecf20Sopenharmony_ci .open = simple_open, 23948c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 23958c2ecf20Sopenharmony_ci .llseek = default_llseek, 23968c2ecf20Sopenharmony_ci}; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_cistatic void ath10k_peer_ps_state_disable(void *data, 23998c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 24008c2ecf20Sopenharmony_ci{ 24018c2ecf20Sopenharmony_ci struct ath10k *ar = data; 24028c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 24058c2ecf20Sopenharmony_ci arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; 24068c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 24078c2ecf20Sopenharmony_ci} 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_ps_state_enable(struct file *file, 24108c2ecf20Sopenharmony_ci const char __user *user_buf, 24118c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 24148c2ecf20Sopenharmony_ci int ret; 24158c2ecf20Sopenharmony_ci u32 param; 24168c2ecf20Sopenharmony_ci u8 ps_state_enable; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable)) 24198c2ecf20Sopenharmony_ci return -EINVAL; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci if (ps_state_enable > 1) 24228c2ecf20Sopenharmony_ci return -EINVAL; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci if (ar->ps_state_enable == ps_state_enable) { 24278c2ecf20Sopenharmony_ci ret = count; 24288c2ecf20Sopenharmony_ci goto exit; 24298c2ecf20Sopenharmony_ci } 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable; 24328c2ecf20Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable); 24338c2ecf20Sopenharmony_ci if (ret) { 24348c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to enable ps_state_enable: %d\n", 24358c2ecf20Sopenharmony_ci ret); 24368c2ecf20Sopenharmony_ci goto exit; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci ar->ps_state_enable = ps_state_enable; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci if (!ar->ps_state_enable) 24418c2ecf20Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 24428c2ecf20Sopenharmony_ci ath10k_peer_ps_state_disable, 24438c2ecf20Sopenharmony_ci ar); 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci ret = count; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ciexit: 24488c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci return ret; 24518c2ecf20Sopenharmony_ci} 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_cistatic ssize_t ath10k_read_ps_state_enable(struct file *file, 24548c2ecf20Sopenharmony_ci char __user *user_buf, 24558c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 24568c2ecf20Sopenharmony_ci{ 24578c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 24588c2ecf20Sopenharmony_ci int len = 0; 24598c2ecf20Sopenharmony_ci char buf[32]; 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 24628c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 24638c2ecf20Sopenharmony_ci ar->ps_state_enable); 24648c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cistatic const struct file_operations fops_ps_state_enable = { 24708c2ecf20Sopenharmony_ci .read = ath10k_read_ps_state_enable, 24718c2ecf20Sopenharmony_ci .write = ath10k_write_ps_state_enable, 24728c2ecf20Sopenharmony_ci .open = simple_open, 24738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 24748c2ecf20Sopenharmony_ci .llseek = default_llseek, 24758c2ecf20Sopenharmony_ci}; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_cistatic ssize_t ath10k_write_reset_htt_stats(struct file *file, 24788c2ecf20Sopenharmony_ci const char __user *user_buf, 24798c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 24808c2ecf20Sopenharmony_ci{ 24818c2ecf20Sopenharmony_ci struct ath10k *ar = file->private_data; 24828c2ecf20Sopenharmony_ci unsigned long reset; 24838c2ecf20Sopenharmony_ci int ret; 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci ret = kstrtoul_from_user(user_buf, count, 0, &reset); 24868c2ecf20Sopenharmony_ci if (ret) 24878c2ecf20Sopenharmony_ci return ret; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci if (reset == 0 || reset > 0x1ffff) 24908c2ecf20Sopenharmony_ci return -EINVAL; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci ar->debug.reset_htt_stats = reset; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci ret = ath10k_debug_htt_stats_req(ar); 24978c2ecf20Sopenharmony_ci if (ret) 24988c2ecf20Sopenharmony_ci goto out; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci ar->debug.reset_htt_stats = 0; 25018c2ecf20Sopenharmony_ci ret = count; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ciout: 25048c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 25058c2ecf20Sopenharmony_ci return ret; 25068c2ecf20Sopenharmony_ci} 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_cistatic const struct file_operations fops_reset_htt_stats = { 25098c2ecf20Sopenharmony_ci .write = ath10k_write_reset_htt_stats, 25108c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 25118c2ecf20Sopenharmony_ci .open = simple_open, 25128c2ecf20Sopenharmony_ci .llseek = default_llseek, 25138c2ecf20Sopenharmony_ci}; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ciint ath10k_debug_create(struct ath10k *ar) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); 25188c2ecf20Sopenharmony_ci if (!ar->debug.cal_data) 25198c2ecf20Sopenharmony_ci return -ENOMEM; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); 25228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs); 25238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.peers); 25248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd); 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci return 0; 25278c2ecf20Sopenharmony_ci} 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_civoid ath10k_debug_destroy(struct ath10k *ar) 25308c2ecf20Sopenharmony_ci{ 25318c2ecf20Sopenharmony_ci vfree(ar->debug.cal_data); 25328c2ecf20Sopenharmony_ci ar->debug.cal_data = NULL; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci ath10k_debug_fw_stats_reset(ar); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci kfree(ar->debug.tpc_stats); 25378c2ecf20Sopenharmony_ci kfree(ar->debug.tpc_stats_final); 25388c2ecf20Sopenharmony_ci} 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ciint ath10k_debug_register(struct ath10k *ar) 25418c2ecf20Sopenharmony_ci{ 25428c2ecf20Sopenharmony_ci ar->debug.debugfs_phy = debugfs_create_dir("ath10k", 25438c2ecf20Sopenharmony_ci ar->hw->wiphy->debugfsdir); 25448c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) { 25458c2ecf20Sopenharmony_ci if (IS_ERR(ar->debug.debugfs_phy)) 25468c2ecf20Sopenharmony_ci return PTR_ERR(ar->debug.debugfs_phy); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci return -ENOMEM; 25498c2ecf20Sopenharmony_ci } 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, 25528c2ecf20Sopenharmony_ci ath10k_debug_htt_stats_dwork); 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci init_completion(&ar->debug.tpc_complete); 25558c2ecf20Sopenharmony_ci init_completion(&ar->debug.fw_stats_complete); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar, 25588c2ecf20Sopenharmony_ci &fops_fw_stats); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci debugfs_create_file("fw_reset_stats", 0400, ar->debug.debugfs_phy, ar, 25618c2ecf20Sopenharmony_ci &fops_fw_reset_stats); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar, 25648c2ecf20Sopenharmony_ci &fops_wmi_services); 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar, 25678c2ecf20Sopenharmony_ci &fops_simulate_fw_crash); 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar, 25708c2ecf20Sopenharmony_ci &fops_reg_addr); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci debugfs_create_file("reg_value", 0600, ar->debug.debugfs_phy, ar, 25738c2ecf20Sopenharmony_ci &fops_reg_value); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci debugfs_create_file("mem_value", 0600, ar->debug.debugfs_phy, ar, 25768c2ecf20Sopenharmony_ci &fops_mem_value); 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci debugfs_create_file("chip_id", 0400, ar->debug.debugfs_phy, ar, 25798c2ecf20Sopenharmony_ci &fops_chip_id); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci debugfs_create_file("htt_stats_mask", 0600, ar->debug.debugfs_phy, ar, 25828c2ecf20Sopenharmony_ci &fops_htt_stats_mask); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci debugfs_create_file("htt_max_amsdu_ampdu", 0600, ar->debug.debugfs_phy, ar, 25858c2ecf20Sopenharmony_ci &fops_htt_max_amsdu_ampdu); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar, 25888c2ecf20Sopenharmony_ci &fops_fw_dbglog); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, 25918c2ecf20Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features)) { 25928c2ecf20Sopenharmony_ci debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar, 25938c2ecf20Sopenharmony_ci &fops_cal_data); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar, 25968c2ecf20Sopenharmony_ci &fops_nf_cal_period); 25978c2ecf20Sopenharmony_ci } 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar, 26008c2ecf20Sopenharmony_ci &fops_ani_enable); 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { 26038c2ecf20Sopenharmony_ci debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy, 26048c2ecf20Sopenharmony_ci ar, &fops_simulate_radar); 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci debugfs_create_bool("dfs_block_radar_events", 0200, 26078c2ecf20Sopenharmony_ci ar->debug.debugfs_phy, 26088c2ecf20Sopenharmony_ci &ar->dfs_block_radar_events); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci debugfs_create_file("dfs_stats", 0400, ar->debug.debugfs_phy, ar, 26118c2ecf20Sopenharmony_ci &fops_dfs_stats); 26128c2ecf20Sopenharmony_ci } 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar, 26158c2ecf20Sopenharmony_ci &fops_pktlog_filter); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci if (test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map)) 26188c2ecf20Sopenharmony_ci debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar, 26198c2ecf20Sopenharmony_ci &fops_quiet_period); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar, 26228c2ecf20Sopenharmony_ci &fops_tpc_stats); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map)) 26258c2ecf20Sopenharmony_ci debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar, 26268c2ecf20Sopenharmony_ci &fops_btcoex); 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) { 26298c2ecf20Sopenharmony_ci debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar, 26308c2ecf20Sopenharmony_ci &fops_peer_stats); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci debugfs_create_file("enable_extd_tx_stats", 0644, 26338c2ecf20Sopenharmony_ci ar->debug.debugfs_phy, ar, 26348c2ecf20Sopenharmony_ci &fops_enable_extd_tx_stats); 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar, 26388c2ecf20Sopenharmony_ci &fops_fw_checksums); 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS)) 26418c2ecf20Sopenharmony_ci debugfs_create_file("sta_tid_stats_mask", 0600, 26428c2ecf20Sopenharmony_ci ar->debug.debugfs_phy, 26438c2ecf20Sopenharmony_ci ar, &fops_sta_tid_stats_mask); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map)) 26468c2ecf20Sopenharmony_ci debugfs_create_file("tpc_stats_final", 0400, 26478c2ecf20Sopenharmony_ci ar->debug.debugfs_phy, ar, 26488c2ecf20Sopenharmony_ci &fops_tpc_stats_final); 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci if (test_bit(WMI_SERVICE_RESET_CHIP, ar->wmi.svc_map)) 26518c2ecf20Sopenharmony_ci debugfs_create_file("warm_hw_reset", 0600, 26528c2ecf20Sopenharmony_ci ar->debug.debugfs_phy, ar, 26538c2ecf20Sopenharmony_ci &fops_warm_hw_reset); 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar, 26568c2ecf20Sopenharmony_ci &fops_ps_state_enable); 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar, 26598c2ecf20Sopenharmony_ci &fops_reset_htt_stats); 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci return 0; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_civoid ath10k_debug_unregister(struct ath10k *ar) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); 26678c2ecf20Sopenharmony_ci} 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci#endif /* CONFIG_ATH10K_DEBUGFS */ 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH10K_DEBUG 26728c2ecf20Sopenharmony_civoid __ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask, 26738c2ecf20Sopenharmony_ci const char *fmt, ...) 26748c2ecf20Sopenharmony_ci{ 26758c2ecf20Sopenharmony_ci struct va_format vaf; 26768c2ecf20Sopenharmony_ci va_list args; 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ci va_start(args, fmt); 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci vaf.fmt = fmt; 26818c2ecf20Sopenharmony_ci vaf.va = &args; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci if (ath10k_debug_mask & mask) 26848c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf); 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci trace_ath10k_log_dbg(ar, mask, &vaf); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci va_end(args); 26898c2ecf20Sopenharmony_ci} 26908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__ath10k_dbg); 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_civoid ath10k_dbg_dump(struct ath10k *ar, 26938c2ecf20Sopenharmony_ci enum ath10k_debug_mask mask, 26948c2ecf20Sopenharmony_ci const char *msg, const char *prefix, 26958c2ecf20Sopenharmony_ci const void *buf, size_t len) 26968c2ecf20Sopenharmony_ci{ 26978c2ecf20Sopenharmony_ci char linebuf[256]; 26988c2ecf20Sopenharmony_ci size_t linebuflen; 26998c2ecf20Sopenharmony_ci const void *ptr; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci if (ath10k_debug_mask & mask) { 27028c2ecf20Sopenharmony_ci if (msg) 27038c2ecf20Sopenharmony_ci __ath10k_dbg(ar, mask, "%s\n", msg); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci for (ptr = buf; (ptr - buf) < len; ptr += 16) { 27068c2ecf20Sopenharmony_ci linebuflen = 0; 27078c2ecf20Sopenharmony_ci linebuflen += scnprintf(linebuf + linebuflen, 27088c2ecf20Sopenharmony_ci sizeof(linebuf) - linebuflen, 27098c2ecf20Sopenharmony_ci "%s%08x: ", 27108c2ecf20Sopenharmony_ci (prefix ? prefix : ""), 27118c2ecf20Sopenharmony_ci (unsigned int)(ptr - buf)); 27128c2ecf20Sopenharmony_ci hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1, 27138c2ecf20Sopenharmony_ci linebuf + linebuflen, 27148c2ecf20Sopenharmony_ci sizeof(linebuf) - linebuflen, true); 27158c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf); 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci } 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci /* tracing code doesn't like null strings :/ */ 27208c2ecf20Sopenharmony_ci trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "", 27218c2ecf20Sopenharmony_ci buf, len); 27228c2ecf20Sopenharmony_ci} 27238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath10k_dbg_dump); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci#endif /* CONFIG_ATH10K_DEBUG */ 2726