xref: /linux/drivers/net/wireless/ath/ath10k/debug.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1f0553ca9SKalle Valo // SPDX-License-Identifier: ISC
25e3dd157SKalle Valo /*
35e3dd157SKalle Valo  * Copyright (c) 2005-2011 Atheros Communications Inc.
48b1083d6SKalle Valo  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
550e79e25SYu Wang  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
6*b1dc0ba4SJeff Johnson  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
75e3dd157SKalle Valo  */
85e3dd157SKalle Valo 
95e3dd157SKalle Valo #include <linux/module.h>
105e3dd157SKalle Valo #include <linux/debugfs.h>
11384914b2SBen Greear #include <linux/vmalloc.h>
123e58044bSKalle Valo #include <linux/crc32.h>
133e58044bSKalle Valo #include <linux/firmware.h>
14417f1735SChristophe JAILLET #include <linux/kstrtox.h>
155e3dd157SKalle Valo 
165e3dd157SKalle Valo #include "core.h"
175e3dd157SKalle Valo #include "debug.h"
187869b4faSKalle Valo #include "hif.h"
19d7579d12SMichal Kazior #include "wmi-ops.h"
205e3dd157SKalle Valo 
21a3d135e5SKalle Valo /* ms */
22a3d135e5SKalle Valo #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
23a3d135e5SKalle Valo 
24f67b107dSMarty Faltesek #define ATH10K_DEBUG_CAL_DATA_LEN 12064
25f67b107dSMarty Faltesek 
ath10k_info(struct ath10k * ar,const char * fmt,...)26babcb3edSJoe Perches void ath10k_info(struct ath10k *ar, const char *fmt, ...)
275e3dd157SKalle Valo {
285e3dd157SKalle Valo 	struct va_format vaf = {
295e3dd157SKalle Valo 		.fmt = fmt,
305e3dd157SKalle Valo 	};
315e3dd157SKalle Valo 	va_list args;
325e3dd157SKalle Valo 
335e3dd157SKalle Valo 	va_start(args, fmt);
345e3dd157SKalle Valo 	vaf.va = &args;
35babcb3edSJoe Perches 	dev_info(ar->dev, "%pV", &vaf);
36d35a6c18SMichal Kazior 	trace_ath10k_log_info(ar, &vaf);
375e3dd157SKalle Valo 	va_end(args);
385e3dd157SKalle Valo }
395e3dd157SKalle Valo EXPORT_SYMBOL(ath10k_info);
405e3dd157SKalle Valo 
ath10k_debug_print_hwfw_info(struct ath10k * ar)4123f591eaSKalle Valo void ath10k_debug_print_hwfw_info(struct ath10k *ar)
428a0c797eSKalle Valo {
437ebf721dSKalle Valo 	const struct firmware *firmware;
4484e3df60SMichal Kazior 	char fw_features[128] = {};
458866c727SMichal Kazior 	u32 crc = 0;
46b27bc5a4SMichal Kazior 
47b27bc5a4SMichal Kazior 	ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features));
48b27bc5a4SMichal Kazior 
498605c022SKalle Valo 	ath10k_info(ar, "%s target 0x%08x chip_id 0x%08x sub %04x:%04x",
508a0c797eSKalle Valo 		    ar->hw_params.name,
518a0c797eSKalle Valo 		    ar->target_version,
52de8781d7SGovind Singh 		    ar->bus_param.chip_id,
538605c022SKalle Valo 		    ar->id.subsystem_vendor, ar->id.subsystem_device);
54f0de90bcSKalle Valo 
55f0de90bcSKalle Valo 	ath10k_info(ar, "kconfig debug %d debugfs %d tracing %d dfs %d testmode %d\n",
5697f2645fSMasahiro Yamada 		    IS_ENABLED(CONFIG_ATH10K_DEBUG),
5797f2645fSMasahiro Yamada 		    IS_ENABLED(CONFIG_ATH10K_DEBUGFS),
5897f2645fSMasahiro Yamada 		    IS_ENABLED(CONFIG_ATH10K_TRACING),
5997f2645fSMasahiro Yamada 		    IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED),
6097f2645fSMasahiro Yamada 		    IS_ENABLED(CONFIG_NL80211_TESTMODE));
61f0de90bcSKalle Valo 
627ebf721dSKalle Valo 	firmware = ar->normal_mode_fw.fw_file.firmware;
637ebf721dSKalle Valo 	if (firmware)
647ebf721dSKalle Valo 		crc = crc32_le(0, firmware->data, firmware->size);
658866c727SMichal Kazior 
663e58044bSKalle Valo 	ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",
6723f591eaSKalle Valo 		    ar->hw->wiphy->fw_version,
6823f591eaSKalle Valo 		    ar->fw_api,
693e58044bSKalle Valo 		    fw_features,
708866c727SMichal Kazior 		    crc);
7123f591eaSKalle Valo }
7223f591eaSKalle Valo 
ath10k_debug_print_board_info(struct ath10k * ar)7323f591eaSKalle Valo void ath10k_debug_print_board_info(struct ath10k *ar)
7423f591eaSKalle Valo {
7523f591eaSKalle Valo 	char boardinfo[100];
7650e79e25SYu Wang 	const struct firmware *board;
7750e79e25SYu Wang 	u32 crc;
7823f591eaSKalle Valo 
7923f591eaSKalle Valo 	if (ar->id.bmi_ids_valid)
8023f591eaSKalle Valo 		scnprintf(boardinfo, sizeof(boardinfo), "%d:%d",
8123f591eaSKalle Valo 			  ar->id.bmi_chip_id, ar->id.bmi_board_id);
8223f591eaSKalle Valo 	else
8323f591eaSKalle Valo 		scnprintf(boardinfo, sizeof(boardinfo), "N/A");
8423f591eaSKalle Valo 
8550e79e25SYu Wang 	board = ar->normal_mode_fw.board;
8650e79e25SYu Wang 	if (!IS_ERR_OR_NULL(board))
8750e79e25SYu Wang 		crc = crc32_le(0, board->data, board->size);
8850e79e25SYu Wang 	else
8950e79e25SYu Wang 		crc = 0;
9050e79e25SYu Wang 
913e58044bSKalle Valo 	ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x",
9223f591eaSKalle Valo 		    ar->bd_api,
933e58044bSKalle Valo 		    boardinfo,
9450e79e25SYu Wang 		    crc);
9523f591eaSKalle Valo }
9623f591eaSKalle Valo 
ath10k_debug_print_boot_info(struct ath10k * ar)9723f591eaSKalle Valo void ath10k_debug_print_boot_info(struct ath10k *ar)
9823f591eaSKalle Valo {
99f0de90bcSKalle Valo 	ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n",
1008a0c797eSKalle Valo 		    ar->htt.target_version_major,
10134b28b6eSMichal Kazior 		    ar->htt.target_version_minor,
102bf3c13abSKalle Valo 		    ar->normal_mode_fw.fw_file.wmi_op_version,
10377561f93SKalle Valo 		    ar->normal_mode_fw.fw_file.htt_op_version,
104cfd1061eSMichal Kazior 		    ath10k_cal_mode_str(ar->cal_mode),
105b27bc5a4SMichal Kazior 		    ar->max_num_stations,
106ccec9038SDavid Liu 		    test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),
107f0de90bcSKalle Valo 		    !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags));
1088a0c797eSKalle Valo }
10923f591eaSKalle Valo 
ath10k_print_driver_info(struct ath10k * ar)11023f591eaSKalle Valo void ath10k_print_driver_info(struct ath10k *ar)
11123f591eaSKalle Valo {
11223f591eaSKalle Valo 	ath10k_debug_print_hwfw_info(ar);
11323f591eaSKalle Valo 	ath10k_debug_print_board_info(ar);
11423f591eaSKalle Valo 	ath10k_debug_print_boot_info(ar);
11523f591eaSKalle Valo }
1168a0c797eSKalle Valo EXPORT_SYMBOL(ath10k_print_driver_info);
1178a0c797eSKalle Valo 
ath10k_err(struct ath10k * ar,const char * fmt,...)118babcb3edSJoe Perches void ath10k_err(struct ath10k *ar, const char *fmt, ...)
1195e3dd157SKalle Valo {
1205e3dd157SKalle Valo 	struct va_format vaf = {
1215e3dd157SKalle Valo 		.fmt = fmt,
1225e3dd157SKalle Valo 	};
1235e3dd157SKalle Valo 	va_list args;
1245e3dd157SKalle Valo 
1255e3dd157SKalle Valo 	va_start(args, fmt);
1265e3dd157SKalle Valo 	vaf.va = &args;
127babcb3edSJoe Perches 	dev_err(ar->dev, "%pV", &vaf);
128d35a6c18SMichal Kazior 	trace_ath10k_log_err(ar, &vaf);
1295e3dd157SKalle Valo 	va_end(args);
1305e3dd157SKalle Valo }
1315e3dd157SKalle Valo EXPORT_SYMBOL(ath10k_err);
1325e3dd157SKalle Valo 
ath10k_warn(struct ath10k * ar,const char * fmt,...)133babcb3edSJoe Perches void ath10k_warn(struct ath10k *ar, const char *fmt, ...)
1345e3dd157SKalle Valo {
1355e3dd157SKalle Valo 	struct va_format vaf = {
1365e3dd157SKalle Valo 		.fmt = fmt,
1375e3dd157SKalle Valo 	};
1385e3dd157SKalle Valo 	va_list args;
1395e3dd157SKalle Valo 
1405e3dd157SKalle Valo 	va_start(args, fmt);
1415e3dd157SKalle Valo 	vaf.va = &args;
1427aa7a72aSMichal Kazior 	dev_warn_ratelimited(ar->dev, "%pV", &vaf);
143d35a6c18SMichal Kazior 	trace_ath10k_log_warn(ar, &vaf);
1445e3dd157SKalle Valo 
1455e3dd157SKalle Valo 	va_end(args);
1465e3dd157SKalle Valo }
1475e3dd157SKalle Valo EXPORT_SYMBOL(ath10k_warn);
1485e3dd157SKalle Valo 
1495e3dd157SKalle Valo #ifdef CONFIG_ATH10K_DEBUGFS
1505e3dd157SKalle Valo 
ath10k_read_wmi_services(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1515e3dd157SKalle Valo static ssize_t ath10k_read_wmi_services(struct file *file,
1525e3dd157SKalle Valo 					char __user *user_buf,
1535e3dd157SKalle Valo 					size_t count, loff_t *ppos)
1545e3dd157SKalle Valo {
1555e3dd157SKalle Valo 	struct ath10k *ar = file->private_data;
1565e3dd157SKalle Valo 	char *buf;
15775e0dde2STamizh chelvam 	size_t len = 0, buf_len = 8192;
158cff990ceSMichal Kazior 	const char *name;
1595e3dd157SKalle Valo 	ssize_t ret_cnt;
160cff990ceSMichal Kazior 	bool enabled;
1615e3dd157SKalle Valo 	int i;
1625e3dd157SKalle Valo 
1635e3dd157SKalle Valo 	buf = kzalloc(buf_len, GFP_KERNEL);
1645e3dd157SKalle Valo 	if (!buf)
1655e3dd157SKalle Valo 		return -ENOMEM;
1665e3dd157SKalle Valo 
1675e3dd157SKalle Valo 	mutex_lock(&ar->conf_mutex);
1685e3dd157SKalle Valo 
169acfe7ecfSMichal Kazior 	spin_lock_bh(&ar->data_lock);
170c4f8c836SMichal Kazior 	for (i = 0; i < WMI_SERVICE_MAX; i++) {
171acfe7ecfSMichal Kazior 		enabled = test_bit(i, ar->wmi.svc_map);
172cff990ceSMichal Kazior 		name = wmi_service_name(i);
173cff990ceSMichal Kazior 
174cff990ceSMichal Kazior 		if (!name) {
175cff990ceSMichal Kazior 			if (enabled)
176cff990ceSMichal Kazior 				len += scnprintf(buf + len, buf_len - len,
177cff990ceSMichal Kazior 						 "%-40s %s (bit %d)\n",
178cff990ceSMichal Kazior 						 "unknown", "enabled", i);
179cff990ceSMichal Kazior 
180cff990ceSMichal Kazior 			continue;
181cff990ceSMichal Kazior 		}
1825e3dd157SKalle Valo 
1835e3dd157SKalle Valo 		len += scnprintf(buf + len, buf_len - len,
184cff990ceSMichal Kazior 				 "%-40s %s\n",
185cff990ceSMichal Kazior 				 name, enabled ? "enabled" : "-");
1865e3dd157SKalle Valo 	}
187acfe7ecfSMichal Kazior 	spin_unlock_bh(&ar->data_lock);
1885e3dd157SKalle Valo 
1895e3dd157SKalle Valo 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1905e3dd157SKalle Valo 
1915e3dd157SKalle Valo 	mutex_unlock(&ar->conf_mutex);
1925e3dd157SKalle Valo 
1935e3dd157SKalle Valo 	kfree(buf);
1945e3dd157SKalle Valo 	return ret_cnt;
1955e3dd157SKalle Valo }
1965e3dd157SKalle Valo 
1975e3dd157SKalle Valo static const struct file_operations fops_wmi_services = {
1985e3dd157SKalle Valo 	.read = ath10k_read_wmi_services,
1995e3dd157SKalle Valo 	.open = simple_open,
2005e3dd157SKalle Valo 	.owner = THIS_MODULE,
2015e3dd157SKalle Valo 	.llseek = default_llseek,
2025e3dd157SKalle Valo };
2035e3dd157SKalle Valo 
ath10k_fw_stats_pdevs_free(struct list_head * head)204b4619ea2SMohammed Shafi Shajakhan static void ath10k_fw_stats_pdevs_free(struct list_head *head)
2055326849aSMichal Kazior {
2065326849aSMichal Kazior 	struct ath10k_fw_stats_pdev *i, *tmp;
2075326849aSMichal Kazior 
2085326849aSMichal Kazior 	list_for_each_entry_safe(i, tmp, head, list) {
2095326849aSMichal Kazior 		list_del(&i->list);
2105326849aSMichal Kazior 		kfree(i);
2115326849aSMichal Kazior 	}
2125326849aSMichal Kazior }
2135326849aSMichal Kazior 
ath10k_fw_stats_vdevs_free(struct list_head * head)214b4619ea2SMohammed Shafi Shajakhan static void ath10k_fw_stats_vdevs_free(struct list_head *head)
2157b6b153aSMichal Kazior {
2167b6b153aSMichal Kazior 	struct ath10k_fw_stats_vdev *i, *tmp;
2177b6b153aSMichal Kazior 
2187b6b153aSMichal Kazior 	list_for_each_entry_safe(i, tmp, head, list) {
2197b6b153aSMichal Kazior 		list_del(&i->list);
2207b6b153aSMichal Kazior 		kfree(i);
2217b6b153aSMichal Kazior 	}
2227b6b153aSMichal Kazior }
2237b6b153aSMichal Kazior 
ath10k_fw_stats_peers_free(struct list_head * head)224b4619ea2SMohammed Shafi Shajakhan static void ath10k_fw_stats_peers_free(struct list_head *head)
2255326849aSMichal Kazior {
2265326849aSMichal Kazior 	struct ath10k_fw_stats_peer *i, *tmp;
2275326849aSMichal Kazior 
2285326849aSMichal Kazior 	list_for_each_entry_safe(i, tmp, head, list) {
2295326849aSMichal Kazior 		list_del(&i->list);
2305326849aSMichal Kazior 		kfree(i);
2315326849aSMichal Kazior 	}
2325326849aSMichal Kazior }
2335326849aSMichal Kazior 
ath10k_fw_extd_stats_peers_free(struct list_head * head)2344a49ae94SMohammed Shafi Shajakhan static void ath10k_fw_extd_stats_peers_free(struct list_head *head)
2354a49ae94SMohammed Shafi Shajakhan {
2364a49ae94SMohammed Shafi Shajakhan 	struct ath10k_fw_extd_stats_peer *i, *tmp;
2374a49ae94SMohammed Shafi Shajakhan 
2384a49ae94SMohammed Shafi Shajakhan 	list_for_each_entry_safe(i, tmp, head, list) {
2394a49ae94SMohammed Shafi Shajakhan 		list_del(&i->list);
2404a49ae94SMohammed Shafi Shajakhan 		kfree(i);
2414a49ae94SMohammed Shafi Shajakhan 	}
2424a49ae94SMohammed Shafi Shajakhan }
2434a49ae94SMohammed Shafi Shajakhan 
ath10k_debug_fw_stats_reset(struct ath10k * ar)2445326849aSMichal Kazior static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
2455326849aSMichal Kazior {
2465326849aSMichal Kazior 	spin_lock_bh(&ar->data_lock);
2475326849aSMichal Kazior 	ar->debug.fw_stats_done = false;
2484a49ae94SMohammed Shafi Shajakhan 	ar->debug.fw_stats.extended = false;
249b4619ea2SMohammed Shafi Shajakhan 	ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
250b4619ea2SMohammed Shafi Shajakhan 	ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
251b4619ea2SMohammed Shafi Shajakhan 	ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
2524a49ae94SMohammed Shafi Shajakhan 	ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
2535326849aSMichal Kazior 	spin_unlock_bh(&ar->data_lock);
2545326849aSMichal Kazior }
2555326849aSMichal Kazior 
ath10k_debug_fw_stats_process(struct ath10k * ar,struct sk_buff * skb)25660ef401aSMichal Kazior void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
2575e3dd157SKalle Valo {
2585326849aSMichal Kazior 	struct ath10k_fw_stats stats = {};
259cc61a1bbSMohammed Shafi Shajakhan 	bool is_start, is_started, is_end;
2605326849aSMichal Kazior 	size_t num_peers;
2617b6b153aSMichal Kazior 	size_t num_vdevs;
262d15fb520SMichal Kazior 	int ret;
2635e3dd157SKalle Valo 
2645326849aSMichal Kazior 	INIT_LIST_HEAD(&stats.pdevs);
2657b6b153aSMichal Kazior 	INIT_LIST_HEAD(&stats.vdevs);
2665326849aSMichal Kazior 	INIT_LIST_HEAD(&stats.peers);
2674a49ae94SMohammed Shafi Shajakhan 	INIT_LIST_HEAD(&stats.peers_extd);
2685e3dd157SKalle Valo 
2695326849aSMichal Kazior 	spin_lock_bh(&ar->data_lock);
2705326849aSMichal Kazior 	ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
271d15fb520SMichal Kazior 	if (ret) {
272d15fb520SMichal Kazior 		ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);
2735db879aeSRaja Mani 		goto free;
2745e3dd157SKalle Valo 	}
2755e3dd157SKalle Valo 
2765326849aSMichal Kazior 	/* Stat data may exceed htc-wmi buffer limit. In such case firmware
2775326849aSMichal Kazior 	 * splits the stats data and delivers it in a ping-pong fashion of
2785326849aSMichal Kazior 	 * request cmd-update event.
2795326849aSMichal Kazior 	 *
2805326849aSMichal Kazior 	 * However there is no explicit end-of-data. Instead start-of-data is
2815326849aSMichal Kazior 	 * used as an implicit one. This works as follows:
2825326849aSMichal Kazior 	 *  a) discard stat update events until one with pdev stats is
2835326849aSMichal Kazior 	 *     delivered - this skips session started at end of (b)
2845326849aSMichal Kazior 	 *  b) consume stat update events until another one with pdev stats is
2855326849aSMichal Kazior 	 *     delivered which is treated as end-of-data and is itself discarded
2865326849aSMichal Kazior 	 */
287cc61a1bbSMohammed Shafi Shajakhan 	if (ath10k_peer_stats_enabled(ar))
2884a49ae94SMohammed Shafi Shajakhan 		ath10k_sta_update_rx_duration(ar, &stats);
28974135f59SMohammed Shafi Shajakhan 
290e0b6ce00SMohammed Shafi Shajakhan 	if (ar->debug.fw_stats_done) {
291cc61a1bbSMohammed Shafi Shajakhan 		if (!ath10k_peer_stats_enabled(ar))
2925326849aSMichal Kazior 			ath10k_warn(ar, "received unsolicited stats update event\n");
293e0b6ce00SMohammed Shafi Shajakhan 
2945326849aSMichal Kazior 		goto free;
2955326849aSMichal Kazior 	}
2965326849aSMichal Kazior 
297fd7bc9d9SChristophe JAILLET 	num_peers = list_count_nodes(&ar->debug.fw_stats.peers);
298fd7bc9d9SChristophe JAILLET 	num_vdevs = list_count_nodes(&ar->debug.fw_stats.vdevs);
2995326849aSMichal Kazior 	is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
3005326849aSMichal Kazior 		    !list_empty(&stats.pdevs));
3015326849aSMichal Kazior 	is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
3025326849aSMichal Kazior 		  !list_empty(&stats.pdevs));
3035326849aSMichal Kazior 
3045326849aSMichal Kazior 	if (is_start)
3055326849aSMichal Kazior 		list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
3065326849aSMichal Kazior 
3075326849aSMichal Kazior 	if (is_end)
3085326849aSMichal Kazior 		ar->debug.fw_stats_done = true;
3095326849aSMichal Kazior 
3105c51875cSBalaji Pothunoori 	if (stats.extended)
3115c51875cSBalaji Pothunoori 		ar->debug.fw_stats.extended = true;
3125c51875cSBalaji Pothunoori 
3135326849aSMichal Kazior 	is_started = !list_empty(&ar->debug.fw_stats.pdevs);
3145326849aSMichal Kazior 
3155326849aSMichal Kazior 	if (is_started && !is_end) {
3165326849aSMichal Kazior 		if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) {
3175326849aSMichal Kazior 			/* Although this is unlikely impose a sane limit to
3185326849aSMichal Kazior 			 * prevent firmware from DoS-ing the host.
3195326849aSMichal Kazior 			 */
320d57e7f2eSMohammed Shafi Shajakhan 			ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
321c1e3330fSChristian Lamparter 			ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
3225326849aSMichal Kazior 			ath10k_warn(ar, "dropping fw peer stats\n");
3235326849aSMichal Kazior 			goto free;
3245326849aSMichal Kazior 		}
3255326849aSMichal Kazior 
3267b6b153aSMichal Kazior 		if (num_vdevs >= BITS_PER_LONG) {
327d57e7f2eSMohammed Shafi Shajakhan 			ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
3287b6b153aSMichal Kazior 			ath10k_warn(ar, "dropping fw vdev stats\n");
3297b6b153aSMichal Kazior 			goto free;
3307b6b153aSMichal Kazior 		}
3317b6b153aSMichal Kazior 
332c1e3330fSChristian Lamparter 		if (!list_empty(&stats.peers))
3334a49ae94SMohammed Shafi Shajakhan 			list_splice_tail_init(&stats.peers_extd,
3344a49ae94SMohammed Shafi Shajakhan 					      &ar->debug.fw_stats.peers_extd);
335c1e3330fSChristian Lamparter 
336c1e3330fSChristian Lamparter 		list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
337c1e3330fSChristian Lamparter 		list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
3385326849aSMichal Kazior 	}
3395326849aSMichal Kazior 
34060ef401aSMichal Kazior 	complete(&ar->debug.fw_stats_complete);
341d15fb520SMichal Kazior 
3425326849aSMichal Kazior free:
3435326849aSMichal Kazior 	/* In some cases lists have been spliced and cleared. Free up
3445326849aSMichal Kazior 	 * resources if that is not the case.
3455326849aSMichal Kazior 	 */
346b4619ea2SMohammed Shafi Shajakhan 	ath10k_fw_stats_pdevs_free(&stats.pdevs);
347b4619ea2SMohammed Shafi Shajakhan 	ath10k_fw_stats_vdevs_free(&stats.vdevs);
348b4619ea2SMohammed Shafi Shajakhan 	ath10k_fw_stats_peers_free(&stats.peers);
3494a49ae94SMohammed Shafi Shajakhan 	ath10k_fw_extd_stats_peers_free(&stats.peers_extd);
3505326849aSMichal Kazior 
351d15fb520SMichal Kazior 	spin_unlock_bh(&ar->data_lock);
3525e3dd157SKalle Valo }
3535e3dd157SKalle Valo 
ath10k_debug_fw_stats_request(struct ath10k * ar)3544913e675SWen Gong int ath10k_debug_fw_stats_request(struct ath10k *ar)
3555e3dd157SKalle Valo {
3566e8d5438SNicholas Mc Guire 	unsigned long timeout, time_left;
3575e3dd157SKalle Valo 	int ret;
3585e3dd157SKalle Valo 
359fb2e9c0cSMichal Kazior 	lockdep_assert_held(&ar->conf_mutex);
3605e3dd157SKalle Valo 
3615326849aSMichal Kazior 	timeout = jiffies + msecs_to_jiffies(1 * HZ);
3625326849aSMichal Kazior 
3635326849aSMichal Kazior 	ath10k_debug_fw_stats_reset(ar);
3645326849aSMichal Kazior 
3655326849aSMichal Kazior 	for (;;) {
3665326849aSMichal Kazior 		if (time_after(jiffies, timeout))
3675326849aSMichal Kazior 			return -ETIMEDOUT;
3685326849aSMichal Kazior 
3695326849aSMichal Kazior 		reinit_completion(&ar->debug.fw_stats_complete);
3705326849aSMichal Kazior 
3716274cd41SYanbo Li 		ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
3725e3dd157SKalle Valo 		if (ret) {
3735326849aSMichal Kazior 			ath10k_warn(ar, "could not request stats (%d)\n", ret);
374fb2e9c0cSMichal Kazior 			return ret;
3755e3dd157SKalle Valo 		}
3765e3dd157SKalle Valo 
3776e8d5438SNicholas Mc Guire 		time_left =
3786e8d5438SNicholas Mc Guire 		wait_for_completion_timeout(&ar->debug.fw_stats_complete,
3795326849aSMichal Kazior 					    1 * HZ);
3806e8d5438SNicholas Mc Guire 		if (!time_left)
381fb2e9c0cSMichal Kazior 			return -ETIMEDOUT;
382fb2e9c0cSMichal Kazior 
3835326849aSMichal Kazior 		spin_lock_bh(&ar->data_lock);
3845326849aSMichal Kazior 		if (ar->debug.fw_stats_done) {
3855326849aSMichal Kazior 			spin_unlock_bh(&ar->data_lock);
3865326849aSMichal Kazior 			break;
3875326849aSMichal Kazior 		}
3885326849aSMichal Kazior 		spin_unlock_bh(&ar->data_lock);
3895326849aSMichal Kazior 	}
3905326849aSMichal Kazior 
391fb2e9c0cSMichal Kazior 	return 0;
392fb2e9c0cSMichal Kazior }
393fb2e9c0cSMichal Kazior 
ath10k_fw_stats_open(struct inode * inode,struct file * file)394fb2e9c0cSMichal Kazior static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
395fb2e9c0cSMichal Kazior {
396fb2e9c0cSMichal Kazior 	struct ath10k *ar = inode->i_private;
397fb2e9c0cSMichal Kazior 	void *buf = NULL;
398fb2e9c0cSMichal Kazior 	int ret;
3995e3dd157SKalle Valo 
400fb2e9c0cSMichal Kazior 	mutex_lock(&ar->conf_mutex);
401fb2e9c0cSMichal Kazior 
402fb2e9c0cSMichal Kazior 	if (ar->state != ATH10K_STATE_ON) {
403fb2e9c0cSMichal Kazior 		ret = -ENETDOWN;
404fb2e9c0cSMichal Kazior 		goto err_unlock;
405fb2e9c0cSMichal Kazior 	}
406fb2e9c0cSMichal Kazior 
407fb2e9c0cSMichal Kazior 	buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE);
408fb2e9c0cSMichal Kazior 	if (!buf) {
409fb2e9c0cSMichal Kazior 		ret = -ENOMEM;
410fb2e9c0cSMichal Kazior 		goto err_unlock;
411fb2e9c0cSMichal Kazior 	}
412fb2e9c0cSMichal Kazior 
4135326849aSMichal Kazior 	ret = ath10k_debug_fw_stats_request(ar);
414fb2e9c0cSMichal Kazior 	if (ret) {
415fb2e9c0cSMichal Kazior 		ath10k_warn(ar, "failed to request fw stats: %d\n", ret);
416fb2e9c0cSMichal Kazior 		goto err_free;
417fb2e9c0cSMichal Kazior 	}
418fb2e9c0cSMichal Kazior 
419bc6f9ae6SManikanta Pubbisetty 	ret = ath10k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
420bc6f9ae6SManikanta Pubbisetty 	if (ret) {
421bc6f9ae6SManikanta Pubbisetty 		ath10k_warn(ar, "failed to fill fw stats: %d\n", ret);
422bc6f9ae6SManikanta Pubbisetty 		goto err_free;
423bc6f9ae6SManikanta Pubbisetty 	}
424bc6f9ae6SManikanta Pubbisetty 
425fb2e9c0cSMichal Kazior 	file->private_data = buf;
426fb2e9c0cSMichal Kazior 
4275e3dd157SKalle Valo 	mutex_unlock(&ar->conf_mutex);
428fb2e9c0cSMichal Kazior 	return 0;
429fb2e9c0cSMichal Kazior 
430fb2e9c0cSMichal Kazior err_free:
431fb2e9c0cSMichal Kazior 	vfree(buf);
432fb2e9c0cSMichal Kazior 
433fb2e9c0cSMichal Kazior err_unlock:
434fb2e9c0cSMichal Kazior 	mutex_unlock(&ar->conf_mutex);
435fb2e9c0cSMichal Kazior 	return ret;
436fb2e9c0cSMichal Kazior }
437fb2e9c0cSMichal Kazior 
ath10k_fw_stats_release(struct inode * inode,struct file * file)438fb2e9c0cSMichal Kazior static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
439fb2e9c0cSMichal Kazior {
440fb2e9c0cSMichal Kazior 	vfree(file->private_data);
441fb2e9c0cSMichal Kazior 
442fb2e9c0cSMichal Kazior 	return 0;
443fb2e9c0cSMichal Kazior }
444fb2e9c0cSMichal Kazior 
ath10k_fw_stats_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)445fb2e9c0cSMichal Kazior static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
446fb2e9c0cSMichal Kazior 				    size_t count, loff_t *ppos)
447fb2e9c0cSMichal Kazior {
448fb2e9c0cSMichal Kazior 	const char *buf = file->private_data;
449182f1e5aSAmadeusz Sławiński 	size_t len = strlen(buf);
450fb2e9c0cSMichal Kazior 
451fb2e9c0cSMichal Kazior 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
4525e3dd157SKalle Valo }
4535e3dd157SKalle Valo 
4545e3dd157SKalle Valo static const struct file_operations fops_fw_stats = {
455fb2e9c0cSMichal Kazior 	.open = ath10k_fw_stats_open,
456fb2e9c0cSMichal Kazior 	.release = ath10k_fw_stats_release,
45760ef401aSMichal Kazior 	.read = ath10k_fw_stats_read,
4585e3dd157SKalle Valo 	.owner = THIS_MODULE,
4595e3dd157SKalle Valo 	.llseek = default_llseek,
4605e3dd157SKalle Valo };
4615e3dd157SKalle Valo 
ath10k_debug_fw_reset_stats_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)462f51dbe73SBen Greear static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
463f51dbe73SBen Greear 						char __user *user_buf,
464f51dbe73SBen Greear 						size_t count, loff_t *ppos)
465f51dbe73SBen Greear {
466f51dbe73SBen Greear 	struct ath10k *ar = file->private_data;
467182f1e5aSAmadeusz Sławiński 	int ret;
468182f1e5aSAmadeusz Sławiński 	size_t len = 0, buf_len = 500;
469f51dbe73SBen Greear 	char *buf;
470f51dbe73SBen Greear 
471f51dbe73SBen Greear 	buf = kmalloc(buf_len, GFP_KERNEL);
472f51dbe73SBen Greear 	if (!buf)
473f51dbe73SBen Greear 		return -ENOMEM;
474f51dbe73SBen Greear 
475f51dbe73SBen Greear 	spin_lock_bh(&ar->data_lock);
476f51dbe73SBen Greear 
477f51dbe73SBen Greear 	len += scnprintf(buf + len, buf_len - len,
478f51dbe73SBen Greear 			 "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);
479f51dbe73SBen Greear 	len += scnprintf(buf + len, buf_len - len,
480f51dbe73SBen Greear 			 "fw_warm_reset_counter\t\t%d\n",
481f51dbe73SBen Greear 			 ar->stats.fw_warm_reset_counter);
482f51dbe73SBen Greear 	len += scnprintf(buf + len, buf_len - len,
483f51dbe73SBen Greear 			 "fw_cold_reset_counter\t\t%d\n",
484f51dbe73SBen Greear 			 ar->stats.fw_cold_reset_counter);
485f51dbe73SBen Greear 
486f51dbe73SBen Greear 	spin_unlock_bh(&ar->data_lock);
487f51dbe73SBen Greear 
488f51dbe73SBen Greear 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
489f51dbe73SBen Greear 
490f51dbe73SBen Greear 	kfree(buf);
491f51dbe73SBen Greear 
492f51dbe73SBen Greear 	return ret;
493f51dbe73SBen Greear }
494f51dbe73SBen Greear 
495f51dbe73SBen Greear static const struct file_operations fops_fw_reset_stats = {
496f51dbe73SBen Greear 	.open = simple_open,
497f51dbe73SBen Greear 	.read = ath10k_debug_fw_reset_stats_read,
498f51dbe73SBen Greear 	.owner = THIS_MODULE,
499f51dbe73SBen Greear 	.llseek = default_llseek,
500f51dbe73SBen Greear };
501f51dbe73SBen Greear 
502d5aebc77SBen Greear /* This is a clean assert crash in firmware. */
ath10k_debug_fw_assert(struct ath10k * ar)503d5aebc77SBen Greear static int ath10k_debug_fw_assert(struct ath10k *ar)
504d5aebc77SBen Greear {
505d5aebc77SBen Greear 	struct wmi_vdev_install_key_cmd *cmd;
506d5aebc77SBen Greear 	struct sk_buff *skb;
507d5aebc77SBen Greear 
508d5aebc77SBen Greear 	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16);
509d5aebc77SBen Greear 	if (!skb)
510d5aebc77SBen Greear 		return -ENOMEM;
511d5aebc77SBen Greear 
512d5aebc77SBen Greear 	cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
513d5aebc77SBen Greear 	memset(cmd, 0, sizeof(*cmd));
514d5aebc77SBen Greear 
515d5aebc77SBen Greear 	/* big enough number so that firmware asserts */
516d5aebc77SBen Greear 	cmd->vdev_id = __cpu_to_le32(0x7ffe);
517d5aebc77SBen Greear 
518d5aebc77SBen Greear 	return ath10k_wmi_cmd_send(ar, skb,
519d5aebc77SBen Greear 				   ar->wmi.cmd->vdev_install_key_cmdid);
520d5aebc77SBen Greear }
521d5aebc77SBen Greear 
ath10k_read_simulate_fw_crash(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)522278c4a85SMichal Kazior static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
523278c4a85SMichal Kazior 					     char __user *user_buf,
524278c4a85SMichal Kazior 					     size_t count, loff_t *ppos)
525278c4a85SMichal Kazior {
52675cb96d3SKalle Valo 	const char buf[] =
52775cb96d3SKalle Valo 		"To simulate firmware crash write one of the keywords to this file:\n"
52875cb96d3SKalle Valo 		"`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n"
52975cb96d3SKalle Valo 		"`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n"
530605cdba1SMichal Kazior 		"`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n"
531605cdba1SMichal Kazior 		"`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
5328c656992SMarek Puzyniak 
533278c4a85SMichal Kazior 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
534278c4a85SMichal Kazior }
535278c4a85SMichal Kazior 
5368c656992SMarek Puzyniak /* Simulate firmware crash:
5378c656992SMarek Puzyniak  * 'soft': Call wmi command causing firmware hang. This firmware hang is
5388c656992SMarek Puzyniak  * recoverable by warm firmware reset.
5398c656992SMarek Puzyniak  * 'hard': Force firmware crash by setting any vdev parameter for not allowed
5408c656992SMarek Puzyniak  * vdev id. This is hard firmware crash because it is recoverable only by cold
5418c656992SMarek Puzyniak  * firmware reset.
5428c656992SMarek Puzyniak  */
ath10k_write_simulate_fw_crash(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)543278c4a85SMichal Kazior static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
544278c4a85SMichal Kazior 					      const char __user *user_buf,
545278c4a85SMichal Kazior 					      size_t count, loff_t *ppos)
546278c4a85SMichal Kazior {
547278c4a85SMichal Kazior 	struct ath10k *ar = file->private_data;
548a16703aaSMichael Mera 	char buf[32] = {0};
549a16703aaSMichael Mera 	ssize_t rc;
550278c4a85SMichal Kazior 	int ret;
551278c4a85SMichal Kazior 
552a16703aaSMichael Mera 	/* filter partial writes and invalid commands */
553a16703aaSMichael Mera 	if (*ppos != 0 || count >= sizeof(buf) || count == 0)
554a16703aaSMichael Mera 		return -EINVAL;
5558c656992SMarek Puzyniak 
556a16703aaSMichael Mera 	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
557a16703aaSMichael Mera 	if (rc < 0)
558a16703aaSMichael Mera 		return rc;
559278c4a85SMichal Kazior 
560f5e30751SMohammed Shafi Shajakhan 	/* drop the possible '\n' from the end */
561a16703aaSMichael Mera 	if (buf[*ppos - 1] == '\n')
562a16703aaSMichael Mera 		buf[*ppos - 1] = '\0';
563f5e30751SMohammed Shafi Shajakhan 
564f5e30751SMohammed Shafi Shajakhan 	mutex_lock(&ar->conf_mutex);
565f5e30751SMohammed Shafi Shajakhan 
566278c4a85SMichal Kazior 	if (ar->state != ATH10K_STATE_ON &&
567278c4a85SMichal Kazior 	    ar->state != ATH10K_STATE_RESTARTED) {
568278c4a85SMichal Kazior 		ret = -ENETDOWN;
569278c4a85SMichal Kazior 		goto exit;
570278c4a85SMichal Kazior 	}
571278c4a85SMichal Kazior 
5728c656992SMarek Puzyniak 	if (!strcmp(buf, "soft")) {
5737aa7a72aSMichal Kazior 		ath10k_info(ar, "simulating soft firmware crash\n");
574278c4a85SMichal Kazior 		ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
5758c656992SMarek Puzyniak 	} else if (!strcmp(buf, "hard")) {
5767aa7a72aSMichal Kazior 		ath10k_info(ar, "simulating hard firmware crash\n");
577611b3682SBen Greear 		/* 0x7fff is vdev id, and it is always out of range for all
578611b3682SBen Greear 		 * firmware variants in order to force a firmware crash.
579611b3682SBen Greear 		 */
580611b3682SBen Greear 		ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
5815b07e07fSKalle Valo 						ar->wmi.vdev_param->rts_threshold,
5825b07e07fSKalle Valo 						0);
583d5aebc77SBen Greear 	} else if (!strcmp(buf, "assert")) {
584d5aebc77SBen Greear 		ath10k_info(ar, "simulating firmware assert crash\n");
585d5aebc77SBen Greear 		ret = ath10k_debug_fw_assert(ar);
586605cdba1SMichal Kazior 	} else if (!strcmp(buf, "hw-restart")) {
587605cdba1SMichal Kazior 		ath10k_info(ar, "user requested hw restart\n");
5885dadbe4eSWen Gong 		ath10k_core_start_recovery(ar);
589605cdba1SMichal Kazior 		ret = 0;
5908c656992SMarek Puzyniak 	} else {
5918c656992SMarek Puzyniak 		ret = -EINVAL;
5928c656992SMarek Puzyniak 		goto exit;
5938c656992SMarek Puzyniak 	}
594278c4a85SMichal Kazior 
5958c656992SMarek Puzyniak 	if (ret) {
5967aa7a72aSMichal Kazior 		ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
5978c656992SMarek Puzyniak 		goto exit;
5988c656992SMarek Puzyniak 	}
5998c656992SMarek Puzyniak 
600278c4a85SMichal Kazior 	ret = count;
601278c4a85SMichal Kazior 
602278c4a85SMichal Kazior exit:
603278c4a85SMichal Kazior 	mutex_unlock(&ar->conf_mutex);
604278c4a85SMichal Kazior 	return ret;
605278c4a85SMichal Kazior }
606278c4a85SMichal Kazior 
607278c4a85SMichal Kazior static const struct file_operations fops_simulate_fw_crash = {
608278c4a85SMichal Kazior 	.read = ath10k_read_simulate_fw_crash,
609278c4a85SMichal Kazior 	.write = ath10k_write_simulate_fw_crash,
610278c4a85SMichal Kazior 	.open = simple_open,
611278c4a85SMichal Kazior 	.owner = THIS_MODULE,
612278c4a85SMichal Kazior 	.llseek = default_llseek,
613278c4a85SMichal Kazior };
614278c4a85SMichal Kazior 
ath10k_read_chip_id(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)615763b8cd3SKalle Valo static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
616763b8cd3SKalle Valo 				   size_t count, loff_t *ppos)
617763b8cd3SKalle Valo {
618763b8cd3SKalle Valo 	struct ath10k *ar = file->private_data;
619182f1e5aSAmadeusz Sławiński 	size_t len;
620763b8cd3SKalle Valo 	char buf[50];
621763b8cd3SKalle Valo 
622de8781d7SGovind Singh 	len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->bus_param.chip_id);
623763b8cd3SKalle Valo 
624763b8cd3SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
625763b8cd3SKalle Valo }
626763b8cd3SKalle Valo 
627763b8cd3SKalle Valo static const struct file_operations fops_chip_id = {
628763b8cd3SKalle Valo 	.read = ath10k_read_chip_id,
629763b8cd3SKalle Valo 	.open = simple_open,
630763b8cd3SKalle Valo 	.owner = THIS_MODULE,
631763b8cd3SKalle Valo 	.llseek = default_llseek,
632763b8cd3SKalle Valo };
633763b8cd3SKalle Valo 
ath10k_reg_addr_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)634077a3804SYanbo Li static ssize_t ath10k_reg_addr_read(struct file *file,
635077a3804SYanbo Li 				    char __user *user_buf,
636077a3804SYanbo Li 				    size_t count, loff_t *ppos)
637077a3804SYanbo Li {
638077a3804SYanbo Li 	struct ath10k *ar = file->private_data;
639077a3804SYanbo Li 	u8 buf[32];
640182f1e5aSAmadeusz Sławiński 	size_t len = 0;
641077a3804SYanbo Li 	u32 reg_addr;
642077a3804SYanbo Li 
643077a3804SYanbo Li 	mutex_lock(&ar->conf_mutex);
644077a3804SYanbo Li 	reg_addr = ar->debug.reg_addr;
645077a3804SYanbo Li 	mutex_unlock(&ar->conf_mutex);
646077a3804SYanbo Li 
647077a3804SYanbo Li 	len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
648077a3804SYanbo Li 
649077a3804SYanbo Li 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
650077a3804SYanbo Li }
651077a3804SYanbo Li 
ath10k_reg_addr_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)652077a3804SYanbo Li static ssize_t ath10k_reg_addr_write(struct file *file,
653077a3804SYanbo Li 				     const char __user *user_buf,
654077a3804SYanbo Li 				     size_t count, loff_t *ppos)
655077a3804SYanbo Li {
656077a3804SYanbo Li 	struct ath10k *ar = file->private_data;
657077a3804SYanbo Li 	u32 reg_addr;
658077a3804SYanbo Li 	int ret;
659077a3804SYanbo Li 
660077a3804SYanbo Li 	ret = kstrtou32_from_user(user_buf, count, 0, &reg_addr);
661077a3804SYanbo Li 	if (ret)
662077a3804SYanbo Li 		return ret;
663077a3804SYanbo Li 
664077a3804SYanbo Li 	if (!IS_ALIGNED(reg_addr, 4))
665077a3804SYanbo Li 		return -EFAULT;
666077a3804SYanbo Li 
667077a3804SYanbo Li 	mutex_lock(&ar->conf_mutex);
668077a3804SYanbo Li 	ar->debug.reg_addr = reg_addr;
669077a3804SYanbo Li 	mutex_unlock(&ar->conf_mutex);
670077a3804SYanbo Li 
671077a3804SYanbo Li 	return count;
672077a3804SYanbo Li }
673077a3804SYanbo Li 
674077a3804SYanbo Li static const struct file_operations fops_reg_addr = {
675077a3804SYanbo Li 	.read = ath10k_reg_addr_read,
676077a3804SYanbo Li 	.write = ath10k_reg_addr_write,
677077a3804SYanbo Li 	.open = simple_open,
678077a3804SYanbo Li 	.owner = THIS_MODULE,
679077a3804SYanbo Li 	.llseek = default_llseek,
680077a3804SYanbo Li };
681077a3804SYanbo Li 
ath10k_reg_value_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)682077a3804SYanbo Li static ssize_t ath10k_reg_value_read(struct file *file,
683077a3804SYanbo Li 				     char __user *user_buf,
684077a3804SYanbo Li 				     size_t count, loff_t *ppos)
685077a3804SYanbo Li {
686077a3804SYanbo Li 	struct ath10k *ar = file->private_data;
687077a3804SYanbo Li 	u8 buf[48];
688182f1e5aSAmadeusz Sławiński 	size_t len;
689077a3804SYanbo Li 	u32 reg_addr, reg_val;
690077a3804SYanbo Li 	int ret;
691077a3804SYanbo Li 
692077a3804SYanbo Li 	mutex_lock(&ar->conf_mutex);
693077a3804SYanbo Li 
694077a3804SYanbo Li 	if (ar->state != ATH10K_STATE_ON &&
695077a3804SYanbo Li 	    ar->state != ATH10K_STATE_UTF) {
696077a3804SYanbo Li 		ret = -ENETDOWN;
697077a3804SYanbo Li 		goto exit;
698077a3804SYanbo Li 	}
699077a3804SYanbo Li 
700077a3804SYanbo Li 	reg_addr = ar->debug.reg_addr;
701077a3804SYanbo Li 
702077a3804SYanbo Li 	reg_val = ath10k_hif_read32(ar, reg_addr);
703077a3804SYanbo Li 	len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
704077a3804SYanbo Li 
705077a3804SYanbo Li 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
706077a3804SYanbo Li 
707077a3804SYanbo Li exit:
708077a3804SYanbo Li 	mutex_unlock(&ar->conf_mutex);
709077a3804SYanbo Li 
710077a3804SYanbo Li 	return ret;
711077a3804SYanbo Li }
712077a3804SYanbo Li 
ath10k_reg_value_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)713077a3804SYanbo Li static ssize_t ath10k_reg_value_write(struct file *file,
714077a3804SYanbo Li 				      const char __user *user_buf,
715077a3804SYanbo Li 				      size_t count, loff_t *ppos)
716077a3804SYanbo Li {
717077a3804SYanbo Li 	struct ath10k *ar = file->private_data;
718077a3804SYanbo Li 	u32 reg_addr, reg_val;
719077a3804SYanbo Li 	int ret;
720077a3804SYanbo Li 
721077a3804SYanbo Li 	mutex_lock(&ar->conf_mutex);
722077a3804SYanbo Li 
723077a3804SYanbo Li 	if (ar->state != ATH10K_STATE_ON &&
724077a3804SYanbo Li 	    ar->state != ATH10K_STATE_UTF) {
725077a3804SYanbo Li 		ret = -ENETDOWN;
726077a3804SYanbo Li 		goto exit;
727077a3804SYanbo Li 	}
728077a3804SYanbo Li 
729077a3804SYanbo Li 	reg_addr = ar->debug.reg_addr;
730077a3804SYanbo Li 
731077a3804SYanbo Li 	ret = kstrtou32_from_user(user_buf, count, 0, &reg_val);
732077a3804SYanbo Li 	if (ret)
733077a3804SYanbo Li 		goto exit;
734077a3804SYanbo Li 
735077a3804SYanbo Li 	ath10k_hif_write32(ar, reg_addr, reg_val);
736077a3804SYanbo Li 
737077a3804SYanbo Li 	ret = count;
738077a3804SYanbo Li 
739077a3804SYanbo Li exit:
740077a3804SYanbo Li 	mutex_unlock(&ar->conf_mutex);
741077a3804SYanbo Li 
742077a3804SYanbo Li 	return ret;
743077a3804SYanbo Li }
744077a3804SYanbo Li 
745077a3804SYanbo Li static const struct file_operations fops_reg_value = {
746077a3804SYanbo Li 	.read = ath10k_reg_value_read,
747077a3804SYanbo Li 	.write = ath10k_reg_value_write,
748077a3804SYanbo Li 	.open = simple_open,
749077a3804SYanbo Li 	.owner = THIS_MODULE,
750077a3804SYanbo Li 	.llseek = default_llseek,
751077a3804SYanbo Li };
752077a3804SYanbo Li 
ath10k_mem_value_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)7539f65ad25SYanbo Li static ssize_t ath10k_mem_value_read(struct file *file,
7549f65ad25SYanbo Li 				     char __user *user_buf,
7559f65ad25SYanbo Li 				     size_t count, loff_t *ppos)
7569f65ad25SYanbo Li {
7579f65ad25SYanbo Li 	struct ath10k *ar = file->private_data;
7589f65ad25SYanbo Li 	u8 *buf;
7599f65ad25SYanbo Li 	int ret;
7609f65ad25SYanbo Li 
7619f65ad25SYanbo Li 	if (*ppos < 0)
7629f65ad25SYanbo Li 		return -EINVAL;
7639f65ad25SYanbo Li 
7649f65ad25SYanbo Li 	if (!count)
7659f65ad25SYanbo Li 		return 0;
7669f65ad25SYanbo Li 
7679f65ad25SYanbo Li 	mutex_lock(&ar->conf_mutex);
7689f65ad25SYanbo Li 
7699f65ad25SYanbo Li 	buf = vmalloc(count);
7709f65ad25SYanbo Li 	if (!buf) {
7719f65ad25SYanbo Li 		ret = -ENOMEM;
7729f65ad25SYanbo Li 		goto exit;
7739f65ad25SYanbo Li 	}
7749f65ad25SYanbo Li 
7759f65ad25SYanbo Li 	if (ar->state != ATH10K_STATE_ON &&
7769f65ad25SYanbo Li 	    ar->state != ATH10K_STATE_UTF) {
7779f65ad25SYanbo Li 		ret = -ENETDOWN;
7789f65ad25SYanbo Li 		goto exit;
7799f65ad25SYanbo Li 	}
7809f65ad25SYanbo Li 
7819f65ad25SYanbo Li 	ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
7829f65ad25SYanbo Li 	if (ret) {
7838a7968beSMamatha Telu 		ath10k_warn(ar, "failed to read address 0x%08x via diagnose window from debugfs: %d\n",
7849f65ad25SYanbo Li 			    (u32)(*ppos), ret);
7859f65ad25SYanbo Li 		goto exit;
7869f65ad25SYanbo Li 	}
7879f65ad25SYanbo Li 
7889f65ad25SYanbo Li 	ret = copy_to_user(user_buf, buf, count);
7899f65ad25SYanbo Li 	if (ret) {
7909f65ad25SYanbo Li 		ret = -EFAULT;
7919f65ad25SYanbo Li 		goto exit;
7929f65ad25SYanbo Li 	}
7939f65ad25SYanbo Li 
7949f65ad25SYanbo Li 	count -= ret;
7959f65ad25SYanbo Li 	*ppos += count;
7969f65ad25SYanbo Li 	ret = count;
7979f65ad25SYanbo Li 
7989f65ad25SYanbo Li exit:
7999f65ad25SYanbo Li 	vfree(buf);
8009f65ad25SYanbo Li 	mutex_unlock(&ar->conf_mutex);
8019f65ad25SYanbo Li 
8029f65ad25SYanbo Li 	return ret;
8039f65ad25SYanbo Li }
8049f65ad25SYanbo Li 
ath10k_mem_value_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)8059f65ad25SYanbo Li static ssize_t ath10k_mem_value_write(struct file *file,
8069f65ad25SYanbo Li 				      const char __user *user_buf,
8079f65ad25SYanbo Li 				      size_t count, loff_t *ppos)
8089f65ad25SYanbo Li {
8099f65ad25SYanbo Li 	struct ath10k *ar = file->private_data;
8109f65ad25SYanbo Li 	u8 *buf;
8119f65ad25SYanbo Li 	int ret;
8129f65ad25SYanbo Li 
8139f65ad25SYanbo Li 	if (*ppos < 0)
8149f65ad25SYanbo Li 		return -EINVAL;
8159f65ad25SYanbo Li 
8169f65ad25SYanbo Li 	if (!count)
8179f65ad25SYanbo Li 		return 0;
8189f65ad25SYanbo Li 
8199f65ad25SYanbo Li 	mutex_lock(&ar->conf_mutex);
8209f65ad25SYanbo Li 
8219f65ad25SYanbo Li 	buf = vmalloc(count);
8229f65ad25SYanbo Li 	if (!buf) {
8239f65ad25SYanbo Li 		ret = -ENOMEM;
8249f65ad25SYanbo Li 		goto exit;
8259f65ad25SYanbo Li 	}
8269f65ad25SYanbo Li 
8279f65ad25SYanbo Li 	if (ar->state != ATH10K_STATE_ON &&
8289f65ad25SYanbo Li 	    ar->state != ATH10K_STATE_UTF) {
8299f65ad25SYanbo Li 		ret = -ENETDOWN;
8309f65ad25SYanbo Li 		goto exit;
8319f65ad25SYanbo Li 	}
8329f65ad25SYanbo Li 
8339f65ad25SYanbo Li 	ret = copy_from_user(buf, user_buf, count);
8349f65ad25SYanbo Li 	if (ret) {
8359f65ad25SYanbo Li 		ret = -EFAULT;
8369f65ad25SYanbo Li 		goto exit;
8379f65ad25SYanbo Li 	}
8389f65ad25SYanbo Li 
8399f65ad25SYanbo Li 	ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
8409f65ad25SYanbo Li 	if (ret) {
8419f65ad25SYanbo Li 		ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
8429f65ad25SYanbo Li 			    (u32)(*ppos), ret);
8439f65ad25SYanbo Li 		goto exit;
8449f65ad25SYanbo Li 	}
8459f65ad25SYanbo Li 
8469f65ad25SYanbo Li 	*ppos += count;
8479f65ad25SYanbo Li 	ret = count;
8489f65ad25SYanbo Li 
8499f65ad25SYanbo Li exit:
8509f65ad25SYanbo Li 	vfree(buf);
8519f65ad25SYanbo Li 	mutex_unlock(&ar->conf_mutex);
8529f65ad25SYanbo Li 
8539f65ad25SYanbo Li 	return ret;
8549f65ad25SYanbo Li }
8559f65ad25SYanbo Li 
8569f65ad25SYanbo Li static const struct file_operations fops_mem_value = {
8579f65ad25SYanbo Li 	.read = ath10k_mem_value_read,
8589f65ad25SYanbo Li 	.write = ath10k_mem_value_write,
8599f65ad25SYanbo Li 	.open = simple_open,
8609f65ad25SYanbo Li 	.owner = THIS_MODULE,
8619f65ad25SYanbo Li 	.llseek = default_llseek,
8629f65ad25SYanbo Li };
8639f65ad25SYanbo Li 
ath10k_debug_htt_stats_req(struct ath10k * ar)864a3d135e5SKalle Valo static int ath10k_debug_htt_stats_req(struct ath10k *ar)
865a3d135e5SKalle Valo {
866a3d135e5SKalle Valo 	u64 cookie;
867a3d135e5SKalle Valo 	int ret;
868a3d135e5SKalle Valo 
869a3d135e5SKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
870a3d135e5SKalle Valo 
871a3d135e5SKalle Valo 	if (ar->debug.htt_stats_mask == 0)
872a3d135e5SKalle Valo 		/* htt stats are disabled */
873a3d135e5SKalle Valo 		return 0;
874a3d135e5SKalle Valo 
875a3d135e5SKalle Valo 	if (ar->state != ATH10K_STATE_ON)
876a3d135e5SKalle Valo 		return 0;
877a3d135e5SKalle Valo 
878a3d135e5SKalle Valo 	cookie = get_jiffies_64();
879a3d135e5SKalle Valo 
880a3d135e5SKalle Valo 	ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
881473a4084SMaharaja Kennadyrajan 				       ar->debug.reset_htt_stats, cookie);
882a3d135e5SKalle Valo 	if (ret) {
8837aa7a72aSMichal Kazior 		ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
884a3d135e5SKalle Valo 		return ret;
885a3d135e5SKalle Valo 	}
886a3d135e5SKalle Valo 
887a3d135e5SKalle Valo 	queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork,
888a3d135e5SKalle Valo 			   msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL));
889a3d135e5SKalle Valo 
890a3d135e5SKalle Valo 	return 0;
891a3d135e5SKalle Valo }
892a3d135e5SKalle Valo 
ath10k_debug_htt_stats_dwork(struct work_struct * work)893a3d135e5SKalle Valo static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
894a3d135e5SKalle Valo {
895a3d135e5SKalle Valo 	struct ath10k *ar = container_of(work, struct ath10k,
896a3d135e5SKalle Valo 					 debug.htt_stats_dwork.work);
897a3d135e5SKalle Valo 
898a3d135e5SKalle Valo 	mutex_lock(&ar->conf_mutex);
899a3d135e5SKalle Valo 
900a3d135e5SKalle Valo 	ath10k_debug_htt_stats_req(ar);
901a3d135e5SKalle Valo 
902a3d135e5SKalle Valo 	mutex_unlock(&ar->conf_mutex);
903a3d135e5SKalle Valo }
904a3d135e5SKalle Valo 
ath10k_read_htt_stats_mask(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)905a3d135e5SKalle Valo static ssize_t ath10k_read_htt_stats_mask(struct file *file,
906a3d135e5SKalle Valo 					  char __user *user_buf,
907a3d135e5SKalle Valo 					  size_t count, loff_t *ppos)
908a3d135e5SKalle Valo {
909a3d135e5SKalle Valo 	struct ath10k *ar = file->private_data;
910a3d135e5SKalle Valo 	char buf[32];
911182f1e5aSAmadeusz Sławiński 	size_t len;
912a3d135e5SKalle Valo 
913a3d135e5SKalle Valo 	len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);
914a3d135e5SKalle Valo 
915a3d135e5SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
916a3d135e5SKalle Valo }
917a3d135e5SKalle Valo 
ath10k_write_htt_stats_mask(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)918a3d135e5SKalle Valo static ssize_t ath10k_write_htt_stats_mask(struct file *file,
919a3d135e5SKalle Valo 					   const char __user *user_buf,
920a3d135e5SKalle Valo 					   size_t count, loff_t *ppos)
921a3d135e5SKalle Valo {
922a3d135e5SKalle Valo 	struct ath10k *ar = file->private_data;
923a3d135e5SKalle Valo 	unsigned long mask;
924a3d135e5SKalle Valo 	int ret;
925a3d135e5SKalle Valo 
926a3d135e5SKalle Valo 	ret = kstrtoul_from_user(user_buf, count, 0, &mask);
927a3d135e5SKalle Valo 	if (ret)
928a3d135e5SKalle Valo 		return ret;
929a3d135e5SKalle Valo 
93014bf9217SMaharaja Kennadyrajan 	/* max 17 bit masks (for now) */
93114bf9217SMaharaja Kennadyrajan 	if (mask > HTT_STATS_BIT_MASK)
932a3d135e5SKalle Valo 		return -E2BIG;
933a3d135e5SKalle Valo 
934a3d135e5SKalle Valo 	mutex_lock(&ar->conf_mutex);
935a3d135e5SKalle Valo 
936a3d135e5SKalle Valo 	ar->debug.htt_stats_mask = mask;
937a3d135e5SKalle Valo 
938a3d135e5SKalle Valo 	ret = ath10k_debug_htt_stats_req(ar);
939a3d135e5SKalle Valo 	if (ret)
940a3d135e5SKalle Valo 		goto out;
941a3d135e5SKalle Valo 
942a3d135e5SKalle Valo 	ret = count;
943a3d135e5SKalle Valo 
944a3d135e5SKalle Valo out:
945a3d135e5SKalle Valo 	mutex_unlock(&ar->conf_mutex);
946a3d135e5SKalle Valo 
947a3d135e5SKalle Valo 	return ret;
948a3d135e5SKalle Valo }
949a3d135e5SKalle Valo 
950a3d135e5SKalle Valo static const struct file_operations fops_htt_stats_mask = {
951a3d135e5SKalle Valo 	.read = ath10k_read_htt_stats_mask,
952a3d135e5SKalle Valo 	.write = ath10k_write_htt_stats_mask,
953a3d135e5SKalle Valo 	.open = simple_open,
954a3d135e5SKalle Valo 	.owner = THIS_MODULE,
955a3d135e5SKalle Valo 	.llseek = default_llseek,
956a3d135e5SKalle Valo };
957a3d135e5SKalle Valo 
ath10k_read_htt_max_amsdu_ampdu(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)958d385623aSJanusz Dziedzic static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
959d385623aSJanusz Dziedzic 					       char __user *user_buf,
960d385623aSJanusz Dziedzic 					       size_t count, loff_t *ppos)
961d385623aSJanusz Dziedzic {
962d385623aSJanusz Dziedzic 	struct ath10k *ar = file->private_data;
963d385623aSJanusz Dziedzic 	char buf[64];
96481ec3c09SMohammed Shafi Shajakhan 	u8 amsdu, ampdu;
965182f1e5aSAmadeusz Sławiński 	size_t len;
966d385623aSJanusz Dziedzic 
967d385623aSJanusz Dziedzic 	mutex_lock(&ar->conf_mutex);
968d385623aSJanusz Dziedzic 
969ccec9038SDavid Liu 	amsdu = ar->htt.max_num_amsdu;
970ccec9038SDavid Liu 	ampdu = ar->htt.max_num_ampdu;
971d385623aSJanusz Dziedzic 	mutex_unlock(&ar->conf_mutex);
972d385623aSJanusz Dziedzic 
973d385623aSJanusz Dziedzic 	len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu);
974d385623aSJanusz Dziedzic 
975d385623aSJanusz Dziedzic 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
976d385623aSJanusz Dziedzic }
977d385623aSJanusz Dziedzic 
ath10k_write_htt_max_amsdu_ampdu(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)978d385623aSJanusz Dziedzic static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,
979d385623aSJanusz Dziedzic 						const char __user *user_buf,
980d385623aSJanusz Dziedzic 						size_t count, loff_t *ppos)
981d385623aSJanusz Dziedzic {
982d385623aSJanusz Dziedzic 	struct ath10k *ar = file->private_data;
983d385623aSJanusz Dziedzic 	int res;
9842f177c16SVenkateswara Naralasetty 	char buf[64] = {0};
985d385623aSJanusz Dziedzic 	unsigned int amsdu, ampdu;
986d385623aSJanusz Dziedzic 
9872f177c16SVenkateswara Naralasetty 	res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
9882f177c16SVenkateswara Naralasetty 				     user_buf, count);
9892f177c16SVenkateswara Naralasetty 	if (res <= 0)
9902f177c16SVenkateswara Naralasetty 		return res;
991d385623aSJanusz Dziedzic 
992d385623aSJanusz Dziedzic 	res = sscanf(buf, "%u %u", &amsdu, &ampdu);
993d385623aSJanusz Dziedzic 
994d385623aSJanusz Dziedzic 	if (res != 2)
995d385623aSJanusz Dziedzic 		return -EINVAL;
996d385623aSJanusz Dziedzic 
997d385623aSJanusz Dziedzic 	mutex_lock(&ar->conf_mutex);
998d385623aSJanusz Dziedzic 
999d385623aSJanusz Dziedzic 	res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu);
1000d385623aSJanusz Dziedzic 	if (res)
1001d385623aSJanusz Dziedzic 		goto out;
1002d385623aSJanusz Dziedzic 
1003d385623aSJanusz Dziedzic 	res = count;
1004ccec9038SDavid Liu 	ar->htt.max_num_amsdu = amsdu;
1005ccec9038SDavid Liu 	ar->htt.max_num_ampdu = ampdu;
1006d385623aSJanusz Dziedzic 
1007d385623aSJanusz Dziedzic out:
1008d385623aSJanusz Dziedzic 	mutex_unlock(&ar->conf_mutex);
1009d385623aSJanusz Dziedzic 	return res;
1010d385623aSJanusz Dziedzic }
1011d385623aSJanusz Dziedzic 
1012d385623aSJanusz Dziedzic static const struct file_operations fops_htt_max_amsdu_ampdu = {
1013d385623aSJanusz Dziedzic 	.read = ath10k_read_htt_max_amsdu_ampdu,
1014d385623aSJanusz Dziedzic 	.write = ath10k_write_htt_max_amsdu_ampdu,
1015d385623aSJanusz Dziedzic 	.open = simple_open,
1016d385623aSJanusz Dziedzic 	.owner = THIS_MODULE,
1017d385623aSJanusz Dziedzic 	.llseek = default_llseek,
1018d385623aSJanusz Dziedzic };
1019d385623aSJanusz Dziedzic 
ath10k_read_fw_dbglog(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1020f118a3e5SKalle Valo static ssize_t ath10k_read_fw_dbglog(struct file *file,
1021f118a3e5SKalle Valo 				     char __user *user_buf,
1022f118a3e5SKalle Valo 				     size_t count, loff_t *ppos)
1023f118a3e5SKalle Valo {
1024f118a3e5SKalle Valo 	struct ath10k *ar = file->private_data;
1025182f1e5aSAmadeusz Sławiński 	size_t len;
1026afcbc82cSMaharaja Kennadyrajan 	char buf[96];
1027f118a3e5SKalle Valo 
1028afcbc82cSMaharaja Kennadyrajan 	len = scnprintf(buf, sizeof(buf), "0x%16llx %u\n",
1029467210a6SSenthilKumar Jegadeesan 			ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level);
1030f118a3e5SKalle Valo 
1031f118a3e5SKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1032f118a3e5SKalle Valo }
1033f118a3e5SKalle Valo 
ath10k_write_fw_dbglog(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1034f118a3e5SKalle Valo static ssize_t ath10k_write_fw_dbglog(struct file *file,
1035f118a3e5SKalle Valo 				      const char __user *user_buf,
1036f118a3e5SKalle Valo 				      size_t count, loff_t *ppos)
1037f118a3e5SKalle Valo {
1038f118a3e5SKalle Valo 	struct ath10k *ar = file->private_data;
1039f118a3e5SKalle Valo 	int ret;
10402f177c16SVenkateswara Naralasetty 	char buf[96] = {0};
1041afcbc82cSMaharaja Kennadyrajan 	unsigned int log_level;
1042afcbc82cSMaharaja Kennadyrajan 	u64 mask;
1043f118a3e5SKalle Valo 
10442f177c16SVenkateswara Naralasetty 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
10452f177c16SVenkateswara Naralasetty 				     user_buf, count);
10462f177c16SVenkateswara Naralasetty 	if (ret <= 0)
10472f177c16SVenkateswara Naralasetty 		return ret;
1048467210a6SSenthilKumar Jegadeesan 
1049afcbc82cSMaharaja Kennadyrajan 	ret = sscanf(buf, "%llx %u", &mask, &log_level);
1050467210a6SSenthilKumar Jegadeesan 
1051467210a6SSenthilKumar Jegadeesan 	if (!ret)
1052467210a6SSenthilKumar Jegadeesan 		return -EINVAL;
1053467210a6SSenthilKumar Jegadeesan 
1054467210a6SSenthilKumar Jegadeesan 	if (ret == 1)
1055467210a6SSenthilKumar Jegadeesan 		/* default if user did not specify */
1056467210a6SSenthilKumar Jegadeesan 		log_level = ATH10K_DBGLOG_LEVEL_WARN;
1057f118a3e5SKalle Valo 
1058f118a3e5SKalle Valo 	mutex_lock(&ar->conf_mutex);
1059f118a3e5SKalle Valo 
1060f118a3e5SKalle Valo 	ar->debug.fw_dbglog_mask = mask;
1061467210a6SSenthilKumar Jegadeesan 	ar->debug.fw_dbglog_level = log_level;
1062f118a3e5SKalle Valo 
1063f118a3e5SKalle Valo 	if (ar->state == ATH10K_STATE_ON) {
1064467210a6SSenthilKumar Jegadeesan 		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
1065467210a6SSenthilKumar Jegadeesan 					    ar->debug.fw_dbglog_level);
1066f118a3e5SKalle Valo 		if (ret) {
10677aa7a72aSMichal Kazior 			ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
1068f118a3e5SKalle Valo 				    ret);
1069f118a3e5SKalle Valo 			goto exit;
1070f118a3e5SKalle Valo 		}
1071f118a3e5SKalle Valo 	}
1072f118a3e5SKalle Valo 
1073f118a3e5SKalle Valo 	ret = count;
1074f118a3e5SKalle Valo 
1075f118a3e5SKalle Valo exit:
1076f118a3e5SKalle Valo 	mutex_unlock(&ar->conf_mutex);
1077f118a3e5SKalle Valo 
1078f118a3e5SKalle Valo 	return ret;
1079f118a3e5SKalle Valo }
1080f118a3e5SKalle Valo 
10816cddcc7aSBen Greear /* TODO:  Would be nice to always support ethtool stats, would need to
10826cddcc7aSBen Greear  * move the stats storage out of ath10k_debug, or always have ath10k_debug
10836cddcc7aSBen Greear  * struct available..
10846cddcc7aSBen Greear  */
10856cddcc7aSBen Greear 
1086b8a71b95SJeff Johnson /* This generally corresponds to the debugfs fw_stats file */
10876cddcc7aSBen Greear static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
10886cddcc7aSBen Greear 	"tx_pkts_nic",
10896cddcc7aSBen Greear 	"tx_bytes_nic",
10906cddcc7aSBen Greear 	"rx_pkts_nic",
10916cddcc7aSBen Greear 	"rx_bytes_nic",
10926cddcc7aSBen Greear 	"d_noise_floor",
10936cddcc7aSBen Greear 	"d_cycle_count",
10946cddcc7aSBen Greear 	"d_phy_error",
10956cddcc7aSBen Greear 	"d_rts_bad",
10966cddcc7aSBen Greear 	"d_rts_good",
10976cddcc7aSBen Greear 	"d_tx_power", /* in .5 dbM I think */
10986cddcc7aSBen Greear 	"d_rx_crc_err", /* fcs_bad */
1099ea0c3e2aSLinus Lüssing 	"d_rx_crc_err_drop", /* frame with FCS error, dropped late in kernel */
11006cddcc7aSBen Greear 	"d_no_beacon",
11016cddcc7aSBen Greear 	"d_tx_mpdus_queued",
11026cddcc7aSBen Greear 	"d_tx_msdu_queued",
11036cddcc7aSBen Greear 	"d_tx_msdu_dropped",
11046cddcc7aSBen Greear 	"d_local_enqued",
11056cddcc7aSBen Greear 	"d_local_freed",
11066cddcc7aSBen Greear 	"d_tx_ppdu_hw_queued",
11076cddcc7aSBen Greear 	"d_tx_ppdu_reaped",
11086cddcc7aSBen Greear 	"d_tx_fifo_underrun",
11096cddcc7aSBen Greear 	"d_tx_ppdu_abort",
111017818dfaSColin Ian King 	"d_tx_mpdu_requeued",
11116cddcc7aSBen Greear 	"d_tx_excessive_retries",
11126cddcc7aSBen Greear 	"d_tx_hw_rate",
11136cddcc7aSBen Greear 	"d_tx_dropped_sw_retries",
11146cddcc7aSBen Greear 	"d_tx_illegal_rate",
11156cddcc7aSBen Greear 	"d_tx_continuous_xretries",
11166cddcc7aSBen Greear 	"d_tx_timeout",
11176cddcc7aSBen Greear 	"d_tx_mpdu_txop_limit",
11186cddcc7aSBen Greear 	"d_pdev_resets",
11196cddcc7aSBen Greear 	"d_rx_mid_ppdu_route_change",
11206cddcc7aSBen Greear 	"d_rx_status",
11216cddcc7aSBen Greear 	"d_rx_extra_frags_ring0",
11226cddcc7aSBen Greear 	"d_rx_extra_frags_ring1",
11236cddcc7aSBen Greear 	"d_rx_extra_frags_ring2",
11246cddcc7aSBen Greear 	"d_rx_extra_frags_ring3",
11256cddcc7aSBen Greear 	"d_rx_msdu_htt",
11266cddcc7aSBen Greear 	"d_rx_mpdu_htt",
11276cddcc7aSBen Greear 	"d_rx_msdu_stack",
11286cddcc7aSBen Greear 	"d_rx_mpdu_stack",
11296cddcc7aSBen Greear 	"d_rx_phy_err",
11306cddcc7aSBen Greear 	"d_rx_phy_err_drops",
11316cddcc7aSBen Greear 	"d_rx_mpdu_errors", /* FCS, MIC, ENC */
11326cddcc7aSBen Greear 	"d_fw_crash_count",
11336cddcc7aSBen Greear 	"d_fw_warm_reset_count",
11346cddcc7aSBen Greear 	"d_fw_cold_reset_count",
11356cddcc7aSBen Greear };
11366cddcc7aSBen Greear 
11376cddcc7aSBen Greear #define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
11386cddcc7aSBen Greear 
ath10k_debug_get_et_strings(struct ieee80211_hw * hw,struct ieee80211_vif * vif,u32 sset,u8 * data)11396cddcc7aSBen Greear void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
11406cddcc7aSBen Greear 				 struct ieee80211_vif *vif,
11416cddcc7aSBen Greear 				 u32 sset, u8 *data)
11426cddcc7aSBen Greear {
11436cddcc7aSBen Greear 	if (sset == ETH_SS_STATS)
1144cb4c132eSDmitry Antipov 		memcpy(data, ath10k_gstrings_stats,
11456cddcc7aSBen Greear 		       sizeof(ath10k_gstrings_stats));
11466cddcc7aSBen Greear }
11476cddcc7aSBen Greear 
ath10k_debug_get_et_sset_count(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int sset)11486cddcc7aSBen Greear int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
11496cddcc7aSBen Greear 				   struct ieee80211_vif *vif, int sset)
11506cddcc7aSBen Greear {
11516cddcc7aSBen Greear 	if (sset == ETH_SS_STATS)
11526cddcc7aSBen Greear 		return ATH10K_SSTATS_LEN;
11536cddcc7aSBen Greear 
11546cddcc7aSBen Greear 	return 0;
11556cddcc7aSBen Greear }
11566cddcc7aSBen Greear 
ath10k_debug_get_et_stats(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ethtool_stats * stats,u64 * data)11576cddcc7aSBen Greear void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
11586cddcc7aSBen Greear 			       struct ieee80211_vif *vif,
11596cddcc7aSBen Greear 			       struct ethtool_stats *stats, u64 *data)
11606cddcc7aSBen Greear {
11616cddcc7aSBen Greear 	struct ath10k *ar = hw->priv;
11626cddcc7aSBen Greear 	static const struct ath10k_fw_stats_pdev zero_stats = {};
11636cddcc7aSBen Greear 	const struct ath10k_fw_stats_pdev *pdev_stats;
11646cddcc7aSBen Greear 	int i = 0, ret;
11656cddcc7aSBen Greear 
11666cddcc7aSBen Greear 	mutex_lock(&ar->conf_mutex);
11676cddcc7aSBen Greear 
11686cddcc7aSBen Greear 	if (ar->state == ATH10K_STATE_ON) {
11696cddcc7aSBen Greear 		ret = ath10k_debug_fw_stats_request(ar);
11706cddcc7aSBen Greear 		if (ret) {
11716cddcc7aSBen Greear 			/* just print a warning and try to use older results */
11726cddcc7aSBen Greear 			ath10k_warn(ar,
11736cddcc7aSBen Greear 				    "failed to get fw stats for ethtool: %d\n",
11746cddcc7aSBen Greear 				    ret);
11756cddcc7aSBen Greear 		}
11766cddcc7aSBen Greear 	}
11776cddcc7aSBen Greear 
11786cddcc7aSBen Greear 	pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs,
11796cddcc7aSBen Greear 					      struct ath10k_fw_stats_pdev,
11806cddcc7aSBen Greear 					      list);
11816cddcc7aSBen Greear 	if (!pdev_stats) {
11826cddcc7aSBen Greear 		/* no results available so just return zeroes */
11836cddcc7aSBen Greear 		pdev_stats = &zero_stats;
11846cddcc7aSBen Greear 	}
11856cddcc7aSBen Greear 
11866cddcc7aSBen Greear 	spin_lock_bh(&ar->data_lock);
11876cddcc7aSBen Greear 
11886cddcc7aSBen Greear 	data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
11896cddcc7aSBen Greear 	data[i++] = 0; /* tx bytes */
11906cddcc7aSBen Greear 	data[i++] = pdev_stats->htt_mpdus;
11916cddcc7aSBen Greear 	data[i++] = 0; /* rx bytes */
11926cddcc7aSBen Greear 	data[i++] = pdev_stats->ch_noise_floor;
11936cddcc7aSBen Greear 	data[i++] = pdev_stats->cycle_count;
11946cddcc7aSBen Greear 	data[i++] = pdev_stats->phy_err_count;
11956cddcc7aSBen Greear 	data[i++] = pdev_stats->rts_bad;
11966cddcc7aSBen Greear 	data[i++] = pdev_stats->rts_good;
11976cddcc7aSBen Greear 	data[i++] = pdev_stats->chan_tx_power;
11986cddcc7aSBen Greear 	data[i++] = pdev_stats->fcs_bad;
1199ea0c3e2aSLinus Lüssing 	data[i++] = ar->stats.rx_crc_err_drop;
12006cddcc7aSBen Greear 	data[i++] = pdev_stats->no_beacons;
12016cddcc7aSBen Greear 	data[i++] = pdev_stats->mpdu_enqued;
12026cddcc7aSBen Greear 	data[i++] = pdev_stats->msdu_enqued;
12036cddcc7aSBen Greear 	data[i++] = pdev_stats->wmm_drop;
12046cddcc7aSBen Greear 	data[i++] = pdev_stats->local_enqued;
12056cddcc7aSBen Greear 	data[i++] = pdev_stats->local_freed;
12066cddcc7aSBen Greear 	data[i++] = pdev_stats->hw_queued;
12076cddcc7aSBen Greear 	data[i++] = pdev_stats->hw_reaped;
12086cddcc7aSBen Greear 	data[i++] = pdev_stats->underrun;
12096cddcc7aSBen Greear 	data[i++] = pdev_stats->tx_abort;
121017818dfaSColin Ian King 	data[i++] = pdev_stats->mpdus_requeued;
12116cddcc7aSBen Greear 	data[i++] = pdev_stats->tx_ko;
12126cddcc7aSBen Greear 	data[i++] = pdev_stats->data_rc;
12136cddcc7aSBen Greear 	data[i++] = pdev_stats->sw_retry_failure;
12146cddcc7aSBen Greear 	data[i++] = pdev_stats->illgl_rate_phy_err;
12156cddcc7aSBen Greear 	data[i++] = pdev_stats->pdev_cont_xretry;
12166cddcc7aSBen Greear 	data[i++] = pdev_stats->pdev_tx_timeout;
12176cddcc7aSBen Greear 	data[i++] = pdev_stats->txop_ovf;
12186cddcc7aSBen Greear 	data[i++] = pdev_stats->pdev_resets;
12196cddcc7aSBen Greear 	data[i++] = pdev_stats->mid_ppdu_route_change;
12206cddcc7aSBen Greear 	data[i++] = pdev_stats->status_rcvd;
12216cddcc7aSBen Greear 	data[i++] = pdev_stats->r0_frags;
12226cddcc7aSBen Greear 	data[i++] = pdev_stats->r1_frags;
12236cddcc7aSBen Greear 	data[i++] = pdev_stats->r2_frags;
12246cddcc7aSBen Greear 	data[i++] = pdev_stats->r3_frags;
12256cddcc7aSBen Greear 	data[i++] = pdev_stats->htt_msdus;
12266cddcc7aSBen Greear 	data[i++] = pdev_stats->htt_mpdus;
12276cddcc7aSBen Greear 	data[i++] = pdev_stats->loc_msdus;
12286cddcc7aSBen Greear 	data[i++] = pdev_stats->loc_mpdus;
12296cddcc7aSBen Greear 	data[i++] = pdev_stats->phy_errs;
12306cddcc7aSBen Greear 	data[i++] = pdev_stats->phy_err_drop;
12316cddcc7aSBen Greear 	data[i++] = pdev_stats->mpdu_errs;
12326cddcc7aSBen Greear 	data[i++] = ar->stats.fw_crash_counter;
12336cddcc7aSBen Greear 	data[i++] = ar->stats.fw_warm_reset_counter;
12346cddcc7aSBen Greear 	data[i++] = ar->stats.fw_cold_reset_counter;
12356cddcc7aSBen Greear 
12366cddcc7aSBen Greear 	spin_unlock_bh(&ar->data_lock);
12376cddcc7aSBen Greear 
12386cddcc7aSBen Greear 	mutex_unlock(&ar->conf_mutex);
12396cddcc7aSBen Greear 
12406cddcc7aSBen Greear 	WARN_ON(i != ATH10K_SSTATS_LEN);
12416cddcc7aSBen Greear }
12426cddcc7aSBen Greear 
1243f118a3e5SKalle Valo static const struct file_operations fops_fw_dbglog = {
1244f118a3e5SKalle Valo 	.read = ath10k_read_fw_dbglog,
1245f118a3e5SKalle Valo 	.write = ath10k_write_fw_dbglog,
1246f118a3e5SKalle Valo 	.open = simple_open,
1247f118a3e5SKalle Valo 	.owner = THIS_MODULE,
1248f118a3e5SKalle Valo 	.llseek = default_llseek,
1249f118a3e5SKalle Valo };
1250f118a3e5SKalle Valo 
ath10k_debug_cal_data_fetch(struct ath10k * ar)1251f67b107dSMarty Faltesek static int ath10k_debug_cal_data_fetch(struct ath10k *ar)
12527869b4faSKalle Valo {
12537869b4faSKalle Valo 	u32 hi_addr;
12547869b4faSKalle Valo 	__le32 addr;
12557869b4faSKalle Valo 	int ret;
12567869b4faSKalle Valo 
1257f67b107dSMarty Faltesek 	lockdep_assert_held(&ar->conf_mutex);
12587869b4faSKalle Valo 
1259f67b107dSMarty Faltesek 	if (WARN_ON(ar->hw_params.cal_data_len > ATH10K_DEBUG_CAL_DATA_LEN))
1260f67b107dSMarty Faltesek 		return -EINVAL;
12617869b4faSKalle Valo 
12626566abeaSWen Gong 	if (ar->hw_params.cal_data_len == 0)
12636566abeaSWen Gong 		return -EOPNOTSUPP;
12646566abeaSWen Gong 
12657869b4faSKalle Valo 	hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
12667869b4faSKalle Valo 
12677869b4faSKalle Valo 	ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
12687869b4faSKalle Valo 	if (ret) {
1269f67b107dSMarty Faltesek 		ath10k_warn(ar, "failed to read hi_board_data address: %d\n",
1270f67b107dSMarty Faltesek 			    ret);
1271f67b107dSMarty Faltesek 		return ret;
12727869b4faSKalle Valo 	}
12737869b4faSKalle Valo 
1274f67b107dSMarty Faltesek 	ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), ar->debug.cal_data,
12750b8e3c4cSRaja Mani 				   ar->hw_params.cal_data_len);
12767869b4faSKalle Valo 	if (ret) {
12777869b4faSKalle Valo 		ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
1278f67b107dSMarty Faltesek 		return ret;
12797869b4faSKalle Valo 	}
12807869b4faSKalle Valo 
1281f67b107dSMarty Faltesek 	return 0;
1282f67b107dSMarty Faltesek }
12837869b4faSKalle Valo 
ath10k_debug_cal_data_open(struct inode * inode,struct file * file)1284f67b107dSMarty Faltesek static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
1285f67b107dSMarty Faltesek {
1286f67b107dSMarty Faltesek 	struct ath10k *ar = inode->i_private;
1287f67b107dSMarty Faltesek 
1288f67b107dSMarty Faltesek 	mutex_lock(&ar->conf_mutex);
1289f67b107dSMarty Faltesek 
1290f67b107dSMarty Faltesek 	if (ar->state == ATH10K_STATE_ON ||
1291f67b107dSMarty Faltesek 	    ar->state == ATH10K_STATE_UTF) {
1292f67b107dSMarty Faltesek 		ath10k_debug_cal_data_fetch(ar);
1293f67b107dSMarty Faltesek 	}
1294f67b107dSMarty Faltesek 
1295f67b107dSMarty Faltesek 	file->private_data = ar;
12967869b4faSKalle Valo 	mutex_unlock(&ar->conf_mutex);
12977869b4faSKalle Valo 
12987869b4faSKalle Valo 	return 0;
12997869b4faSKalle Valo }
13007869b4faSKalle Valo 
ath10k_debug_cal_data_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)13017869b4faSKalle Valo static ssize_t ath10k_debug_cal_data_read(struct file *file,
13027869b4faSKalle Valo 					  char __user *user_buf,
13037869b4faSKalle Valo 					  size_t count, loff_t *ppos)
13047869b4faSKalle Valo {
13050b8e3c4cSRaja Mani 	struct ath10k *ar = file->private_data;
13067869b4faSKalle Valo 
1307f67b107dSMarty Faltesek 	mutex_lock(&ar->conf_mutex);
13087869b4faSKalle Valo 
1309f67b107dSMarty Faltesek 	count = simple_read_from_buffer(user_buf, count, ppos,
1310f67b107dSMarty Faltesek 					ar->debug.cal_data,
1311f67b107dSMarty Faltesek 					ar->hw_params.cal_data_len);
13127869b4faSKalle Valo 
1313f67b107dSMarty Faltesek 	mutex_unlock(&ar->conf_mutex);
1314f67b107dSMarty Faltesek 
1315f67b107dSMarty Faltesek 	return count;
13167869b4faSKalle Valo }
13177869b4faSKalle Valo 
ath10k_write_ani_enable(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1318b3e71d7aSAshok Raj Nagarajan static ssize_t ath10k_write_ani_enable(struct file *file,
1319b3e71d7aSAshok Raj Nagarajan 				       const char __user *user_buf,
1320b3e71d7aSAshok Raj Nagarajan 				       size_t count, loff_t *ppos)
1321b3e71d7aSAshok Raj Nagarajan {
1322b3e71d7aSAshok Raj Nagarajan 	struct ath10k *ar = file->private_data;
1323b3e71d7aSAshok Raj Nagarajan 	int ret;
1324b3e71d7aSAshok Raj Nagarajan 	u8 enable;
1325b3e71d7aSAshok Raj Nagarajan 
1326b3e71d7aSAshok Raj Nagarajan 	if (kstrtou8_from_user(user_buf, count, 0, &enable))
1327b3e71d7aSAshok Raj Nagarajan 		return -EINVAL;
1328b3e71d7aSAshok Raj Nagarajan 
1329b3e71d7aSAshok Raj Nagarajan 	mutex_lock(&ar->conf_mutex);
1330b3e71d7aSAshok Raj Nagarajan 
1331b3e71d7aSAshok Raj Nagarajan 	if (ar->ani_enabled == enable) {
1332b3e71d7aSAshok Raj Nagarajan 		ret = count;
1333b3e71d7aSAshok Raj Nagarajan 		goto exit;
1334b3e71d7aSAshok Raj Nagarajan 	}
1335b3e71d7aSAshok Raj Nagarajan 
1336b3e71d7aSAshok Raj Nagarajan 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->ani_enable,
1337b3e71d7aSAshok Raj Nagarajan 					enable);
1338b3e71d7aSAshok Raj Nagarajan 	if (ret) {
1339b3e71d7aSAshok Raj Nagarajan 		ath10k_warn(ar, "ani_enable failed from debugfs: %d\n", ret);
1340b3e71d7aSAshok Raj Nagarajan 		goto exit;
1341b3e71d7aSAshok Raj Nagarajan 	}
1342b3e71d7aSAshok Raj Nagarajan 	ar->ani_enabled = enable;
1343b3e71d7aSAshok Raj Nagarajan 
1344b3e71d7aSAshok Raj Nagarajan 	ret = count;
1345b3e71d7aSAshok Raj Nagarajan 
1346b3e71d7aSAshok Raj Nagarajan exit:
1347b3e71d7aSAshok Raj Nagarajan 	mutex_unlock(&ar->conf_mutex);
1348b3e71d7aSAshok Raj Nagarajan 
1349b3e71d7aSAshok Raj Nagarajan 	return ret;
1350b3e71d7aSAshok Raj Nagarajan }
1351b3e71d7aSAshok Raj Nagarajan 
ath10k_read_ani_enable(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1352b3e71d7aSAshok Raj Nagarajan static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,
1353b3e71d7aSAshok Raj Nagarajan 				      size_t count, loff_t *ppos)
1354b3e71d7aSAshok Raj Nagarajan {
1355b3e71d7aSAshok Raj Nagarajan 	struct ath10k *ar = file->private_data;
1356182f1e5aSAmadeusz Sławiński 	size_t len;
1357b3e71d7aSAshok Raj Nagarajan 	char buf[32];
1358b3e71d7aSAshok Raj Nagarajan 
1359182f1e5aSAmadeusz Sławiński 	len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled);
1360b3e71d7aSAshok Raj Nagarajan 
1361b3e71d7aSAshok Raj Nagarajan 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1362b3e71d7aSAshok Raj Nagarajan }
1363b3e71d7aSAshok Raj Nagarajan 
1364b3e71d7aSAshok Raj Nagarajan static const struct file_operations fops_ani_enable = {
1365b3e71d7aSAshok Raj Nagarajan 	.read = ath10k_read_ani_enable,
1366b3e71d7aSAshok Raj Nagarajan 	.write = ath10k_write_ani_enable,
1367b3e71d7aSAshok Raj Nagarajan 	.open = simple_open,
1368b3e71d7aSAshok Raj Nagarajan 	.owner = THIS_MODULE,
1369b3e71d7aSAshok Raj Nagarajan 	.llseek = default_llseek,
1370b3e71d7aSAshok Raj Nagarajan };
1371b3e71d7aSAshok Raj Nagarajan 
13727869b4faSKalle Valo static const struct file_operations fops_cal_data = {
13737869b4faSKalle Valo 	.open = ath10k_debug_cal_data_open,
13747869b4faSKalle Valo 	.read = ath10k_debug_cal_data_read,
13757869b4faSKalle Valo 	.owner = THIS_MODULE,
13767869b4faSKalle Valo 	.llseek = default_llseek,
13777869b4faSKalle Valo };
13787869b4faSKalle Valo 
ath10k_read_nf_cal_period(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1379a7bd3e99SPeter Oh static ssize_t ath10k_read_nf_cal_period(struct file *file,
1380a7bd3e99SPeter Oh 					 char __user *user_buf,
1381a7bd3e99SPeter Oh 					 size_t count, loff_t *ppos)
1382a7bd3e99SPeter Oh {
1383a7bd3e99SPeter Oh 	struct ath10k *ar = file->private_data;
1384182f1e5aSAmadeusz Sławiński 	size_t len;
1385a7bd3e99SPeter Oh 	char buf[32];
1386a7bd3e99SPeter Oh 
1387182f1e5aSAmadeusz Sławiński 	len = scnprintf(buf, sizeof(buf), "%d\n", ar->debug.nf_cal_period);
1388a7bd3e99SPeter Oh 
1389a7bd3e99SPeter Oh 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1390a7bd3e99SPeter Oh }
1391a7bd3e99SPeter Oh 
ath10k_write_nf_cal_period(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1392a7bd3e99SPeter Oh static ssize_t ath10k_write_nf_cal_period(struct file *file,
1393a7bd3e99SPeter Oh 					  const char __user *user_buf,
1394a7bd3e99SPeter Oh 					  size_t count, loff_t *ppos)
1395a7bd3e99SPeter Oh {
1396a7bd3e99SPeter Oh 	struct ath10k *ar = file->private_data;
1397a7bd3e99SPeter Oh 	unsigned long period;
1398a7bd3e99SPeter Oh 	int ret;
1399a7bd3e99SPeter Oh 
1400a7bd3e99SPeter Oh 	ret = kstrtoul_from_user(user_buf, count, 0, &period);
1401a7bd3e99SPeter Oh 	if (ret)
1402a7bd3e99SPeter Oh 		return ret;
1403a7bd3e99SPeter Oh 
1404a7bd3e99SPeter Oh 	if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX)
1405a7bd3e99SPeter Oh 		return -EINVAL;
1406a7bd3e99SPeter Oh 
1407a7bd3e99SPeter Oh 	/* there's no way to switch back to the firmware default */
1408a7bd3e99SPeter Oh 	if (period == 0)
1409a7bd3e99SPeter Oh 		return -EINVAL;
1410a7bd3e99SPeter Oh 
1411a7bd3e99SPeter Oh 	mutex_lock(&ar->conf_mutex);
1412a7bd3e99SPeter Oh 
1413a7bd3e99SPeter Oh 	ar->debug.nf_cal_period = period;
1414a7bd3e99SPeter Oh 
1415a7bd3e99SPeter Oh 	if (ar->state != ATH10K_STATE_ON) {
1416a7bd3e99SPeter Oh 		/* firmware is not running, nothing else to do */
1417a7bd3e99SPeter Oh 		ret = count;
1418a7bd3e99SPeter Oh 		goto exit;
1419a7bd3e99SPeter Oh 	}
1420a7bd3e99SPeter Oh 
1421a7bd3e99SPeter Oh 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period,
1422a7bd3e99SPeter Oh 					ar->debug.nf_cal_period);
1423a7bd3e99SPeter Oh 	if (ret) {
1424a7bd3e99SPeter Oh 		ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n",
1425a7bd3e99SPeter Oh 			    ret);
1426a7bd3e99SPeter Oh 		goto exit;
1427a7bd3e99SPeter Oh 	}
1428a7bd3e99SPeter Oh 
1429a7bd3e99SPeter Oh 	ret = count;
1430a7bd3e99SPeter Oh 
1431a7bd3e99SPeter Oh exit:
1432a7bd3e99SPeter Oh 	mutex_unlock(&ar->conf_mutex);
1433a7bd3e99SPeter Oh 
1434a7bd3e99SPeter Oh 	return ret;
1435a7bd3e99SPeter Oh }
1436a7bd3e99SPeter Oh 
1437a7bd3e99SPeter Oh static const struct file_operations fops_nf_cal_period = {
1438a7bd3e99SPeter Oh 	.read = ath10k_read_nf_cal_period,
1439a7bd3e99SPeter Oh 	.write = ath10k_write_nf_cal_period,
1440a7bd3e99SPeter Oh 	.open = simple_open,
1441a7bd3e99SPeter Oh 	.owner = THIS_MODULE,
1442a7bd3e99SPeter Oh 	.llseek = default_llseek,
1443a7bd3e99SPeter Oh };
1444a7bd3e99SPeter Oh 
144529542666SMaharaja Kennadyrajan #define ATH10K_TPC_CONFIG_BUF_SIZE	(1024 * 1024)
144629542666SMaharaja Kennadyrajan 
ath10k_debug_tpc_stats_request(struct ath10k * ar)144729542666SMaharaja Kennadyrajan static int ath10k_debug_tpc_stats_request(struct ath10k *ar)
144829542666SMaharaja Kennadyrajan {
144929542666SMaharaja Kennadyrajan 	int ret;
145029542666SMaharaja Kennadyrajan 	unsigned long time_left;
145129542666SMaharaja Kennadyrajan 
145229542666SMaharaja Kennadyrajan 	lockdep_assert_held(&ar->conf_mutex);
145329542666SMaharaja Kennadyrajan 
145429542666SMaharaja Kennadyrajan 	reinit_completion(&ar->debug.tpc_complete);
145529542666SMaharaja Kennadyrajan 
145629542666SMaharaja Kennadyrajan 	ret = ath10k_wmi_pdev_get_tpc_config(ar, WMI_TPC_CONFIG_PARAM);
145729542666SMaharaja Kennadyrajan 	if (ret) {
145829542666SMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to request tpc config: %d\n", ret);
145929542666SMaharaja Kennadyrajan 		return ret;
146029542666SMaharaja Kennadyrajan 	}
146129542666SMaharaja Kennadyrajan 
146229542666SMaharaja Kennadyrajan 	time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
146329542666SMaharaja Kennadyrajan 						1 * HZ);
146429542666SMaharaja Kennadyrajan 	if (time_left == 0)
146529542666SMaharaja Kennadyrajan 		return -ETIMEDOUT;
146629542666SMaharaja Kennadyrajan 
146729542666SMaharaja Kennadyrajan 	return 0;
146829542666SMaharaja Kennadyrajan }
146929542666SMaharaja Kennadyrajan 
ath10k_debug_tpc_stats_process(struct ath10k * ar,struct ath10k_tpc_stats * tpc_stats)147029542666SMaharaja Kennadyrajan void ath10k_debug_tpc_stats_process(struct ath10k *ar,
147129542666SMaharaja Kennadyrajan 				    struct ath10k_tpc_stats *tpc_stats)
147229542666SMaharaja Kennadyrajan {
147329542666SMaharaja Kennadyrajan 	spin_lock_bh(&ar->data_lock);
147429542666SMaharaja Kennadyrajan 
147529542666SMaharaja Kennadyrajan 	kfree(ar->debug.tpc_stats);
147629542666SMaharaja Kennadyrajan 	ar->debug.tpc_stats = tpc_stats;
147729542666SMaharaja Kennadyrajan 	complete(&ar->debug.tpc_complete);
147829542666SMaharaja Kennadyrajan 
147929542666SMaharaja Kennadyrajan 	spin_unlock_bh(&ar->data_lock);
148029542666SMaharaja Kennadyrajan }
148129542666SMaharaja Kennadyrajan 
1482bc64d052SMaharaja Kennadyrajan void
ath10k_debug_tpc_stats_final_process(struct ath10k * ar,struct ath10k_tpc_stats_final * tpc_stats)1483bc64d052SMaharaja Kennadyrajan ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
1484bc64d052SMaharaja Kennadyrajan 				     struct ath10k_tpc_stats_final *tpc_stats)
1485bc64d052SMaharaja Kennadyrajan {
1486bc64d052SMaharaja Kennadyrajan 	spin_lock_bh(&ar->data_lock);
1487bc64d052SMaharaja Kennadyrajan 
1488bc64d052SMaharaja Kennadyrajan 	kfree(ar->debug.tpc_stats_final);
1489bc64d052SMaharaja Kennadyrajan 	ar->debug.tpc_stats_final = tpc_stats;
1490bc64d052SMaharaja Kennadyrajan 	complete(&ar->debug.tpc_complete);
1491bc64d052SMaharaja Kennadyrajan 
1492bc64d052SMaharaja Kennadyrajan 	spin_unlock_bh(&ar->data_lock);
1493bc64d052SMaharaja Kennadyrajan }
1494bc64d052SMaharaja Kennadyrajan 
ath10k_tpc_stats_print(struct ath10k_tpc_stats * tpc_stats,unsigned int j,char * buf,size_t * len)149529542666SMaharaja Kennadyrajan static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
1496182f1e5aSAmadeusz Sławiński 				   unsigned int j, char *buf, size_t *len)
149729542666SMaharaja Kennadyrajan {
1498182f1e5aSAmadeusz Sławiński 	int i;
1499182f1e5aSAmadeusz Sławiński 	size_t buf_len;
150029542666SMaharaja Kennadyrajan 	static const char table_str[][5] = { "CDD",
150129542666SMaharaja Kennadyrajan 					     "STBC",
150229542666SMaharaja Kennadyrajan 					     "TXBF" };
150329542666SMaharaja Kennadyrajan 	static const char pream_str[][6] = { "CCK",
150429542666SMaharaja Kennadyrajan 					     "OFDM",
150529542666SMaharaja Kennadyrajan 					     "HT20",
150629542666SMaharaja Kennadyrajan 					     "HT40",
150729542666SMaharaja Kennadyrajan 					     "VHT20",
150829542666SMaharaja Kennadyrajan 					     "VHT40",
150929542666SMaharaja Kennadyrajan 					     "VHT80",
151029542666SMaharaja Kennadyrajan 					     "HTCUP" };
151129542666SMaharaja Kennadyrajan 
151229542666SMaharaja Kennadyrajan 	buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
151329542666SMaharaja Kennadyrajan 	*len += scnprintf(buf + *len, buf_len - *len,
151429542666SMaharaja Kennadyrajan 			  "********************************\n");
151529542666SMaharaja Kennadyrajan 	*len += scnprintf(buf + *len, buf_len - *len,
151629542666SMaharaja Kennadyrajan 			  "******************* %s POWER TABLE ****************\n",
151729542666SMaharaja Kennadyrajan 			  table_str[j]);
151829542666SMaharaja Kennadyrajan 	*len += scnprintf(buf + *len, buf_len - *len,
151929542666SMaharaja Kennadyrajan 			  "********************************\n");
152029542666SMaharaja Kennadyrajan 	*len += scnprintf(buf + *len, buf_len - *len,
15214b190675STamizh Chelvam 			  "No.  Preamble Rate_code ");
15224b190675STamizh Chelvam 
1523c5329b2dSMiaoqing Pan 	for (i = 0; i < tpc_stats->num_tx_chain; i++)
15244b190675STamizh Chelvam 		*len += scnprintf(buf + *len, buf_len - *len,
15254b190675STamizh Chelvam 				  "tpc_value%d ", i);
15264b190675STamizh Chelvam 
15274b190675STamizh Chelvam 	*len += scnprintf(buf + *len, buf_len - *len, "\n");
152829542666SMaharaja Kennadyrajan 
152929542666SMaharaja Kennadyrajan 	for (i = 0; i < tpc_stats->rate_max; i++) {
153029542666SMaharaja Kennadyrajan 		*len += scnprintf(buf + *len, buf_len - *len,
153129542666SMaharaja Kennadyrajan 				  "%8d %s 0x%2x %s\n", i,
153229542666SMaharaja Kennadyrajan 				  pream_str[tpc_stats->tpc_table[j].pream_idx[i]],
153329542666SMaharaja Kennadyrajan 				  tpc_stats->tpc_table[j].rate_code[i],
153429542666SMaharaja Kennadyrajan 				  tpc_stats->tpc_table[j].tpc_value[i]);
153529542666SMaharaja Kennadyrajan 	}
153629542666SMaharaja Kennadyrajan 
153729542666SMaharaja Kennadyrajan 	*len += scnprintf(buf + *len, buf_len - *len,
153829542666SMaharaja Kennadyrajan 			  "***********************************\n");
153929542666SMaharaja Kennadyrajan }
154029542666SMaharaja Kennadyrajan 
ath10k_tpc_stats_fill(struct ath10k * ar,struct ath10k_tpc_stats * tpc_stats,char * buf)154129542666SMaharaja Kennadyrajan static void ath10k_tpc_stats_fill(struct ath10k *ar,
154229542666SMaharaja Kennadyrajan 				  struct ath10k_tpc_stats *tpc_stats,
154329542666SMaharaja Kennadyrajan 				  char *buf)
154429542666SMaharaja Kennadyrajan {
1545182f1e5aSAmadeusz Sławiński 	int j;
1546182f1e5aSAmadeusz Sławiński 	size_t len, buf_len;
154729542666SMaharaja Kennadyrajan 
154829542666SMaharaja Kennadyrajan 	len = 0;
154929542666SMaharaja Kennadyrajan 	buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
155029542666SMaharaja Kennadyrajan 
155129542666SMaharaja Kennadyrajan 	spin_lock_bh(&ar->data_lock);
155229542666SMaharaja Kennadyrajan 
155329542666SMaharaja Kennadyrajan 	if (!tpc_stats) {
155429542666SMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to get tpc stats\n");
155529542666SMaharaja Kennadyrajan 		goto unlock;
155629542666SMaharaja Kennadyrajan 	}
155729542666SMaharaja Kennadyrajan 
155829542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len, "\n");
155929542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
156029542666SMaharaja Kennadyrajan 			 "*************************************\n");
156129542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
156229542666SMaharaja Kennadyrajan 			 "TPC config for channel %4d mode %d\n",
156329542666SMaharaja Kennadyrajan 			 tpc_stats->chan_freq,
156429542666SMaharaja Kennadyrajan 			 tpc_stats->phy_mode);
156529542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
156629542666SMaharaja Kennadyrajan 			 "*************************************\n");
156729542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
156829542666SMaharaja Kennadyrajan 			 "CTL		=  0x%2x Reg. Domain		= %2d\n",
156929542666SMaharaja Kennadyrajan 			 tpc_stats->ctl,
157029542666SMaharaja Kennadyrajan 			 tpc_stats->reg_domain);
157129542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
157229542666SMaharaja Kennadyrajan 			 "Antenna Gain	= %2d Reg. Max Antenna Gain	=  %2d\n",
157329542666SMaharaja Kennadyrajan 			 tpc_stats->twice_antenna_gain,
157429542666SMaharaja Kennadyrajan 			 tpc_stats->twice_antenna_reduction);
157529542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
157629542666SMaharaja Kennadyrajan 			 "Power Limit	= %2d Reg. Max Power		= %2d\n",
157729542666SMaharaja Kennadyrajan 			 tpc_stats->power_limit,
157829542666SMaharaja Kennadyrajan 			 tpc_stats->twice_max_rd_power / 2);
157929542666SMaharaja Kennadyrajan 	len += scnprintf(buf + len, buf_len - len,
158029542666SMaharaja Kennadyrajan 			 "Num tx chains	= %2d Num supported rates	= %2d\n",
158129542666SMaharaja Kennadyrajan 			 tpc_stats->num_tx_chain,
158229542666SMaharaja Kennadyrajan 			 tpc_stats->rate_max);
158329542666SMaharaja Kennadyrajan 
1584e871fb63SMaharaja Kennadyrajan 	for (j = 0; j < WMI_TPC_FLAG; j++) {
158529542666SMaharaja Kennadyrajan 		switch (j) {
158629542666SMaharaja Kennadyrajan 		case WMI_TPC_TABLE_TYPE_CDD:
158729542666SMaharaja Kennadyrajan 			if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
158829542666SMaharaja Kennadyrajan 				len += scnprintf(buf + len, buf_len - len,
158929542666SMaharaja Kennadyrajan 						 "CDD not supported\n");
159029542666SMaharaja Kennadyrajan 				break;
159129542666SMaharaja Kennadyrajan 			}
159229542666SMaharaja Kennadyrajan 
159329542666SMaharaja Kennadyrajan 			ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
159429542666SMaharaja Kennadyrajan 			break;
159529542666SMaharaja Kennadyrajan 		case WMI_TPC_TABLE_TYPE_STBC:
159629542666SMaharaja Kennadyrajan 			if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
159729542666SMaharaja Kennadyrajan 				len += scnprintf(buf + len, buf_len - len,
159829542666SMaharaja Kennadyrajan 						 "STBC not supported\n");
159929542666SMaharaja Kennadyrajan 				break;
160029542666SMaharaja Kennadyrajan 			}
160129542666SMaharaja Kennadyrajan 
160229542666SMaharaja Kennadyrajan 			ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
160329542666SMaharaja Kennadyrajan 			break;
160429542666SMaharaja Kennadyrajan 		case WMI_TPC_TABLE_TYPE_TXBF:
160529542666SMaharaja Kennadyrajan 			if (tpc_stats->flag[j] == ATH10K_TPC_TABLE_TYPE_FLAG) {
160629542666SMaharaja Kennadyrajan 				len += scnprintf(buf + len, buf_len - len,
160729542666SMaharaja Kennadyrajan 						 "TXBF not supported\n***************************\n");
160829542666SMaharaja Kennadyrajan 				break;
160929542666SMaharaja Kennadyrajan 			}
161029542666SMaharaja Kennadyrajan 
161129542666SMaharaja Kennadyrajan 			ath10k_tpc_stats_print(tpc_stats, j, buf, &len);
161229542666SMaharaja Kennadyrajan 			break;
161329542666SMaharaja Kennadyrajan 		default:
161429542666SMaharaja Kennadyrajan 			len += scnprintf(buf + len, buf_len - len,
161529542666SMaharaja Kennadyrajan 					 "Invalid Type\n");
161629542666SMaharaja Kennadyrajan 			break;
161729542666SMaharaja Kennadyrajan 		}
161829542666SMaharaja Kennadyrajan 	}
161929542666SMaharaja Kennadyrajan 
162029542666SMaharaja Kennadyrajan unlock:
162129542666SMaharaja Kennadyrajan 	spin_unlock_bh(&ar->data_lock);
162229542666SMaharaja Kennadyrajan 
162329542666SMaharaja Kennadyrajan 	if (len >= buf_len)
162429542666SMaharaja Kennadyrajan 		buf[len - 1] = 0;
162529542666SMaharaja Kennadyrajan 	else
162629542666SMaharaja Kennadyrajan 		buf[len] = 0;
162729542666SMaharaja Kennadyrajan }
162829542666SMaharaja Kennadyrajan 
ath10k_tpc_stats_open(struct inode * inode,struct file * file)162929542666SMaharaja Kennadyrajan static int ath10k_tpc_stats_open(struct inode *inode, struct file *file)
163029542666SMaharaja Kennadyrajan {
163129542666SMaharaja Kennadyrajan 	struct ath10k *ar = inode->i_private;
163229542666SMaharaja Kennadyrajan 	void *buf = NULL;
163329542666SMaharaja Kennadyrajan 	int ret;
163429542666SMaharaja Kennadyrajan 
163529542666SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
163629542666SMaharaja Kennadyrajan 
163729542666SMaharaja Kennadyrajan 	if (ar->state != ATH10K_STATE_ON) {
163829542666SMaharaja Kennadyrajan 		ret = -ENETDOWN;
163929542666SMaharaja Kennadyrajan 		goto err_unlock;
164029542666SMaharaja Kennadyrajan 	}
164129542666SMaharaja Kennadyrajan 
164229542666SMaharaja Kennadyrajan 	buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
164329542666SMaharaja Kennadyrajan 	if (!buf) {
164429542666SMaharaja Kennadyrajan 		ret = -ENOMEM;
164529542666SMaharaja Kennadyrajan 		goto err_unlock;
164629542666SMaharaja Kennadyrajan 	}
164729542666SMaharaja Kennadyrajan 
164829542666SMaharaja Kennadyrajan 	ret = ath10k_debug_tpc_stats_request(ar);
164929542666SMaharaja Kennadyrajan 	if (ret) {
165029542666SMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to request tpc config stats: %d\n",
165129542666SMaharaja Kennadyrajan 			    ret);
165229542666SMaharaja Kennadyrajan 		goto err_free;
165329542666SMaharaja Kennadyrajan 	}
165429542666SMaharaja Kennadyrajan 
165529542666SMaharaja Kennadyrajan 	ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
165629542666SMaharaja Kennadyrajan 	file->private_data = buf;
165729542666SMaharaja Kennadyrajan 
165829542666SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
165929542666SMaharaja Kennadyrajan 	return 0;
166029542666SMaharaja Kennadyrajan 
166129542666SMaharaja Kennadyrajan err_free:
166229542666SMaharaja Kennadyrajan 	vfree(buf);
166329542666SMaharaja Kennadyrajan 
166429542666SMaharaja Kennadyrajan err_unlock:
166529542666SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
166629542666SMaharaja Kennadyrajan 	return ret;
166729542666SMaharaja Kennadyrajan }
166829542666SMaharaja Kennadyrajan 
ath10k_tpc_stats_release(struct inode * inode,struct file * file)166929542666SMaharaja Kennadyrajan static int ath10k_tpc_stats_release(struct inode *inode, struct file *file)
167029542666SMaharaja Kennadyrajan {
167129542666SMaharaja Kennadyrajan 	vfree(file->private_data);
167229542666SMaharaja Kennadyrajan 
167329542666SMaharaja Kennadyrajan 	return 0;
167429542666SMaharaja Kennadyrajan }
167529542666SMaharaja Kennadyrajan 
ath10k_tpc_stats_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)167629542666SMaharaja Kennadyrajan static ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf,
167729542666SMaharaja Kennadyrajan 				     size_t count, loff_t *ppos)
167829542666SMaharaja Kennadyrajan {
167929542666SMaharaja Kennadyrajan 	const char *buf = file->private_data;
1680182f1e5aSAmadeusz Sławiński 	size_t len = strlen(buf);
168129542666SMaharaja Kennadyrajan 
168229542666SMaharaja Kennadyrajan 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
168329542666SMaharaja Kennadyrajan }
168429542666SMaharaja Kennadyrajan 
168529542666SMaharaja Kennadyrajan static const struct file_operations fops_tpc_stats = {
168629542666SMaharaja Kennadyrajan 	.open = ath10k_tpc_stats_open,
168729542666SMaharaja Kennadyrajan 	.release = ath10k_tpc_stats_release,
168829542666SMaharaja Kennadyrajan 	.read = ath10k_tpc_stats_read,
168929542666SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
169029542666SMaharaja Kennadyrajan 	.llseek = default_llseek,
169129542666SMaharaja Kennadyrajan };
169229542666SMaharaja Kennadyrajan 
ath10k_debug_start(struct ath10k * ar)1693db66ea04SKalle Valo int ath10k_debug_start(struct ath10k *ar)
1694db66ea04SKalle Valo {
1695a3d135e5SKalle Valo 	int ret;
1696a3d135e5SKalle Valo 
169760631c5cSKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
169860631c5cSKalle Valo 
1699a3d135e5SKalle Valo 	ret = ath10k_debug_htt_stats_req(ar);
1700a3d135e5SKalle Valo 	if (ret)
1701a3d135e5SKalle Valo 		/* continue normally anyway, this isn't serious */
17027aa7a72aSMichal Kazior 		ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
17037aa7a72aSMichal Kazior 			    ret);
1704a3d135e5SKalle Valo 
1705f118a3e5SKalle Valo 	if (ar->debug.fw_dbglog_mask) {
1706467210a6SSenthilKumar Jegadeesan 		ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
1707467210a6SSenthilKumar Jegadeesan 					    ATH10K_DBGLOG_LEVEL_WARN);
1708f118a3e5SKalle Valo 		if (ret)
1709f118a3e5SKalle Valo 			/* not serious */
17107aa7a72aSMichal Kazior 			ath10k_warn(ar, "failed to enable dbglog during start: %d",
1711f118a3e5SKalle Valo 				    ret);
1712f118a3e5SKalle Valo 	}
1713f118a3e5SKalle Valo 
17147f9befbbSAnilkumar Kolli 	if (ar->pktlog_filter) {
171590174455SRajkumar Manoharan 		ret = ath10k_wmi_pdev_pktlog_enable(ar,
17167f9befbbSAnilkumar Kolli 						    ar->pktlog_filter);
171790174455SRajkumar Manoharan 		if (ret)
171890174455SRajkumar Manoharan 			/* not serious */
171990174455SRajkumar Manoharan 			ath10k_warn(ar,
172090174455SRajkumar Manoharan 				    "failed to enable pktlog filter %x: %d\n",
17217f9befbbSAnilkumar Kolli 				    ar->pktlog_filter, ret);
172290174455SRajkumar Manoharan 	} else {
172390174455SRajkumar Manoharan 		ret = ath10k_wmi_pdev_pktlog_disable(ar);
172490174455SRajkumar Manoharan 		if (ret)
172590174455SRajkumar Manoharan 			/* not serious */
172690174455SRajkumar Manoharan 			ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
172790174455SRajkumar Manoharan 	}
172890174455SRajkumar Manoharan 
17295db98aeeSSurabhi Vishnoi 	if (ar->debug.nf_cal_period &&
17305db98aeeSSurabhi Vishnoi 	    !test_bit(ATH10K_FW_FEATURE_NON_BMI,
17315db98aeeSSurabhi Vishnoi 		      ar->normal_mode_fw.fw_file.fw_features)) {
1732a7bd3e99SPeter Oh 		ret = ath10k_wmi_pdev_set_param(ar,
1733a7bd3e99SPeter Oh 						ar->wmi.pdev_param->cal_period,
1734a7bd3e99SPeter Oh 						ar->debug.nf_cal_period);
1735a7bd3e99SPeter Oh 		if (ret)
1736a7bd3e99SPeter Oh 			/* not serious */
1737a7bd3e99SPeter Oh 			ath10k_warn(ar, "cal period cfg failed from debug start: %d\n",
1738a7bd3e99SPeter Oh 				    ret);
1739a7bd3e99SPeter Oh 	}
1740a7bd3e99SPeter Oh 
174190174455SRajkumar Manoharan 	return ret;
1742db66ea04SKalle Valo }
1743db66ea04SKalle Valo 
ath10k_debug_stop(struct ath10k * ar)1744db66ea04SKalle Valo void ath10k_debug_stop(struct ath10k *ar)
1745db66ea04SKalle Valo {
174660631c5cSKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
174760631c5cSKalle Valo 
17485db98aeeSSurabhi Vishnoi 	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
17495db98aeeSSurabhi Vishnoi 		      ar->normal_mode_fw.fw_file.fw_features))
1750f67b107dSMarty Faltesek 		ath10k_debug_cal_data_fetch(ar);
1751f67b107dSMarty Faltesek 
175260631c5cSKalle Valo 	/* Must not use _sync to avoid deadlock, we do that in
175360631c5cSKalle Valo 	 * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid
1754d6dfe25cSMarcin Rokicki 	 * warning from del_timer().
1755d6dfe25cSMarcin Rokicki 	 */
175660631c5cSKalle Valo 	if (ar->debug.htt_stats_mask != 0)
175760631c5cSKalle Valo 		cancel_delayed_work(&ar->debug.htt_stats_dwork);
1758d385623aSJanusz Dziedzic 
175990174455SRajkumar Manoharan 	ath10k_wmi_pdev_pktlog_disable(ar);
1760db66ea04SKalle Valo }
1761db66ea04SKalle Valo 
ath10k_write_simulate_radar(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)17629702c686SJanusz Dziedzic static ssize_t ath10k_write_simulate_radar(struct file *file,
17639702c686SJanusz Dziedzic 					   const char __user *user_buf,
17649702c686SJanusz Dziedzic 					   size_t count, loff_t *ppos)
17659702c686SJanusz Dziedzic {
17669702c686SJanusz Dziedzic 	struct ath10k *ar = file->private_data;
1767ca07baabSMohammed Shafi Shajakhan 	struct ath10k_vif *arvif;
1768ca07baabSMohammed Shafi Shajakhan 
1769762fd1aeSKalle Valo 	/* Just check for the first vif alone, as all the vifs will be
1770ca07baabSMohammed Shafi Shajakhan 	 * sharing the same channel and if the channel is disabled, all the
1771ca07baabSMohammed Shafi Shajakhan 	 * vifs will share the same 'is_started' state.
1772ca07baabSMohammed Shafi Shajakhan 	 */
1773ca07baabSMohammed Shafi Shajakhan 	arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
1774ca07baabSMohammed Shafi Shajakhan 	if (!arvif->is_started)
1775ca07baabSMohammed Shafi Shajakhan 		return -EINVAL;
17769702c686SJanusz Dziedzic 
17779702c686SJanusz Dziedzic 	ieee80211_radar_detected(ar->hw);
17789702c686SJanusz Dziedzic 
17799702c686SJanusz Dziedzic 	return count;
17809702c686SJanusz Dziedzic }
17819702c686SJanusz Dziedzic 
17829702c686SJanusz Dziedzic static const struct file_operations fops_simulate_radar = {
17839702c686SJanusz Dziedzic 	.write = ath10k_write_simulate_radar,
17849702c686SJanusz Dziedzic 	.open = simple_open,
17859702c686SJanusz Dziedzic 	.owner = THIS_MODULE,
17869702c686SJanusz Dziedzic 	.llseek = default_llseek,
17879702c686SJanusz Dziedzic };
17889702c686SJanusz Dziedzic 
17899702c686SJanusz Dziedzic #define ATH10K_DFS_STAT(s, p) (\
17909702c686SJanusz Dziedzic 	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
17919702c686SJanusz Dziedzic 			 ar->debug.dfs_stats.p))
17929702c686SJanusz Dziedzic 
17939702c686SJanusz Dziedzic #define ATH10K_DFS_POOL_STAT(s, p) (\
17949702c686SJanusz Dziedzic 	len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \
17959702c686SJanusz Dziedzic 			 ar->debug.dfs_pool_stats.p))
17969702c686SJanusz Dziedzic 
ath10k_read_dfs_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)17979702c686SJanusz Dziedzic static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,
17989702c686SJanusz Dziedzic 				     size_t count, loff_t *ppos)
17999702c686SJanusz Dziedzic {
18009702c686SJanusz Dziedzic 	int retval = 0, len = 0;
18019702c686SJanusz Dziedzic 	const int size = 8000;
18029702c686SJanusz Dziedzic 	struct ath10k *ar = file->private_data;
18039702c686SJanusz Dziedzic 	char *buf;
18049702c686SJanusz Dziedzic 
18059702c686SJanusz Dziedzic 	buf = kzalloc(size, GFP_KERNEL);
18069702c686SJanusz Dziedzic 	if (buf == NULL)
18079702c686SJanusz Dziedzic 		return -ENOMEM;
18089702c686SJanusz Dziedzic 
18099702c686SJanusz Dziedzic 	if (!ar->dfs_detector) {
18109702c686SJanusz Dziedzic 		len += scnprintf(buf + len, size - len, "DFS not enabled\n");
18119702c686SJanusz Dziedzic 		goto exit;
18129702c686SJanusz Dziedzic 	}
18139702c686SJanusz Dziedzic 
18149702c686SJanusz Dziedzic 	ar->debug.dfs_pool_stats =
18159702c686SJanusz Dziedzic 			ar->dfs_detector->get_stats(ar->dfs_detector);
18169702c686SJanusz Dziedzic 
18179702c686SJanusz Dziedzic 	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
18189702c686SJanusz Dziedzic 
18199702c686SJanusz Dziedzic 	ATH10K_DFS_STAT("reported phy errors", phy_errors);
18209702c686SJanusz Dziedzic 	ATH10K_DFS_STAT("pulse events reported", pulses_total);
18219702c686SJanusz Dziedzic 	ATH10K_DFS_STAT("DFS pulses detected", pulses_detected);
18229702c686SJanusz Dziedzic 	ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded);
18239702c686SJanusz Dziedzic 	ATH10K_DFS_STAT("Radars detected", radar_detected);
18249702c686SJanusz Dziedzic 
18259702c686SJanusz Dziedzic 	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
18269702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Pool references", pool_reference);
18279702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated);
18289702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error);
18299702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used);
18309702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated);
18319702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);
18329702c686SJanusz Dziedzic 	ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);
18339702c686SJanusz Dziedzic 
18349702c686SJanusz Dziedzic exit:
18359702c686SJanusz Dziedzic 	if (len > size)
18369702c686SJanusz Dziedzic 		len = size;
18379702c686SJanusz Dziedzic 
18389702c686SJanusz Dziedzic 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
18399702c686SJanusz Dziedzic 	kfree(buf);
18409702c686SJanusz Dziedzic 
18419702c686SJanusz Dziedzic 	return retval;
18429702c686SJanusz Dziedzic }
18439702c686SJanusz Dziedzic 
18449702c686SJanusz Dziedzic static const struct file_operations fops_dfs_stats = {
18459702c686SJanusz Dziedzic 	.read = ath10k_read_dfs_stats,
18469702c686SJanusz Dziedzic 	.open = simple_open,
18479702c686SJanusz Dziedzic 	.owner = THIS_MODULE,
18489702c686SJanusz Dziedzic 	.llseek = default_llseek,
18499702c686SJanusz Dziedzic };
18509702c686SJanusz Dziedzic 
ath10k_write_pktlog_filter(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)185190174455SRajkumar Manoharan static ssize_t ath10k_write_pktlog_filter(struct file *file,
185290174455SRajkumar Manoharan 					  const char __user *ubuf,
185390174455SRajkumar Manoharan 					  size_t count, loff_t *ppos)
185490174455SRajkumar Manoharan {
185590174455SRajkumar Manoharan 	struct ath10k *ar = file->private_data;
185690174455SRajkumar Manoharan 	u32 filter;
185790174455SRajkumar Manoharan 	int ret;
185890174455SRajkumar Manoharan 
185990174455SRajkumar Manoharan 	if (kstrtouint_from_user(ubuf, count, 0, &filter))
186090174455SRajkumar Manoharan 		return -EINVAL;
186190174455SRajkumar Manoharan 
186290174455SRajkumar Manoharan 	mutex_lock(&ar->conf_mutex);
186390174455SRajkumar Manoharan 
186490174455SRajkumar Manoharan 	if (ar->state != ATH10K_STATE_ON) {
18657f9befbbSAnilkumar Kolli 		ar->pktlog_filter = filter;
186690174455SRajkumar Manoharan 		ret = count;
186790174455SRajkumar Manoharan 		goto out;
186890174455SRajkumar Manoharan 	}
186990174455SRajkumar Manoharan 
18707f9befbbSAnilkumar Kolli 	if (filter == ar->pktlog_filter) {
18719ddc486aSAnilkumar Kolli 		ret = count;
18729ddc486aSAnilkumar Kolli 		goto out;
18739ddc486aSAnilkumar Kolli 	}
18749ddc486aSAnilkumar Kolli 
18759ddc486aSAnilkumar Kolli 	if (filter) {
187690174455SRajkumar Manoharan 		ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
187790174455SRajkumar Manoharan 		if (ret) {
187890174455SRajkumar Manoharan 			ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
18797f9befbbSAnilkumar Kolli 				    ar->pktlog_filter, ret);
188090174455SRajkumar Manoharan 			goto out;
188190174455SRajkumar Manoharan 		}
188290174455SRajkumar Manoharan 	} else {
188390174455SRajkumar Manoharan 		ret = ath10k_wmi_pdev_pktlog_disable(ar);
188490174455SRajkumar Manoharan 		if (ret) {
188590174455SRajkumar Manoharan 			ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
188690174455SRajkumar Manoharan 			goto out;
188790174455SRajkumar Manoharan 		}
188890174455SRajkumar Manoharan 	}
188990174455SRajkumar Manoharan 
18907f9befbbSAnilkumar Kolli 	ar->pktlog_filter = filter;
189190174455SRajkumar Manoharan 	ret = count;
189290174455SRajkumar Manoharan 
189390174455SRajkumar Manoharan out:
189490174455SRajkumar Manoharan 	mutex_unlock(&ar->conf_mutex);
189590174455SRajkumar Manoharan 	return ret;
189690174455SRajkumar Manoharan }
189790174455SRajkumar Manoharan 
ath10k_read_pktlog_filter(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)189890174455SRajkumar Manoharan static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
189990174455SRajkumar Manoharan 					 size_t count, loff_t *ppos)
190090174455SRajkumar Manoharan {
190190174455SRajkumar Manoharan 	char buf[32];
190290174455SRajkumar Manoharan 	struct ath10k *ar = file->private_data;
190390174455SRajkumar Manoharan 	int len = 0;
190490174455SRajkumar Manoharan 
190590174455SRajkumar Manoharan 	mutex_lock(&ar->conf_mutex);
190690174455SRajkumar Manoharan 	len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
19077f9befbbSAnilkumar Kolli 			ar->pktlog_filter);
190890174455SRajkumar Manoharan 	mutex_unlock(&ar->conf_mutex);
190990174455SRajkumar Manoharan 
191090174455SRajkumar Manoharan 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
191190174455SRajkumar Manoharan }
191290174455SRajkumar Manoharan 
191390174455SRajkumar Manoharan static const struct file_operations fops_pktlog_filter = {
191490174455SRajkumar Manoharan 	.read = ath10k_read_pktlog_filter,
191590174455SRajkumar Manoharan 	.write = ath10k_write_pktlog_filter,
191690174455SRajkumar Manoharan 	.open = simple_open
191790174455SRajkumar Manoharan };
191890174455SRajkumar Manoharan 
ath10k_write_quiet_period(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)191963fb32dfSRajkumar Manoharan static ssize_t ath10k_write_quiet_period(struct file *file,
192063fb32dfSRajkumar Manoharan 					 const char __user *ubuf,
192163fb32dfSRajkumar Manoharan 					 size_t count, loff_t *ppos)
192263fb32dfSRajkumar Manoharan {
192363fb32dfSRajkumar Manoharan 	struct ath10k *ar = file->private_data;
192463fb32dfSRajkumar Manoharan 	u32 period;
192563fb32dfSRajkumar Manoharan 
192663fb32dfSRajkumar Manoharan 	if (kstrtouint_from_user(ubuf, count, 0, &period))
192763fb32dfSRajkumar Manoharan 		return -EINVAL;
192863fb32dfSRajkumar Manoharan 
192963fb32dfSRajkumar Manoharan 	if (period < ATH10K_QUIET_PERIOD_MIN) {
193063fb32dfSRajkumar Manoharan 		ath10k_warn(ar, "Quiet period %u can not be lesser than 25ms\n",
193163fb32dfSRajkumar Manoharan 			    period);
193263fb32dfSRajkumar Manoharan 		return -EINVAL;
193363fb32dfSRajkumar Manoharan 	}
193463fb32dfSRajkumar Manoharan 	mutex_lock(&ar->conf_mutex);
193563fb32dfSRajkumar Manoharan 	ar->thermal.quiet_period = period;
19368515b5c7SRajkumar Manoharan 	ath10k_thermal_set_throttling(ar);
193763fb32dfSRajkumar Manoharan 	mutex_unlock(&ar->conf_mutex);
193863fb32dfSRajkumar Manoharan 
193963fb32dfSRajkumar Manoharan 	return count;
194063fb32dfSRajkumar Manoharan }
194163fb32dfSRajkumar Manoharan 
ath10k_read_quiet_period(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)194263fb32dfSRajkumar Manoharan static ssize_t ath10k_read_quiet_period(struct file *file, char __user *ubuf,
194363fb32dfSRajkumar Manoharan 					size_t count, loff_t *ppos)
194463fb32dfSRajkumar Manoharan {
194563fb32dfSRajkumar Manoharan 	char buf[32];
194663fb32dfSRajkumar Manoharan 	struct ath10k *ar = file->private_data;
194763fb32dfSRajkumar Manoharan 	int len = 0;
194863fb32dfSRajkumar Manoharan 
194963fb32dfSRajkumar Manoharan 	mutex_lock(&ar->conf_mutex);
195063fb32dfSRajkumar Manoharan 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
195163fb32dfSRajkumar Manoharan 			ar->thermal.quiet_period);
195263fb32dfSRajkumar Manoharan 	mutex_unlock(&ar->conf_mutex);
195363fb32dfSRajkumar Manoharan 
195463fb32dfSRajkumar Manoharan 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
195563fb32dfSRajkumar Manoharan }
195663fb32dfSRajkumar Manoharan 
195763fb32dfSRajkumar Manoharan static const struct file_operations fops_quiet_period = {
195863fb32dfSRajkumar Manoharan 	.read = ath10k_read_quiet_period,
195963fb32dfSRajkumar Manoharan 	.write = ath10k_write_quiet_period,
196063fb32dfSRajkumar Manoharan 	.open = simple_open
196163fb32dfSRajkumar Manoharan };
196263fb32dfSRajkumar Manoharan 
ath10k_write_btcoex(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1963844fa572SYanbo Li static ssize_t ath10k_write_btcoex(struct file *file,
1964844fa572SYanbo Li 				   const char __user *ubuf,
1965844fa572SYanbo Li 				   size_t count, loff_t *ppos)
1966844fa572SYanbo Li {
1967844fa572SYanbo Li 	struct ath10k *ar = file->private_data;
19683fcb8142SDmitry Antipov 	ssize_t ret;
1969844fa572SYanbo Li 	bool val;
197039136248SRajkumar Manoharan 	u32 pdev_param;
1971844fa572SYanbo Li 
19723fcb8142SDmitry Antipov 	ret = kstrtobool_from_user(ubuf, count, &val);
19733fcb8142SDmitry Antipov 	if (ret)
19743fcb8142SDmitry Antipov 		return ret;
1975844fa572SYanbo Li 
19769f83993eSTamizh Chelvam 	if (!ar->coex_support)
19779f83993eSTamizh Chelvam 		return -EOPNOTSUPP;
19789f83993eSTamizh Chelvam 
1979844fa572SYanbo Li 	mutex_lock(&ar->conf_mutex);
1980844fa572SYanbo Li 
1981c28e6f06SMohammed Shafi Shajakhan 	if (ar->state != ATH10K_STATE_ON &&
1982c28e6f06SMohammed Shafi Shajakhan 	    ar->state != ATH10K_STATE_RESTARTED) {
1983c28e6f06SMohammed Shafi Shajakhan 		ret = -ENETDOWN;
1984c28e6f06SMohammed Shafi Shajakhan 		goto exit;
1985c28e6f06SMohammed Shafi Shajakhan 	}
1986c28e6f06SMohammed Shafi Shajakhan 
198787be054aSMohammed Shafi Shajakhan 	if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) {
198887be054aSMohammed Shafi Shajakhan 		ret = count;
1989844fa572SYanbo Li 		goto exit;
199087be054aSMohammed Shafi Shajakhan 	}
1991844fa572SYanbo Li 
199239136248SRajkumar Manoharan 	pdev_param = ar->wmi.pdev_param->enable_btcoex;
199339136248SRajkumar Manoharan 	if (test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,
199439136248SRajkumar Manoharan 		     ar->running_fw->fw_file.fw_features)) {
199539136248SRajkumar Manoharan 		ret = ath10k_wmi_pdev_set_param(ar, pdev_param, val);
199639136248SRajkumar Manoharan 		if (ret) {
19973fcb8142SDmitry Antipov 			ath10k_warn(ar, "failed to enable btcoex: %zd\n", ret);
199839136248SRajkumar Manoharan 			ret = count;
199939136248SRajkumar Manoharan 			goto exit;
200039136248SRajkumar Manoharan 		}
200139136248SRajkumar Manoharan 	} else {
200239136248SRajkumar Manoharan 		ath10k_info(ar, "restarting firmware due to btcoex change");
20035dadbe4eSWen Gong 		ath10k_core_start_recovery(ar);
200439136248SRajkumar Manoharan 	}
200539136248SRajkumar Manoharan 
2006844fa572SYanbo Li 	if (val)
2007844fa572SYanbo Li 		set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
2008844fa572SYanbo Li 	else
2009844fa572SYanbo Li 		clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
2010844fa572SYanbo Li 
2011c28e6f06SMohammed Shafi Shajakhan 	ret = count;
2012844fa572SYanbo Li 
2013844fa572SYanbo Li exit:
2014844fa572SYanbo Li 	mutex_unlock(&ar->conf_mutex);
2015844fa572SYanbo Li 
2016c28e6f06SMohammed Shafi Shajakhan 	return ret;
2017844fa572SYanbo Li }
2018844fa572SYanbo Li 
ath10k_read_btcoex(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)2019844fa572SYanbo Li static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,
2020844fa572SYanbo Li 				  size_t count, loff_t *ppos)
2021844fa572SYanbo Li {
2022844fa572SYanbo Li 	char buf[32];
2023844fa572SYanbo Li 	struct ath10k *ar = file->private_data;
2024844fa572SYanbo Li 	int len = 0;
2025844fa572SYanbo Li 
2026844fa572SYanbo Li 	mutex_lock(&ar->conf_mutex);
2027844fa572SYanbo Li 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
2028844fa572SYanbo Li 			test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags));
2029844fa572SYanbo Li 	mutex_unlock(&ar->conf_mutex);
2030844fa572SYanbo Li 
2031844fa572SYanbo Li 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
2032844fa572SYanbo Li }
2033844fa572SYanbo Li 
2034844fa572SYanbo Li static const struct file_operations fops_btcoex = {
2035844fa572SYanbo Li 	.read = ath10k_read_btcoex,
2036844fa572SYanbo Li 	.write = ath10k_write_btcoex,
2037844fa572SYanbo Li 	.open = simple_open
2038844fa572SYanbo Li };
2039844fa572SYanbo Li 
ath10k_write_enable_extd_tx_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)2040348cd95cSAnilkumar Kolli static ssize_t ath10k_write_enable_extd_tx_stats(struct file *file,
2041348cd95cSAnilkumar Kolli 						 const char __user *ubuf,
2042348cd95cSAnilkumar Kolli 						 size_t count, loff_t *ppos)
2043348cd95cSAnilkumar Kolli {
2044348cd95cSAnilkumar Kolli 	struct ath10k *ar = file->private_data;
2045348cd95cSAnilkumar Kolli 	u32 filter;
2046348cd95cSAnilkumar Kolli 	int ret;
2047348cd95cSAnilkumar Kolli 
2048348cd95cSAnilkumar Kolli 	if (kstrtouint_from_user(ubuf, count, 0, &filter))
2049348cd95cSAnilkumar Kolli 		return -EINVAL;
2050348cd95cSAnilkumar Kolli 
2051348cd95cSAnilkumar Kolli 	mutex_lock(&ar->conf_mutex);
2052348cd95cSAnilkumar Kolli 
2053348cd95cSAnilkumar Kolli 	if (ar->state != ATH10K_STATE_ON) {
2054348cd95cSAnilkumar Kolli 		ar->debug.enable_extd_tx_stats = filter;
2055348cd95cSAnilkumar Kolli 		ret = count;
2056348cd95cSAnilkumar Kolli 		goto out;
2057348cd95cSAnilkumar Kolli 	}
2058348cd95cSAnilkumar Kolli 
2059348cd95cSAnilkumar Kolli 	if (filter == ar->debug.enable_extd_tx_stats) {
2060348cd95cSAnilkumar Kolli 		ret = count;
2061348cd95cSAnilkumar Kolli 		goto out;
2062348cd95cSAnilkumar Kolli 	}
2063348cd95cSAnilkumar Kolli 
2064348cd95cSAnilkumar Kolli 	ar->debug.enable_extd_tx_stats = filter;
2065348cd95cSAnilkumar Kolli 	ret = count;
2066348cd95cSAnilkumar Kolli 
2067348cd95cSAnilkumar Kolli out:
2068348cd95cSAnilkumar Kolli 	mutex_unlock(&ar->conf_mutex);
2069348cd95cSAnilkumar Kolli 	return ret;
2070348cd95cSAnilkumar Kolli }
2071348cd95cSAnilkumar Kolli 
ath10k_read_enable_extd_tx_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)2072348cd95cSAnilkumar Kolli static ssize_t ath10k_read_enable_extd_tx_stats(struct file *file,
2073348cd95cSAnilkumar Kolli 						char __user *ubuf,
2074348cd95cSAnilkumar Kolli 						size_t count, loff_t *ppos)
2075348cd95cSAnilkumar Kolli 
2076348cd95cSAnilkumar Kolli {
2077348cd95cSAnilkumar Kolli 	char buf[32];
2078348cd95cSAnilkumar Kolli 	struct ath10k *ar = file->private_data;
2079348cd95cSAnilkumar Kolli 	int len = 0;
2080348cd95cSAnilkumar Kolli 
2081348cd95cSAnilkumar Kolli 	mutex_lock(&ar->conf_mutex);
2082348cd95cSAnilkumar Kolli 	len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
2083348cd95cSAnilkumar Kolli 			ar->debug.enable_extd_tx_stats);
2084348cd95cSAnilkumar Kolli 	mutex_unlock(&ar->conf_mutex);
2085348cd95cSAnilkumar Kolli 
2086348cd95cSAnilkumar Kolli 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
2087348cd95cSAnilkumar Kolli }
2088348cd95cSAnilkumar Kolli 
2089348cd95cSAnilkumar Kolli static const struct file_operations fops_enable_extd_tx_stats = {
2090348cd95cSAnilkumar Kolli 	.read = ath10k_read_enable_extd_tx_stats,
2091348cd95cSAnilkumar Kolli 	.write = ath10k_write_enable_extd_tx_stats,
2092348cd95cSAnilkumar Kolli 	.open = simple_open
2093348cd95cSAnilkumar Kolli };
2094348cd95cSAnilkumar Kolli 
ath10k_write_peer_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)2095cc61a1bbSMohammed Shafi Shajakhan static ssize_t ath10k_write_peer_stats(struct file *file,
2096cc61a1bbSMohammed Shafi Shajakhan 				       const char __user *ubuf,
2097cc61a1bbSMohammed Shafi Shajakhan 				       size_t count, loff_t *ppos)
2098cc61a1bbSMohammed Shafi Shajakhan {
2099cc61a1bbSMohammed Shafi Shajakhan 	struct ath10k *ar = file->private_data;
21003fcb8142SDmitry Antipov 	ssize_t ret;
2101cc61a1bbSMohammed Shafi Shajakhan 	bool val;
2102cc61a1bbSMohammed Shafi Shajakhan 
21033fcb8142SDmitry Antipov 	ret = kstrtobool_from_user(ubuf, count, &val);
21043fcb8142SDmitry Antipov 	if (ret)
21053fcb8142SDmitry Antipov 		return ret;
2106cc61a1bbSMohammed Shafi Shajakhan 
2107cc61a1bbSMohammed Shafi Shajakhan 	mutex_lock(&ar->conf_mutex);
2108cc61a1bbSMohammed Shafi Shajakhan 
2109cc61a1bbSMohammed Shafi Shajakhan 	if (ar->state != ATH10K_STATE_ON &&
2110cc61a1bbSMohammed Shafi Shajakhan 	    ar->state != ATH10K_STATE_RESTARTED) {
2111cc61a1bbSMohammed Shafi Shajakhan 		ret = -ENETDOWN;
2112cc61a1bbSMohammed Shafi Shajakhan 		goto exit;
2113cc61a1bbSMohammed Shafi Shajakhan 	}
2114cc61a1bbSMohammed Shafi Shajakhan 
211587be054aSMohammed Shafi Shajakhan 	if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) {
211687be054aSMohammed Shafi Shajakhan 		ret = count;
2117cc61a1bbSMohammed Shafi Shajakhan 		goto exit;
211887be054aSMohammed Shafi Shajakhan 	}
2119cc61a1bbSMohammed Shafi Shajakhan 
2120cc61a1bbSMohammed Shafi Shajakhan 	if (val)
2121cc61a1bbSMohammed Shafi Shajakhan 		set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
2122cc61a1bbSMohammed Shafi Shajakhan 	else
2123cc61a1bbSMohammed Shafi Shajakhan 		clear_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
2124cc61a1bbSMohammed Shafi Shajakhan 
2125cc61a1bbSMohammed Shafi Shajakhan 	ath10k_info(ar, "restarting firmware due to Peer stats change");
2126cc61a1bbSMohammed Shafi Shajakhan 
21275dadbe4eSWen Gong 	ath10k_core_start_recovery(ar);
2128cc61a1bbSMohammed Shafi Shajakhan 	ret = count;
2129cc61a1bbSMohammed Shafi Shajakhan 
2130cc61a1bbSMohammed Shafi Shajakhan exit:
2131cc61a1bbSMohammed Shafi Shajakhan 	mutex_unlock(&ar->conf_mutex);
2132cc61a1bbSMohammed Shafi Shajakhan 	return ret;
2133cc61a1bbSMohammed Shafi Shajakhan }
2134cc61a1bbSMohammed Shafi Shajakhan 
ath10k_read_peer_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)2135cc61a1bbSMohammed Shafi Shajakhan static ssize_t ath10k_read_peer_stats(struct file *file, char __user *ubuf,
2136cc61a1bbSMohammed Shafi Shajakhan 				      size_t count, loff_t *ppos)
2137cc61a1bbSMohammed Shafi Shajakhan 
2138cc61a1bbSMohammed Shafi Shajakhan {
2139cc61a1bbSMohammed Shafi Shajakhan 	char buf[32];
2140cc61a1bbSMohammed Shafi Shajakhan 	struct ath10k *ar = file->private_data;
2141cc61a1bbSMohammed Shafi Shajakhan 	int len = 0;
2142cc61a1bbSMohammed Shafi Shajakhan 
2143cc61a1bbSMohammed Shafi Shajakhan 	mutex_lock(&ar->conf_mutex);
2144cc61a1bbSMohammed Shafi Shajakhan 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
2145cc61a1bbSMohammed Shafi Shajakhan 			test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags));
2146cc61a1bbSMohammed Shafi Shajakhan 	mutex_unlock(&ar->conf_mutex);
2147cc61a1bbSMohammed Shafi Shajakhan 
2148cc61a1bbSMohammed Shafi Shajakhan 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
2149cc61a1bbSMohammed Shafi Shajakhan }
2150cc61a1bbSMohammed Shafi Shajakhan 
2151cc61a1bbSMohammed Shafi Shajakhan static const struct file_operations fops_peer_stats = {
2152cc61a1bbSMohammed Shafi Shajakhan 	.read = ath10k_read_peer_stats,
2153cc61a1bbSMohammed Shafi Shajakhan 	.write = ath10k_write_peer_stats,
2154cc61a1bbSMohammed Shafi Shajakhan 	.open = simple_open
2155cc61a1bbSMohammed Shafi Shajakhan };
2156cc61a1bbSMohammed Shafi Shajakhan 
ath10k_debug_fw_checksums_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)21579e100c4dSKalle Valo static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
21589e100c4dSKalle Valo 					      char __user *user_buf,
21599e100c4dSKalle Valo 					      size_t count, loff_t *ppos)
21609e100c4dSKalle Valo {
21619e100c4dSKalle Valo 	struct ath10k *ar = file->private_data;
2162182f1e5aSAmadeusz Sławiński 	size_t len = 0, buf_len = 4096;
21639e100c4dSKalle Valo 	ssize_t ret_cnt;
21649e100c4dSKalle Valo 	char *buf;
21659e100c4dSKalle Valo 
21669e100c4dSKalle Valo 	buf = kzalloc(buf_len, GFP_KERNEL);
21679e100c4dSKalle Valo 	if (!buf)
21689e100c4dSKalle Valo 		return -ENOMEM;
21699e100c4dSKalle Valo 
21709e100c4dSKalle Valo 	mutex_lock(&ar->conf_mutex);
21719e100c4dSKalle Valo 
21729e100c4dSKalle Valo 	len += scnprintf(buf + len, buf_len - len,
21739e100c4dSKalle Valo 			 "firmware-N.bin\t\t%08x\n",
21747ebf721dSKalle Valo 			 crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data,
21757ebf721dSKalle Valo 				  ar->normal_mode_fw.fw_file.firmware->size));
21769e100c4dSKalle Valo 	len += scnprintf(buf + len, buf_len - len,
21779e100c4dSKalle Valo 			 "athwlan\t\t\t%08x\n",
21787ebf721dSKalle Valo 			 crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data,
21797ebf721dSKalle Valo 				  ar->normal_mode_fw.fw_file.firmware_len));
21809e100c4dSKalle Valo 	len += scnprintf(buf + len, buf_len - len,
21819e100c4dSKalle Valo 			 "otp\t\t\t%08x\n",
21827ebf721dSKalle Valo 			 crc32_le(0, ar->normal_mode_fw.fw_file.otp_data,
21837ebf721dSKalle Valo 				  ar->normal_mode_fw.fw_file.otp_len));
21849e100c4dSKalle Valo 	len += scnprintf(buf + len, buf_len - len,
21859e100c4dSKalle Valo 			 "codeswap\t\t%08x\n",
21867ebf721dSKalle Valo 			 crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data,
21877ebf721dSKalle Valo 				  ar->normal_mode_fw.fw_file.codeswap_len));
21889e100c4dSKalle Valo 	len += scnprintf(buf + len, buf_len - len,
21899e100c4dSKalle Valo 			 "board-N.bin\t\t%08x\n",
21907ebf721dSKalle Valo 			 crc32_le(0, ar->normal_mode_fw.board->data,
21917ebf721dSKalle Valo 				  ar->normal_mode_fw.board->size));
21929e100c4dSKalle Valo 	len += scnprintf(buf + len, buf_len - len,
21939e100c4dSKalle Valo 			 "board\t\t\t%08x\n",
21947ebf721dSKalle Valo 			 crc32_le(0, ar->normal_mode_fw.board_data,
21957ebf721dSKalle Valo 				  ar->normal_mode_fw.board_len));
21969e100c4dSKalle Valo 
21979e100c4dSKalle Valo 	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
21989e100c4dSKalle Valo 
21999e100c4dSKalle Valo 	mutex_unlock(&ar->conf_mutex);
22009e100c4dSKalle Valo 
22019e100c4dSKalle Valo 	kfree(buf);
22029e100c4dSKalle Valo 	return ret_cnt;
22039e100c4dSKalle Valo }
22049e100c4dSKalle Valo 
22059e100c4dSKalle Valo static const struct file_operations fops_fw_checksums = {
22069e100c4dSKalle Valo 	.read = ath10k_debug_fw_checksums_read,
22079e100c4dSKalle Valo 	.open = simple_open,
22089e100c4dSKalle Valo 	.owner = THIS_MODULE,
22099e100c4dSKalle Valo 	.llseek = default_llseek,
22109e100c4dSKalle Valo };
22119e100c4dSKalle Valo 
ath10k_sta_tid_stats_mask_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2212caee728aSVasanthakumar Thiagarajan static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file,
2213caee728aSVasanthakumar Thiagarajan 					      char __user *user_buf,
2214caee728aSVasanthakumar Thiagarajan 					      size_t count, loff_t *ppos)
2215caee728aSVasanthakumar Thiagarajan {
2216caee728aSVasanthakumar Thiagarajan 	struct ath10k *ar = file->private_data;
2217caee728aSVasanthakumar Thiagarajan 	char buf[32];
2218caee728aSVasanthakumar Thiagarajan 	size_t len;
2219caee728aSVasanthakumar Thiagarajan 
2220caee728aSVasanthakumar Thiagarajan 	len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask);
2221caee728aSVasanthakumar Thiagarajan 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2222caee728aSVasanthakumar Thiagarajan }
2223caee728aSVasanthakumar Thiagarajan 
ath10k_sta_tid_stats_mask_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)2224caee728aSVasanthakumar Thiagarajan static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file,
2225caee728aSVasanthakumar Thiagarajan 					       const char __user *user_buf,
2226caee728aSVasanthakumar Thiagarajan 					       size_t count, loff_t *ppos)
2227caee728aSVasanthakumar Thiagarajan {
2228caee728aSVasanthakumar Thiagarajan 	struct ath10k *ar = file->private_data;
22293fcb8142SDmitry Antipov 	ssize_t ret;
2230caee728aSVasanthakumar Thiagarajan 	u32 mask;
2231caee728aSVasanthakumar Thiagarajan 
22323fcb8142SDmitry Antipov 	ret = kstrtoint_from_user(user_buf, count, 0, &mask);
22333fcb8142SDmitry Antipov 	if (ret)
22343fcb8142SDmitry Antipov 		return ret;
2235caee728aSVasanthakumar Thiagarajan 
2236caee728aSVasanthakumar Thiagarajan 	ar->sta_tid_stats_mask = mask;
2237caee728aSVasanthakumar Thiagarajan 
22383fcb8142SDmitry Antipov 	return count;
2239caee728aSVasanthakumar Thiagarajan }
2240caee728aSVasanthakumar Thiagarajan 
2241caee728aSVasanthakumar Thiagarajan static const struct file_operations fops_sta_tid_stats_mask = {
2242caee728aSVasanthakumar Thiagarajan 	.read = ath10k_sta_tid_stats_mask_read,
2243caee728aSVasanthakumar Thiagarajan 	.write = ath10k_sta_tid_stats_mask_write,
2244caee728aSVasanthakumar Thiagarajan 	.open = simple_open,
2245caee728aSVasanthakumar Thiagarajan 	.owner = THIS_MODULE,
2246caee728aSVasanthakumar Thiagarajan 	.llseek = default_llseek,
2247caee728aSVasanthakumar Thiagarajan };
2248caee728aSVasanthakumar Thiagarajan 
ath10k_debug_tpc_stats_final_request(struct ath10k * ar)2249bc64d052SMaharaja Kennadyrajan static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)
2250bc64d052SMaharaja Kennadyrajan {
2251bc64d052SMaharaja Kennadyrajan 	int ret;
2252bc64d052SMaharaja Kennadyrajan 	unsigned long time_left;
2253bc64d052SMaharaja Kennadyrajan 
2254bc64d052SMaharaja Kennadyrajan 	lockdep_assert_held(&ar->conf_mutex);
2255bc64d052SMaharaja Kennadyrajan 
2256bc64d052SMaharaja Kennadyrajan 	reinit_completion(&ar->debug.tpc_complete);
2257bc64d052SMaharaja Kennadyrajan 
2258bc64d052SMaharaja Kennadyrajan 	ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);
2259bc64d052SMaharaja Kennadyrajan 	if (ret) {
2260bc64d052SMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);
2261bc64d052SMaharaja Kennadyrajan 		return ret;
2262bc64d052SMaharaja Kennadyrajan 	}
2263bc64d052SMaharaja Kennadyrajan 
2264bc64d052SMaharaja Kennadyrajan 	time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
2265bc64d052SMaharaja Kennadyrajan 						1 * HZ);
2266bc64d052SMaharaja Kennadyrajan 	if (time_left == 0)
2267bc64d052SMaharaja Kennadyrajan 		return -ETIMEDOUT;
2268bc64d052SMaharaja Kennadyrajan 
2269bc64d052SMaharaja Kennadyrajan 	return 0;
2270bc64d052SMaharaja Kennadyrajan }
2271bc64d052SMaharaja Kennadyrajan 
ath10k_tpc_stats_final_open(struct inode * inode,struct file * file)2272bc64d052SMaharaja Kennadyrajan static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)
2273bc64d052SMaharaja Kennadyrajan {
2274bc64d052SMaharaja Kennadyrajan 	struct ath10k *ar = inode->i_private;
2275bc64d052SMaharaja Kennadyrajan 	void *buf;
2276bc64d052SMaharaja Kennadyrajan 	int ret;
2277bc64d052SMaharaja Kennadyrajan 
2278bc64d052SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
2279bc64d052SMaharaja Kennadyrajan 
2280bc64d052SMaharaja Kennadyrajan 	if (ar->state != ATH10K_STATE_ON) {
2281bc64d052SMaharaja Kennadyrajan 		ret = -ENETDOWN;
2282bc64d052SMaharaja Kennadyrajan 		goto err_unlock;
2283bc64d052SMaharaja Kennadyrajan 	}
2284bc64d052SMaharaja Kennadyrajan 
2285bc64d052SMaharaja Kennadyrajan 	buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
2286bc64d052SMaharaja Kennadyrajan 	if (!buf) {
2287bc64d052SMaharaja Kennadyrajan 		ret = -ENOMEM;
2288bc64d052SMaharaja Kennadyrajan 		goto err_unlock;
2289bc64d052SMaharaja Kennadyrajan 	}
2290bc64d052SMaharaja Kennadyrajan 
2291bc64d052SMaharaja Kennadyrajan 	ret = ath10k_debug_tpc_stats_final_request(ar);
2292bc64d052SMaharaja Kennadyrajan 	if (ret) {
2293bc64d052SMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to request tpc stats final: %d\n",
2294bc64d052SMaharaja Kennadyrajan 			    ret);
2295bc64d052SMaharaja Kennadyrajan 		goto err_free;
2296bc64d052SMaharaja Kennadyrajan 	}
2297bc64d052SMaharaja Kennadyrajan 
2298bc64d052SMaharaja Kennadyrajan 	ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
2299bc64d052SMaharaja Kennadyrajan 	file->private_data = buf;
2300bc64d052SMaharaja Kennadyrajan 
2301bc64d052SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
2302bc64d052SMaharaja Kennadyrajan 	return 0;
2303bc64d052SMaharaja Kennadyrajan 
2304bc64d052SMaharaja Kennadyrajan err_free:
2305bc64d052SMaharaja Kennadyrajan 	vfree(buf);
2306bc64d052SMaharaja Kennadyrajan 
2307bc64d052SMaharaja Kennadyrajan err_unlock:
2308bc64d052SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
2309bc64d052SMaharaja Kennadyrajan 	return ret;
2310bc64d052SMaharaja Kennadyrajan }
2311bc64d052SMaharaja Kennadyrajan 
ath10k_tpc_stats_final_release(struct inode * inode,struct file * file)2312bc64d052SMaharaja Kennadyrajan static int ath10k_tpc_stats_final_release(struct inode *inode,
2313bc64d052SMaharaja Kennadyrajan 					  struct file *file)
2314bc64d052SMaharaja Kennadyrajan {
2315bc64d052SMaharaja Kennadyrajan 	vfree(file->private_data);
2316bc64d052SMaharaja Kennadyrajan 
2317bc64d052SMaharaja Kennadyrajan 	return 0;
2318bc64d052SMaharaja Kennadyrajan }
2319bc64d052SMaharaja Kennadyrajan 
ath10k_tpc_stats_final_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2320bc64d052SMaharaja Kennadyrajan static ssize_t ath10k_tpc_stats_final_read(struct file *file,
2321bc64d052SMaharaja Kennadyrajan 					   char __user *user_buf,
2322bc64d052SMaharaja Kennadyrajan 					   size_t count, loff_t *ppos)
2323bc64d052SMaharaja Kennadyrajan {
2324bc64d052SMaharaja Kennadyrajan 	const char *buf = file->private_data;
2325bc64d052SMaharaja Kennadyrajan 	unsigned int len = strlen(buf);
2326bc64d052SMaharaja Kennadyrajan 
2327bc64d052SMaharaja Kennadyrajan 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2328bc64d052SMaharaja Kennadyrajan }
2329bc64d052SMaharaja Kennadyrajan 
2330bc64d052SMaharaja Kennadyrajan static const struct file_operations fops_tpc_stats_final = {
2331bc64d052SMaharaja Kennadyrajan 	.open = ath10k_tpc_stats_final_open,
2332bc64d052SMaharaja Kennadyrajan 	.release = ath10k_tpc_stats_final_release,
2333bc64d052SMaharaja Kennadyrajan 	.read = ath10k_tpc_stats_final_read,
2334bc64d052SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
2335bc64d052SMaharaja Kennadyrajan 	.llseek = default_llseek,
2336bc64d052SMaharaja Kennadyrajan };
2337bc64d052SMaharaja Kennadyrajan 
ath10k_write_warm_hw_reset(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)2338db251d7dSMaharaja Kennadyrajan static ssize_t ath10k_write_warm_hw_reset(struct file *file,
2339db251d7dSMaharaja Kennadyrajan 					  const char __user *user_buf,
2340db251d7dSMaharaja Kennadyrajan 					  size_t count, loff_t *ppos)
2341db251d7dSMaharaja Kennadyrajan {
2342db251d7dSMaharaja Kennadyrajan 	struct ath10k *ar = file->private_data;
2343db251d7dSMaharaja Kennadyrajan 	int ret;
2344db251d7dSMaharaja Kennadyrajan 	bool val;
2345db251d7dSMaharaja Kennadyrajan 
2346db251d7dSMaharaja Kennadyrajan 	if (kstrtobool_from_user(user_buf, count, &val))
2347db251d7dSMaharaja Kennadyrajan 		return -EFAULT;
2348db251d7dSMaharaja Kennadyrajan 
2349db251d7dSMaharaja Kennadyrajan 	if (!val)
2350db251d7dSMaharaja Kennadyrajan 		return -EINVAL;
2351db251d7dSMaharaja Kennadyrajan 
2352db251d7dSMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
2353db251d7dSMaharaja Kennadyrajan 
2354db251d7dSMaharaja Kennadyrajan 	if (ar->state != ATH10K_STATE_ON) {
2355db251d7dSMaharaja Kennadyrajan 		ret = -ENETDOWN;
2356db251d7dSMaharaja Kennadyrajan 		goto exit;
2357db251d7dSMaharaja Kennadyrajan 	}
2358db251d7dSMaharaja Kennadyrajan 
2359db251d7dSMaharaja Kennadyrajan 	ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pdev_reset,
2360db251d7dSMaharaja Kennadyrajan 					WMI_RST_MODE_WARM_RESET);
2361db251d7dSMaharaja Kennadyrajan 
2362db251d7dSMaharaja Kennadyrajan 	if (ret) {
2363db251d7dSMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to enable warm hw reset: %d\n", ret);
2364db251d7dSMaharaja Kennadyrajan 		goto exit;
2365db251d7dSMaharaja Kennadyrajan 	}
2366db251d7dSMaharaja Kennadyrajan 
2367db251d7dSMaharaja Kennadyrajan 	ret = count;
2368db251d7dSMaharaja Kennadyrajan 
2369db251d7dSMaharaja Kennadyrajan exit:
2370db251d7dSMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
2371db251d7dSMaharaja Kennadyrajan 	return ret;
2372db251d7dSMaharaja Kennadyrajan }
2373db251d7dSMaharaja Kennadyrajan 
2374db251d7dSMaharaja Kennadyrajan static const struct file_operations fops_warm_hw_reset = {
2375db251d7dSMaharaja Kennadyrajan 	.write = ath10k_write_warm_hw_reset,
2376db251d7dSMaharaja Kennadyrajan 	.open = simple_open,
2377db251d7dSMaharaja Kennadyrajan 	.owner = THIS_MODULE,
2378db251d7dSMaharaja Kennadyrajan 	.llseek = default_llseek,
2379db251d7dSMaharaja Kennadyrajan };
2380db251d7dSMaharaja Kennadyrajan 
ath10k_peer_ps_state_disable(void * data,struct ieee80211_sta * sta)2381d70c0d46SMaharaja Kennadyrajan static void ath10k_peer_ps_state_disable(void *data,
2382d70c0d46SMaharaja Kennadyrajan 					 struct ieee80211_sta *sta)
2383d70c0d46SMaharaja Kennadyrajan {
2384d70c0d46SMaharaja Kennadyrajan 	struct ath10k *ar = data;
2385d70c0d46SMaharaja Kennadyrajan 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
2386d70c0d46SMaharaja Kennadyrajan 
2387d70c0d46SMaharaja Kennadyrajan 	spin_lock_bh(&ar->data_lock);
2388d70c0d46SMaharaja Kennadyrajan 	arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
2389d70c0d46SMaharaja Kennadyrajan 	spin_unlock_bh(&ar->data_lock);
2390d70c0d46SMaharaja Kennadyrajan }
2391d70c0d46SMaharaja Kennadyrajan 
ath10k_write_ps_state_enable(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)2392d70c0d46SMaharaja Kennadyrajan static ssize_t ath10k_write_ps_state_enable(struct file *file,
2393d70c0d46SMaharaja Kennadyrajan 					    const char __user *user_buf,
2394d70c0d46SMaharaja Kennadyrajan 					    size_t count, loff_t *ppos)
2395d70c0d46SMaharaja Kennadyrajan {
2396d70c0d46SMaharaja Kennadyrajan 	struct ath10k *ar = file->private_data;
2397d70c0d46SMaharaja Kennadyrajan 	int ret;
2398d70c0d46SMaharaja Kennadyrajan 	u32 param;
2399d70c0d46SMaharaja Kennadyrajan 	u8 ps_state_enable;
2400d70c0d46SMaharaja Kennadyrajan 
2401d70c0d46SMaharaja Kennadyrajan 	if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
2402d70c0d46SMaharaja Kennadyrajan 		return -EINVAL;
2403d70c0d46SMaharaja Kennadyrajan 
24047bfd82bfSGustavo A. R. Silva 	if (ps_state_enable > 1)
2405d70c0d46SMaharaja Kennadyrajan 		return -EINVAL;
2406d70c0d46SMaharaja Kennadyrajan 
2407d70c0d46SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
2408d70c0d46SMaharaja Kennadyrajan 
2409d70c0d46SMaharaja Kennadyrajan 	if (ar->ps_state_enable == ps_state_enable) {
2410d70c0d46SMaharaja Kennadyrajan 		ret = count;
2411d70c0d46SMaharaja Kennadyrajan 		goto exit;
2412d70c0d46SMaharaja Kennadyrajan 	}
2413d70c0d46SMaharaja Kennadyrajan 
2414d70c0d46SMaharaja Kennadyrajan 	param = ar->wmi.pdev_param->peer_sta_ps_statechg_enable;
2415d70c0d46SMaharaja Kennadyrajan 	ret = ath10k_wmi_pdev_set_param(ar, param, ps_state_enable);
2416d70c0d46SMaharaja Kennadyrajan 	if (ret) {
2417d70c0d46SMaharaja Kennadyrajan 		ath10k_warn(ar, "failed to enable ps_state_enable: %d\n",
2418d70c0d46SMaharaja Kennadyrajan 			    ret);
2419d70c0d46SMaharaja Kennadyrajan 		goto exit;
2420d70c0d46SMaharaja Kennadyrajan 	}
2421d70c0d46SMaharaja Kennadyrajan 	ar->ps_state_enable = ps_state_enable;
2422d70c0d46SMaharaja Kennadyrajan 
2423d70c0d46SMaharaja Kennadyrajan 	if (!ar->ps_state_enable)
2424d70c0d46SMaharaja Kennadyrajan 		ieee80211_iterate_stations_atomic(ar->hw,
2425d70c0d46SMaharaja Kennadyrajan 						  ath10k_peer_ps_state_disable,
2426d70c0d46SMaharaja Kennadyrajan 						  ar);
2427d70c0d46SMaharaja Kennadyrajan 
2428d70c0d46SMaharaja Kennadyrajan 	ret = count;
2429d70c0d46SMaharaja Kennadyrajan 
2430d70c0d46SMaharaja Kennadyrajan exit:
2431d70c0d46SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
2432d70c0d46SMaharaja Kennadyrajan 
2433d70c0d46SMaharaja Kennadyrajan 	return ret;
2434d70c0d46SMaharaja Kennadyrajan }
2435d70c0d46SMaharaja Kennadyrajan 
ath10k_read_ps_state_enable(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2436d70c0d46SMaharaja Kennadyrajan static ssize_t ath10k_read_ps_state_enable(struct file *file,
2437d70c0d46SMaharaja Kennadyrajan 					   char __user *user_buf,
2438d70c0d46SMaharaja Kennadyrajan 					   size_t count, loff_t *ppos)
2439d70c0d46SMaharaja Kennadyrajan {
2440d70c0d46SMaharaja Kennadyrajan 	struct ath10k *ar = file->private_data;
2441d70c0d46SMaharaja Kennadyrajan 	int len = 0;
2442d70c0d46SMaharaja Kennadyrajan 	char buf[32];
2443d70c0d46SMaharaja Kennadyrajan 
2444d70c0d46SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
2445d70c0d46SMaharaja Kennadyrajan 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
2446d70c0d46SMaharaja Kennadyrajan 			ar->ps_state_enable);
2447d70c0d46SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
2448d70c0d46SMaharaja Kennadyrajan 
2449d70c0d46SMaharaja Kennadyrajan 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
2450d70c0d46SMaharaja Kennadyrajan }
2451d70c0d46SMaharaja Kennadyrajan 
2452d70c0d46SMaharaja Kennadyrajan static const struct file_operations fops_ps_state_enable = {
2453d70c0d46SMaharaja Kennadyrajan 	.read = ath10k_read_ps_state_enable,
2454d70c0d46SMaharaja Kennadyrajan 	.write = ath10k_write_ps_state_enable,
2455d70c0d46SMaharaja Kennadyrajan 	.open = simple_open,
2456d70c0d46SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
2457d70c0d46SMaharaja Kennadyrajan 	.llseek = default_llseek,
2458d70c0d46SMaharaja Kennadyrajan };
2459d70c0d46SMaharaja Kennadyrajan 
ath10k_write_reset_htt_stats(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)2460473a4084SMaharaja Kennadyrajan static ssize_t ath10k_write_reset_htt_stats(struct file *file,
2461473a4084SMaharaja Kennadyrajan 					    const char __user *user_buf,
2462473a4084SMaharaja Kennadyrajan 					    size_t count, loff_t *ppos)
2463473a4084SMaharaja Kennadyrajan {
2464473a4084SMaharaja Kennadyrajan 	struct ath10k *ar = file->private_data;
2465473a4084SMaharaja Kennadyrajan 	unsigned long reset;
2466473a4084SMaharaja Kennadyrajan 	int ret;
2467473a4084SMaharaja Kennadyrajan 
2468473a4084SMaharaja Kennadyrajan 	ret = kstrtoul_from_user(user_buf, count, 0, &reset);
2469473a4084SMaharaja Kennadyrajan 	if (ret)
2470473a4084SMaharaja Kennadyrajan 		return ret;
2471473a4084SMaharaja Kennadyrajan 
2472473a4084SMaharaja Kennadyrajan 	if (reset == 0 || reset > 0x1ffff)
2473473a4084SMaharaja Kennadyrajan 		return -EINVAL;
2474473a4084SMaharaja Kennadyrajan 
2475473a4084SMaharaja Kennadyrajan 	mutex_lock(&ar->conf_mutex);
2476473a4084SMaharaja Kennadyrajan 
2477473a4084SMaharaja Kennadyrajan 	ar->debug.reset_htt_stats = reset;
2478473a4084SMaharaja Kennadyrajan 
2479473a4084SMaharaja Kennadyrajan 	ret = ath10k_debug_htt_stats_req(ar);
2480473a4084SMaharaja Kennadyrajan 	if (ret)
2481473a4084SMaharaja Kennadyrajan 		goto out;
2482473a4084SMaharaja Kennadyrajan 
2483473a4084SMaharaja Kennadyrajan 	ar->debug.reset_htt_stats = 0;
2484473a4084SMaharaja Kennadyrajan 	ret = count;
2485473a4084SMaharaja Kennadyrajan 
2486473a4084SMaharaja Kennadyrajan out:
2487473a4084SMaharaja Kennadyrajan 	mutex_unlock(&ar->conf_mutex);
2488473a4084SMaharaja Kennadyrajan 	return ret;
2489473a4084SMaharaja Kennadyrajan }
2490473a4084SMaharaja Kennadyrajan 
2491473a4084SMaharaja Kennadyrajan static const struct file_operations fops_reset_htt_stats = {
2492473a4084SMaharaja Kennadyrajan 	.write = ath10k_write_reset_htt_stats,
2493473a4084SMaharaja Kennadyrajan 	.owner = THIS_MODULE,
2494473a4084SMaharaja Kennadyrajan 	.open = simple_open,
2495473a4084SMaharaja Kennadyrajan 	.llseek = default_llseek,
2496473a4084SMaharaja Kennadyrajan };
2497473a4084SMaharaja Kennadyrajan 
ath10k_debug_create(struct ath10k * ar)24985e3dd157SKalle Valo int ath10k_debug_create(struct ath10k *ar)
24995e3dd157SKalle Valo {
2500f67b107dSMarty Faltesek 	ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
2501f67b107dSMarty Faltesek 	if (!ar->debug.cal_data)
2502f67b107dSMarty Faltesek 		return -ENOMEM;
2503f67b107dSMarty Faltesek 
25045326849aSMichal Kazior 	INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
25057b6b153aSMichal Kazior 	INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
25065326849aSMichal Kazior 	INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
25074a49ae94SMohammed Shafi Shajakhan 	INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
25085326849aSMichal Kazior 
2509e13cf7a3SMichal Kazior 	return 0;
2510384914b2SBen Greear }
2511384914b2SBen Greear 
ath10k_debug_destroy(struct ath10k * ar)2512e13cf7a3SMichal Kazior void ath10k_debug_destroy(struct ath10k *ar)
2513e13cf7a3SMichal Kazior {
2514f67b107dSMarty Faltesek 	vfree(ar->debug.cal_data);
2515f67b107dSMarty Faltesek 	ar->debug.cal_data = NULL;
2516f67b107dSMarty Faltesek 
25175326849aSMichal Kazior 	ath10k_debug_fw_stats_reset(ar);
251829542666SMaharaja Kennadyrajan 
251929542666SMaharaja Kennadyrajan 	kfree(ar->debug.tpc_stats);
2520486a8849SMiaoqing Pan 	kfree(ar->debug.tpc_stats_final);
2521e13cf7a3SMichal Kazior }
2522e13cf7a3SMichal Kazior 
ath10k_debug_register(struct ath10k * ar)2523e13cf7a3SMichal Kazior int ath10k_debug_register(struct ath10k *ar)
2524e13cf7a3SMichal Kazior {
25255e3dd157SKalle Valo 	ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
25265e3dd157SKalle Valo 						   ar->hw->wiphy->debugfsdir);
2527adb43b24SMichal Kazior 	if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) {
2528adb43b24SMichal Kazior 		if (IS_ERR(ar->debug.debugfs_phy))
2529adb43b24SMichal Kazior 			return PTR_ERR(ar->debug.debugfs_phy);
2530d8bb26b9SKalle Valo 
2531e13cf7a3SMichal Kazior 		return -ENOMEM;
2532adb43b24SMichal Kazior 	}
25335e3dd157SKalle Valo 
2534a3d135e5SKalle Valo 	INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
2535a3d135e5SKalle Valo 			  ath10k_debug_htt_stats_dwork);
2536a3d135e5SKalle Valo 
253729542666SMaharaja Kennadyrajan 	init_completion(&ar->debug.tpc_complete);
253860ef401aSMichal Kazior 	init_completion(&ar->debug.fw_stats_complete);
25395e3dd157SKalle Valo 
254053c8d48bSMarcin Rokicki 	debugfs_create_file("fw_stats", 0400, ar->debug.debugfs_phy, ar,
25415e3dd157SKalle Valo 			    &fops_fw_stats);
25425e3dd157SKalle Valo 
254353c8d48bSMarcin Rokicki 	debugfs_create_file("fw_reset_stats", 0400, ar->debug.debugfs_phy, ar,
254453c8d48bSMarcin Rokicki 			    &fops_fw_reset_stats);
2545f51dbe73SBen Greear 
254653c8d48bSMarcin Rokicki 	debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar,
25475e3dd157SKalle Valo 			    &fops_wmi_services);
25485e3dd157SKalle Valo 
254953c8d48bSMarcin Rokicki 	debugfs_create_file("simulate_fw_crash", 0600, ar->debug.debugfs_phy, ar,
255053c8d48bSMarcin Rokicki 			    &fops_simulate_fw_crash);
2551278c4a85SMichal Kazior 
255253c8d48bSMarcin Rokicki 	debugfs_create_file("reg_addr", 0600, ar->debug.debugfs_phy, ar,
255353c8d48bSMarcin Rokicki 			    &fops_reg_addr);
2554077a3804SYanbo Li 
255553c8d48bSMarcin Rokicki 	debugfs_create_file("reg_value", 0600, ar->debug.debugfs_phy, ar,
255653c8d48bSMarcin Rokicki 			    &fops_reg_value);
2557077a3804SYanbo Li 
255853c8d48bSMarcin Rokicki 	debugfs_create_file("mem_value", 0600, ar->debug.debugfs_phy, ar,
255953c8d48bSMarcin Rokicki 			    &fops_mem_value);
25609f65ad25SYanbo Li 
256153c8d48bSMarcin Rokicki 	debugfs_create_file("chip_id", 0400, ar->debug.debugfs_phy, ar,
256253c8d48bSMarcin Rokicki 			    &fops_chip_id);
2563763b8cd3SKalle Valo 
256453c8d48bSMarcin Rokicki 	debugfs_create_file("htt_stats_mask", 0600, ar->debug.debugfs_phy, ar,
256553c8d48bSMarcin Rokicki 			    &fops_htt_stats_mask);
2566a3d135e5SKalle Valo 
256753c8d48bSMarcin Rokicki 	debugfs_create_file("htt_max_amsdu_ampdu", 0600, ar->debug.debugfs_phy, ar,
2568d385623aSJanusz Dziedzic 			    &fops_htt_max_amsdu_ampdu);
2569d385623aSJanusz Dziedzic 
257053c8d48bSMarcin Rokicki 	debugfs_create_file("fw_dbglog", 0600, ar->debug.debugfs_phy, ar,
257153c8d48bSMarcin Rokicki 			    &fops_fw_dbglog);
2572f118a3e5SKalle Valo 
25735db98aeeSSurabhi Vishnoi 	if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,
25745db98aeeSSurabhi Vishnoi 		      ar->normal_mode_fw.fw_file.fw_features)) {
257553c8d48bSMarcin Rokicki 		debugfs_create_file("cal_data", 0400, ar->debug.debugfs_phy, ar,
257653c8d48bSMarcin Rokicki 				    &fops_cal_data);
25777869b4faSKalle Valo 
257853c8d48bSMarcin Rokicki 		debugfs_create_file("nf_cal_period", 0600, ar->debug.debugfs_phy, ar,
257953c8d48bSMarcin Rokicki 				    &fops_nf_cal_period);
25805db98aeeSSurabhi Vishnoi 	}
25815db98aeeSSurabhi Vishnoi 
25825db98aeeSSurabhi Vishnoi 	debugfs_create_file("ani_enable", 0600, ar->debug.debugfs_phy, ar,
25835db98aeeSSurabhi Vishnoi 			    &fops_ani_enable);
2584a7bd3e99SPeter Oh 
258597f2645fSMasahiro Yamada 	if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) {
258653c8d48bSMarcin Rokicki 		debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy,
258753c8d48bSMarcin Rokicki 				    ar, &fops_simulate_radar);
25889702c686SJanusz Dziedzic 
258953c8d48bSMarcin Rokicki 		debugfs_create_bool("dfs_block_radar_events", 0200,
25907d9b40b4SMarek Puzyniak 				    ar->debug.debugfs_phy,
25917d9b40b4SMarek Puzyniak 				    &ar->dfs_block_radar_events);
25927d9b40b4SMarek Puzyniak 
259353c8d48bSMarcin Rokicki 		debugfs_create_file("dfs_stats", 0400, ar->debug.debugfs_phy, ar,
25949702c686SJanusz Dziedzic 				    &fops_dfs_stats);
25959702c686SJanusz Dziedzic 	}
25969702c686SJanusz Dziedzic 
259753c8d48bSMarcin Rokicki 	debugfs_create_file("pktlog_filter", 0644, ar->debug.debugfs_phy, ar,
259853c8d48bSMarcin Rokicki 			    &fops_pktlog_filter);
259990174455SRajkumar Manoharan 
260053884577SRakesh Pillai 	if (test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
260153c8d48bSMarcin Rokicki 		debugfs_create_file("quiet_period", 0644, ar->debug.debugfs_phy, ar,
260253c8d48bSMarcin Rokicki 				    &fops_quiet_period);
260363fb32dfSRajkumar Manoharan 
260453c8d48bSMarcin Rokicki 	debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_phy, ar,
260553c8d48bSMarcin Rokicki 			    &fops_tpc_stats);
260629542666SMaharaja Kennadyrajan 
2607844fa572SYanbo Li 	if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
260853c8d48bSMarcin Rokicki 		debugfs_create_file("btcoex", 0644, ar->debug.debugfs_phy, ar,
260953c8d48bSMarcin Rokicki 				    &fops_btcoex);
2610844fa572SYanbo Li 
2611348cd95cSAnilkumar Kolli 	if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
261253c8d48bSMarcin Rokicki 		debugfs_create_file("peer_stats", 0644, ar->debug.debugfs_phy, ar,
2613cc61a1bbSMohammed Shafi Shajakhan 				    &fops_peer_stats);
2614cc61a1bbSMohammed Shafi Shajakhan 
2615348cd95cSAnilkumar Kolli 		debugfs_create_file("enable_extd_tx_stats", 0644,
2616348cd95cSAnilkumar Kolli 				    ar->debug.debugfs_phy, ar,
2617348cd95cSAnilkumar Kolli 				    &fops_enable_extd_tx_stats);
2618348cd95cSAnilkumar Kolli 	}
2619348cd95cSAnilkumar Kolli 
262053c8d48bSMarcin Rokicki 	debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
262153c8d48bSMarcin Rokicki 			    &fops_fw_checksums);
26229e100c4dSKalle Valo 
2623caee728aSVasanthakumar Thiagarajan 	if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS))
2624caee728aSVasanthakumar Thiagarajan 		debugfs_create_file("sta_tid_stats_mask", 0600,
2625caee728aSVasanthakumar Thiagarajan 				    ar->debug.debugfs_phy,
2626caee728aSVasanthakumar Thiagarajan 				    ar, &fops_sta_tid_stats_mask);
2627caee728aSVasanthakumar Thiagarajan 
2628bc64d052SMaharaja Kennadyrajan 	if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))
2629bc64d052SMaharaja Kennadyrajan 		debugfs_create_file("tpc_stats_final", 0400,
2630bc64d052SMaharaja Kennadyrajan 				    ar->debug.debugfs_phy, ar,
2631bc64d052SMaharaja Kennadyrajan 				    &fops_tpc_stats_final);
2632bc64d052SMaharaja Kennadyrajan 
2633bbdc8c5aSYingying Tang 	if (test_bit(WMI_SERVICE_RESET_CHIP, ar->wmi.svc_map))
2634bbdc8c5aSYingying Tang 		debugfs_create_file("warm_hw_reset", 0600,
2635bbdc8c5aSYingying Tang 				    ar->debug.debugfs_phy, ar,
2636db251d7dSMaharaja Kennadyrajan 				    &fops_warm_hw_reset);
2637db251d7dSMaharaja Kennadyrajan 
2638d70c0d46SMaharaja Kennadyrajan 	debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_phy, ar,
2639d70c0d46SMaharaja Kennadyrajan 			    &fops_ps_state_enable);
2640d70c0d46SMaharaja Kennadyrajan 
2641473a4084SMaharaja Kennadyrajan 	debugfs_create_file("reset_htt_stats", 0200, ar->debug.debugfs_phy, ar,
2642473a4084SMaharaja Kennadyrajan 			    &fops_reset_htt_stats);
2643473a4084SMaharaja Kennadyrajan 
26445e3dd157SKalle Valo 	return 0;
26455e3dd157SKalle Valo }
2646db66ea04SKalle Valo 
ath10k_debug_unregister(struct ath10k * ar)2647e13cf7a3SMichal Kazior void ath10k_debug_unregister(struct ath10k *ar)
264860631c5cSKalle Valo {
264960631c5cSKalle Valo 	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
265060631c5cSKalle Valo }
265160631c5cSKalle Valo 
26525e3dd157SKalle Valo #endif /* CONFIG_ATH10K_DEBUGFS */
26535e3dd157SKalle Valo 
26545e3dd157SKalle Valo #ifdef CONFIG_ATH10K_DEBUG
__ath10k_dbg(struct ath10k * ar,enum ath10k_debug_mask mask,const char * fmt,...)26559d740d63SVenkateswara Naralasetty void __ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
26567aa7a72aSMichal Kazior 		  const char *fmt, ...)
26575e3dd157SKalle Valo {
26585e3dd157SKalle Valo 	struct va_format vaf;
26595e3dd157SKalle Valo 	va_list args;
26605e3dd157SKalle Valo 
26615e3dd157SKalle Valo 	va_start(args, fmt);
26625e3dd157SKalle Valo 
26635e3dd157SKalle Valo 	vaf.fmt = fmt;
26645e3dd157SKalle Valo 	vaf.va = &args;
26655e3dd157SKalle Valo 
26665e3dd157SKalle Valo 	if (ath10k_debug_mask & mask)
26677aa7a72aSMichal Kazior 		dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
26685e3dd157SKalle Valo 
2669d35a6c18SMichal Kazior 	trace_ath10k_log_dbg(ar, mask, &vaf);
26705e3dd157SKalle Valo 
26715e3dd157SKalle Valo 	va_end(args);
26725e3dd157SKalle Valo }
26739d740d63SVenkateswara Naralasetty EXPORT_SYMBOL(__ath10k_dbg);
26745e3dd157SKalle Valo 
ath10k_dbg_dump(struct ath10k * ar,enum ath10k_debug_mask mask,const char * msg,const char * prefix,const void * buf,size_t len)26757aa7a72aSMichal Kazior void ath10k_dbg_dump(struct ath10k *ar,
26767aa7a72aSMichal Kazior 		     enum ath10k_debug_mask mask,
26775e3dd157SKalle Valo 		     const char *msg, const char *prefix,
26785e3dd157SKalle Valo 		     const void *buf, size_t len)
26795e3dd157SKalle Valo {
268045724a8aSMichal Kazior 	char linebuf[256];
2681182f1e5aSAmadeusz Sławiński 	size_t linebuflen;
268245724a8aSMichal Kazior 	const void *ptr;
268345724a8aSMichal Kazior 
26845e3dd157SKalle Valo 	if (ath10k_debug_mask & mask) {
26855e3dd157SKalle Valo 		if (msg)
26869d740d63SVenkateswara Naralasetty 			__ath10k_dbg(ar, mask, "%s\n", msg);
26875e3dd157SKalle Valo 
268845724a8aSMichal Kazior 		for (ptr = buf; (ptr - buf) < len; ptr += 16) {
268945724a8aSMichal Kazior 			linebuflen = 0;
269045724a8aSMichal Kazior 			linebuflen += scnprintf(linebuf + linebuflen,
269145724a8aSMichal Kazior 						sizeof(linebuf) - linebuflen,
269245724a8aSMichal Kazior 						"%s%08x: ",
269345724a8aSMichal Kazior 						(prefix ? prefix : ""),
269445724a8aSMichal Kazior 						(unsigned int)(ptr - buf));
269545724a8aSMichal Kazior 			hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
269645724a8aSMichal Kazior 					   linebuf + linebuflen,
269745724a8aSMichal Kazior 					   sizeof(linebuf) - linebuflen, true);
269845724a8aSMichal Kazior 			dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);
269945724a8aSMichal Kazior 		}
27005e3dd157SKalle Valo 	}
27015e3dd157SKalle Valo 
27025e3dd157SKalle Valo 	/* tracing code doesn't like null strings :/ */
2703d35a6c18SMichal Kazior 	trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "",
27045e3dd157SKalle Valo 				  buf, len);
27055e3dd157SKalle Valo }
27065e3dd157SKalle Valo EXPORT_SYMBOL(ath10k_dbg_dump);
27075e3dd157SKalle Valo 
27085e3dd157SKalle Valo #endif /* CONFIG_ATH10K_DEBUG */
2709