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