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