xref: /src/sys/contrib/dev/athk/ath12k/debugfs.c (revision a96550206e4bde15bf615ff2127b80404a7ec41f)
107b9f6ccSBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
207b9f6ccSBjoern A. Zeeb /*
307b9f6ccSBjoern A. Zeeb  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4025f935eSBjoern A. Zeeb  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
507b9f6ccSBjoern A. Zeeb  */
607b9f6ccSBjoern A. Zeeb 
707b9f6ccSBjoern A. Zeeb #include "core.h"
84aae7925SBjoern A. Zeeb #include "dp_tx.h"
94aae7925SBjoern A. Zeeb #include "debug.h"
1007b9f6ccSBjoern A. Zeeb #include "debugfs.h"
1107b9f6ccSBjoern A. Zeeb #include "debugfs_htt_stats.h"
1207b9f6ccSBjoern A. Zeeb 
ath12k_write_simulate_radar(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1307b9f6ccSBjoern A. Zeeb static ssize_t ath12k_write_simulate_radar(struct file *file,
1407b9f6ccSBjoern A. Zeeb 					   const char __user *user_buf,
1507b9f6ccSBjoern A. Zeeb 					   size_t count, loff_t *ppos)
1607b9f6ccSBjoern A. Zeeb {
1707b9f6ccSBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
1807b9f6ccSBjoern A. Zeeb 	int ret;
1907b9f6ccSBjoern A. Zeeb 
2007b9f6ccSBjoern A. Zeeb 	wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
2107b9f6ccSBjoern A. Zeeb 	ret = ath12k_wmi_simulate_radar(ar);
2207b9f6ccSBjoern A. Zeeb 	if (ret)
2307b9f6ccSBjoern A. Zeeb 		goto exit;
2407b9f6ccSBjoern A. Zeeb 
2507b9f6ccSBjoern A. Zeeb 	ret = count;
2607b9f6ccSBjoern A. Zeeb exit:
2707b9f6ccSBjoern A. Zeeb 	wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
2807b9f6ccSBjoern A. Zeeb 	return ret;
2907b9f6ccSBjoern A. Zeeb }
3007b9f6ccSBjoern A. Zeeb 
3107b9f6ccSBjoern A. Zeeb static const struct file_operations fops_simulate_radar = {
3207b9f6ccSBjoern A. Zeeb 	.write = ath12k_write_simulate_radar,
3307b9f6ccSBjoern A. Zeeb 	.open = simple_open
3407b9f6ccSBjoern A. Zeeb };
3507b9f6ccSBjoern A. Zeeb 
ath12k_read_simulate_fw_crash(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)364aae7925SBjoern A. Zeeb static ssize_t ath12k_read_simulate_fw_crash(struct file *file,
374aae7925SBjoern A. Zeeb 					     char __user *user_buf,
384aae7925SBjoern A. Zeeb 					     size_t count, loff_t *ppos)
394aae7925SBjoern A. Zeeb {
404aae7925SBjoern A. Zeeb 	const char buf[] =
414aae7925SBjoern A. Zeeb 		"To simulate firmware crash write one of the keywords to this file:\n"
424aae7925SBjoern A. Zeeb 		"`assert` - send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n";
434aae7925SBjoern A. Zeeb 
444aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
454aae7925SBjoern A. Zeeb }
464aae7925SBjoern A. Zeeb 
474aae7925SBjoern A. Zeeb static ssize_t
ath12k_write_simulate_fw_crash(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)484aae7925SBjoern A. Zeeb ath12k_write_simulate_fw_crash(struct file *file,
494aae7925SBjoern A. Zeeb 			       const char __user *user_buf,
504aae7925SBjoern A. Zeeb 			       size_t count, loff_t *ppos)
514aae7925SBjoern A. Zeeb {
524aae7925SBjoern A. Zeeb 	struct ath12k_base *ab = file->private_data;
534aae7925SBjoern A. Zeeb 	struct ath12k_pdev *pdev;
544aae7925SBjoern A. Zeeb 	struct ath12k *ar = NULL;
55fa442f39SBjoern A. Zeeb 	char buf[32] = {};
564aae7925SBjoern A. Zeeb 	int i, ret;
574aae7925SBjoern A. Zeeb 	ssize_t rc;
584aae7925SBjoern A. Zeeb 
594aae7925SBjoern A. Zeeb 	/* filter partial writes and invalid commands */
604aae7925SBjoern A. Zeeb 	if (*ppos != 0 || count >= sizeof(buf) || count == 0)
614aae7925SBjoern A. Zeeb 		return -EINVAL;
624aae7925SBjoern A. Zeeb 
634aae7925SBjoern A. Zeeb 	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
644aae7925SBjoern A. Zeeb 	if (rc < 0)
654aae7925SBjoern A. Zeeb 		return rc;
664aae7925SBjoern A. Zeeb 
674aae7925SBjoern A. Zeeb 	/* drop the possible '\n' from the end */
684aae7925SBjoern A. Zeeb 	if (buf[*ppos - 1] == '\n')
694aae7925SBjoern A. Zeeb 		buf[*ppos - 1] = '\0';
704aae7925SBjoern A. Zeeb 
714aae7925SBjoern A. Zeeb 	for (i = 0; i < ab->num_radios; i++) {
724aae7925SBjoern A. Zeeb 		pdev = &ab->pdevs[i];
734aae7925SBjoern A. Zeeb 		ar = pdev->ar;
744aae7925SBjoern A. Zeeb 		if (ar)
754aae7925SBjoern A. Zeeb 			break;
764aae7925SBjoern A. Zeeb 	}
774aae7925SBjoern A. Zeeb 
784aae7925SBjoern A. Zeeb 	if (!ar)
794aae7925SBjoern A. Zeeb 		return -ENETDOWN;
804aae7925SBjoern A. Zeeb 
814aae7925SBjoern A. Zeeb 	if (!strcmp(buf, "assert")) {
824aae7925SBjoern A. Zeeb 		ath12k_info(ab, "simulating firmware assert crash\n");
834aae7925SBjoern A. Zeeb 		ret = ath12k_wmi_force_fw_hang_cmd(ar,
844aae7925SBjoern A. Zeeb 						   ATH12K_WMI_FW_HANG_ASSERT_TYPE,
854aae7925SBjoern A. Zeeb 						   ATH12K_WMI_FW_HANG_DELAY);
864aae7925SBjoern A. Zeeb 	} else {
874aae7925SBjoern A. Zeeb 		return -EINVAL;
884aae7925SBjoern A. Zeeb 	}
894aae7925SBjoern A. Zeeb 
904aae7925SBjoern A. Zeeb 	if (ret) {
914aae7925SBjoern A. Zeeb 		ath12k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
924aae7925SBjoern A. Zeeb 		return ret;
934aae7925SBjoern A. Zeeb 	}
944aae7925SBjoern A. Zeeb 
954aae7925SBjoern A. Zeeb 	return count;
964aae7925SBjoern A. Zeeb }
974aae7925SBjoern A. Zeeb 
984aae7925SBjoern A. Zeeb static const struct file_operations fops_simulate_fw_crash = {
994aae7925SBjoern A. Zeeb 	.read = ath12k_read_simulate_fw_crash,
1004aae7925SBjoern A. Zeeb 	.write = ath12k_write_simulate_fw_crash,
1014aae7925SBjoern A. Zeeb 	.open = simple_open,
1024aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
1034aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
1044aae7925SBjoern A. Zeeb };
1054aae7925SBjoern A. Zeeb 
ath12k_write_tpc_stats_type(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1064aae7925SBjoern A. Zeeb static ssize_t ath12k_write_tpc_stats_type(struct file *file,
1074aae7925SBjoern A. Zeeb 					   const char __user *user_buf,
1084aae7925SBjoern A. Zeeb 					   size_t count, loff_t *ppos)
1094aae7925SBjoern A. Zeeb {
1104aae7925SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
1114aae7925SBjoern A. Zeeb 	u8 type;
1124aae7925SBjoern A. Zeeb 	int ret;
1134aae7925SBjoern A. Zeeb 
1144aae7925SBjoern A. Zeeb 	ret = kstrtou8_from_user(user_buf, count, 0, &type);
1154aae7925SBjoern A. Zeeb 	if (ret)
1164aae7925SBjoern A. Zeeb 		return ret;
1174aae7925SBjoern A. Zeeb 
1184aae7925SBjoern A. Zeeb 	if (type >= WMI_HALPHY_PDEV_TX_STATS_MAX)
1194aae7925SBjoern A. Zeeb 		return -EINVAL;
1204aae7925SBjoern A. Zeeb 
1214aae7925SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
1224aae7925SBjoern A. Zeeb 	ar->debug.tpc_stats_type = type;
1234aae7925SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
1244aae7925SBjoern A. Zeeb 
1254aae7925SBjoern A. Zeeb 	return count;
1264aae7925SBjoern A. Zeeb }
1274aae7925SBjoern A. Zeeb 
ath12k_debug_tpc_stats_request(struct ath12k * ar)1284aae7925SBjoern A. Zeeb static int ath12k_debug_tpc_stats_request(struct ath12k *ar)
1294aae7925SBjoern A. Zeeb {
1304aae7925SBjoern A. Zeeb 	enum wmi_halphy_ctrl_path_stats_id tpc_stats_sub_id;
1314aae7925SBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
1324aae7925SBjoern A. Zeeb 	int ret;
1334aae7925SBjoern A. Zeeb 
1344aae7925SBjoern A. Zeeb 	lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
1354aae7925SBjoern A. Zeeb 
1364aae7925SBjoern A. Zeeb 	reinit_completion(&ar->debug.tpc_complete);
1374aae7925SBjoern A. Zeeb 
1384aae7925SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
1394aae7925SBjoern A. Zeeb 	ar->debug.tpc_request = true;
1404aae7925SBjoern A. Zeeb 	tpc_stats_sub_id = ar->debug.tpc_stats_type;
1414aae7925SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
1424aae7925SBjoern A. Zeeb 
1434aae7925SBjoern A. Zeeb 	ret = ath12k_wmi_send_tpc_stats_request(ar, tpc_stats_sub_id);
1444aae7925SBjoern A. Zeeb 	if (ret) {
1454aae7925SBjoern A. Zeeb 		ath12k_warn(ab, "failed to request pdev tpc stats: %d\n", ret);
1464aae7925SBjoern A. Zeeb 		spin_lock_bh(&ar->data_lock);
1474aae7925SBjoern A. Zeeb 		ar->debug.tpc_request = false;
1484aae7925SBjoern A. Zeeb 		spin_unlock_bh(&ar->data_lock);
1494aae7925SBjoern A. Zeeb 		return ret;
1504aae7925SBjoern A. Zeeb 	}
1514aae7925SBjoern A. Zeeb 
1524aae7925SBjoern A. Zeeb 	return 0;
1534aae7925SBjoern A. Zeeb }
1544aae7925SBjoern A. Zeeb 
ath12k_get_tpc_ctl_mode_idx(struct wmi_tpc_stats_arg * tpc_stats,enum wmi_tpc_pream_bw pream_bw,int * mode_idx)1554aae7925SBjoern A. Zeeb static int ath12k_get_tpc_ctl_mode_idx(struct wmi_tpc_stats_arg *tpc_stats,
1564aae7925SBjoern A. Zeeb 				       enum wmi_tpc_pream_bw pream_bw, int *mode_idx)
1574aae7925SBjoern A. Zeeb {
1584aae7925SBjoern A. Zeeb 	u32 chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
1594aae7925SBjoern A. Zeeb 	u8 band;
1604aae7925SBjoern A. Zeeb 
1614aae7925SBjoern A. Zeeb 	band = ((chan_freq > ATH12K_MIN_6GHZ_FREQ) ? NL80211_BAND_6GHZ :
1624aae7925SBjoern A. Zeeb 		((chan_freq > ATH12K_MIN_5GHZ_FREQ) ? NL80211_BAND_5GHZ :
1634aae7925SBjoern A. Zeeb 		NL80211_BAND_2GHZ));
1644aae7925SBjoern A. Zeeb 
1654aae7925SBjoern A. Zeeb 	if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {
1664aae7925SBjoern A. Zeeb 		switch (pream_bw) {
1674aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT20:
1684aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT20:
1694aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ;
1704aae7925SBjoern A. Zeeb 			break;
1714aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE20:
1724aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT20:
1734aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ;
1744aae7925SBjoern A. Zeeb 			break;
1754aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT40:
1764aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT40:
1774aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ;
1784aae7925SBjoern A. Zeeb 			break;
1794aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE40:
1804aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT40:
1814aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ;
1824aae7925SBjoern A. Zeeb 			break;
1834aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT80:
1844aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ;
1854aae7925SBjoern A. Zeeb 			break;
1864aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT60:
1874aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20;
1884aae7925SBjoern A. Zeeb 			break;
1894aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE80:
1904aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT80:
1914aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ;
1924aae7925SBjoern A. Zeeb 			break;
1934aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT160:
1944aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ;
1954aae7925SBjoern A. Zeeb 			break;
1964aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT120:
1974aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT140:
1984aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20;
1994aae7925SBjoern A. Zeeb 			break;
2004aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE160:
2014aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT160:
2024aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ;
2034aae7925SBjoern A. Zeeb 			break;
2044aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT200:
2054aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120;
2064aae7925SBjoern A. Zeeb 			break;
2074aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT240:
2084aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80;
2094aae7925SBjoern A. Zeeb 			break;
2104aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT280:
2114aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40;
2124aae7925SBjoern A. Zeeb 			break;
2134aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT320:
2144aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ;
2154aae7925SBjoern A. Zeeb 			break;
2164aae7925SBjoern A. Zeeb 		default:
2174aae7925SBjoern A. Zeeb 			/* for 5GHZ and 6GHZ, default case will be for OFDM */
2184aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ;
2194aae7925SBjoern A. Zeeb 			break;
2204aae7925SBjoern A. Zeeb 		}
2214aae7925SBjoern A. Zeeb 	} else {
2224aae7925SBjoern A. Zeeb 		switch (pream_bw) {
2234aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_OFDM:
2244aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ;
2254aae7925SBjoern A. Zeeb 			break;
2264aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT20:
2274aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT20:
2284aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE20:
2294aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT20:
2304aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ;
2314aae7925SBjoern A. Zeeb 			break;
2324aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT40:
2334aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT40:
2344aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE40:
2354aae7925SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT40:
2364aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ;
2374aae7925SBjoern A. Zeeb 			break;
2384aae7925SBjoern A. Zeeb 		default:
2394aae7925SBjoern A. Zeeb 			/* for 2GHZ, default case will be CCK */
2404aae7925SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ;
2414aae7925SBjoern A. Zeeb 			break;
2424aae7925SBjoern A. Zeeb 		}
2434aae7925SBjoern A. Zeeb 	}
2444aae7925SBjoern A. Zeeb 
2454aae7925SBjoern A. Zeeb 	return 0;
2464aae7925SBjoern A. Zeeb }
2474aae7925SBjoern A. Zeeb 
ath12k_tpc_get_rate(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,u32 rate_idx,u32 num_chains,u32 rate_code,enum wmi_tpc_pream_bw pream_bw,enum wmi_halphy_ctrl_path_stats_id type,u32 eht_rate_idx)2484aae7925SBjoern A. Zeeb static s16 ath12k_tpc_get_rate(struct ath12k *ar,
2494aae7925SBjoern A. Zeeb 			       struct wmi_tpc_stats_arg *tpc_stats,
2504aae7925SBjoern A. Zeeb 			       u32 rate_idx, u32 num_chains, u32 rate_code,
2514aae7925SBjoern A. Zeeb 			       enum wmi_tpc_pream_bw pream_bw,
2524aae7925SBjoern A. Zeeb 			       enum wmi_halphy_ctrl_path_stats_id type,
2534aae7925SBjoern A. Zeeb 			       u32 eht_rate_idx)
2544aae7925SBjoern A. Zeeb {
2554aae7925SBjoern A. Zeeb 	u32 tot_nss, tot_modes, txbf_on_off, index_offset1, index_offset2, index_offset3;
2564aae7925SBjoern A. Zeeb 	u8 chain_idx, stm_idx, num_streams;
2574aae7925SBjoern A. Zeeb 	bool is_mu, txbf_enabled = 0;
2584aae7925SBjoern A. Zeeb 	s8 rates_ctl_min, tpc_ctl;
2594aae7925SBjoern A. Zeeb 	s16 rates, tpc, reg_pwr;
2604aae7925SBjoern A. Zeeb 	u16 rate1, rate2;
2614aae7925SBjoern A. Zeeb 	int mode, ret;
2624aae7925SBjoern A. Zeeb 
2634aae7925SBjoern A. Zeeb 	num_streams = 1 + ATH12K_HW_NSS(rate_code);
2644aae7925SBjoern A. Zeeb 	chain_idx = num_chains - 1;
2654aae7925SBjoern A. Zeeb 	stm_idx = num_streams - 1;
2664aae7925SBjoern A. Zeeb 	mode = -1;
2674aae7925SBjoern A. Zeeb 
2684aae7925SBjoern A. Zeeb 	ret = ath12k_get_tpc_ctl_mode_idx(tpc_stats, pream_bw, &mode);
2694aae7925SBjoern A. Zeeb 	if (ret) {
2704aae7925SBjoern A. Zeeb 		ath12k_warn(ar->ab, "Invalid mode index received\n");
2714aae7925SBjoern A. Zeeb 		tpc = TPC_INVAL;
2724aae7925SBjoern A. Zeeb 		goto out;
2734aae7925SBjoern A. Zeeb 	}
2744aae7925SBjoern A. Zeeb 
2754aae7925SBjoern A. Zeeb 	if (num_chains < num_streams) {
2764aae7925SBjoern A. Zeeb 		tpc = TPC_INVAL;
2774aae7925SBjoern A. Zeeb 		goto out;
2784aae7925SBjoern A. Zeeb 	}
2794aae7925SBjoern A. Zeeb 
2804aae7925SBjoern A. Zeeb 	if (le32_to_cpu(tpc_stats->tpc_config.num_tx_chain) <= 1) {
2814aae7925SBjoern A. Zeeb 		tpc = TPC_INVAL;
2824aae7925SBjoern A. Zeeb 		goto out;
2834aae7925SBjoern A. Zeeb 	}
2844aae7925SBjoern A. Zeeb 
2854aae7925SBjoern A. Zeeb 	if (type == WMI_HALPHY_PDEV_TX_SUTXBF_STATS ||
2864aae7925SBjoern A. Zeeb 	    type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS)
2874aae7925SBjoern A. Zeeb 		txbf_enabled = 1;
2884aae7925SBjoern A. Zeeb 
2894aae7925SBjoern A. Zeeb 	if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
2904aae7925SBjoern A. Zeeb 	    type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
2914aae7925SBjoern A. Zeeb 		is_mu = true;
2924aae7925SBjoern A. Zeeb 	} else {
2934aae7925SBjoern A. Zeeb 		is_mu = false;
2944aae7925SBjoern A. Zeeb 	}
2954aae7925SBjoern A. Zeeb 
2964aae7925SBjoern A. Zeeb 	/* Below is the min calculation of ctl array, rates array and
2974aae7925SBjoern A. Zeeb 	 * regulator power table. tpc is minimum of all 3
2984aae7925SBjoern A. Zeeb 	 */
2994aae7925SBjoern A. Zeeb 	if (pream_bw >= WMI_TPC_PREAM_EHT20 && pream_bw <= WMI_TPC_PREAM_EHT320) {
3004aae7925SBjoern A. Zeeb 		rate2 = tpc_stats->rates_array2.rate_array[eht_rate_idx];
3014aae7925SBjoern A. Zeeb 		if (is_mu)
3024aae7925SBjoern A. Zeeb 			rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_MU);
3034aae7925SBjoern A. Zeeb 		else
3044aae7925SBjoern A. Zeeb 			rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_SU);
3054aae7925SBjoern A. Zeeb 	} else {
3064aae7925SBjoern A. Zeeb 		rate1 = tpc_stats->rates_array1.rate_array[rate_idx];
3074aae7925SBjoern A. Zeeb 		if (is_mu)
3084aae7925SBjoern A. Zeeb 			rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_MU);
3094aae7925SBjoern A. Zeeb 		else
3104aae7925SBjoern A. Zeeb 			rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_SU);
3114aae7925SBjoern A. Zeeb 	}
3124aae7925SBjoern A. Zeeb 
3134aae7925SBjoern A. Zeeb 	if (tpc_stats->tlvs_rcvd & WMI_TPC_CTL_PWR_ARRAY) {
3144aae7925SBjoern A. Zeeb 		tot_nss = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d1);
3154aae7925SBjoern A. Zeeb 		tot_modes = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d2);
3164aae7925SBjoern A. Zeeb 		txbf_on_off = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d3);
3174aae7925SBjoern A. Zeeb 		index_offset1 = txbf_on_off * tot_modes * tot_nss;
3184aae7925SBjoern A. Zeeb 		index_offset2 = tot_modes * tot_nss;
3194aae7925SBjoern A. Zeeb 		index_offset3 = tot_nss;
3204aae7925SBjoern A. Zeeb 
3214aae7925SBjoern A. Zeeb 		tpc_ctl = *(tpc_stats->ctl_array.ctl_pwr_table +
3224aae7925SBjoern A. Zeeb 			    chain_idx * index_offset1 + txbf_enabled * index_offset2
3234aae7925SBjoern A. Zeeb 			    + mode * index_offset3 + stm_idx);
3244aae7925SBjoern A. Zeeb 	} else {
3254aae7925SBjoern A. Zeeb 		tpc_ctl = TPC_MAX;
3264aae7925SBjoern A. Zeeb 		ath12k_warn(ar->ab,
3274aae7925SBjoern A. Zeeb 			    "ctl array for tpc stats not received from fw\n");
3284aae7925SBjoern A. Zeeb 	}
3294aae7925SBjoern A. Zeeb 
3304aae7925SBjoern A. Zeeb 	rates_ctl_min = min_t(s16, rates, tpc_ctl);
3314aae7925SBjoern A. Zeeb 
3324aae7925SBjoern A. Zeeb 	reg_pwr = tpc_stats->max_reg_allowed_power.reg_pwr_array[chain_idx];
3334aae7925SBjoern A. Zeeb 
3344aae7925SBjoern A. Zeeb 	if (reg_pwr < 0)
3354aae7925SBjoern A. Zeeb 		reg_pwr = TPC_INVAL;
3364aae7925SBjoern A. Zeeb 
3374aae7925SBjoern A. Zeeb 	tpc = min_t(s16, rates_ctl_min, reg_pwr);
3384aae7925SBjoern A. Zeeb 
3394aae7925SBjoern A. Zeeb 	/* MODULATION_LIMIT is the maximum power limit,tpc should not exceed
3404aae7925SBjoern A. Zeeb 	 * modulation limit even if min tpc of all three array is greater
3414aae7925SBjoern A. Zeeb 	 * modulation limit
3424aae7925SBjoern A. Zeeb 	 */
3434aae7925SBjoern A. Zeeb 	tpc = min_t(s16, tpc, MODULATION_LIMIT);
3444aae7925SBjoern A. Zeeb 
3454aae7925SBjoern A. Zeeb out:
3464aae7925SBjoern A. Zeeb 	return tpc;
3474aae7925SBjoern A. Zeeb }
3484aae7925SBjoern A. Zeeb 
ath12k_get_ratecode(u16 pream_idx,u16 nss,u16 mcs_rate)3494aae7925SBjoern A. Zeeb static u16 ath12k_get_ratecode(u16 pream_idx, u16 nss, u16 mcs_rate)
3504aae7925SBjoern A. Zeeb {
3514aae7925SBjoern A. Zeeb 	u16 mode_type = ~0;
3524aae7925SBjoern A. Zeeb 
3534aae7925SBjoern A. Zeeb 	/* Below assignments are just for printing purpose only */
3544aae7925SBjoern A. Zeeb 	switch (pream_idx) {
3554aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_CCK:
3564aae7925SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_CCK;
3574aae7925SBjoern A. Zeeb 		break;
3584aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_OFDM:
3594aae7925SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_OFDM;
3604aae7925SBjoern A. Zeeb 		break;
3614aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_HT20:
3624aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_HT40:
3634aae7925SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_HT;
3644aae7925SBjoern A. Zeeb 		break;
3654aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT20:
3664aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT40:
3674aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT80:
3684aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT160:
3694aae7925SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_VHT;
3704aae7925SBjoern A. Zeeb 		break;
3714aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE20:
3724aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE40:
3734aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE80:
3744aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE160:
3754aae7925SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_HE;
3764aae7925SBjoern A. Zeeb 		break;
3774aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT20:
3784aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT40:
3794aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT60:
3804aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT80:
3814aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT120:
3824aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT140:
3834aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT160:
3844aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT200:
3854aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT240:
3864aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT280:
3874aae7925SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT320:
3884aae7925SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_EHT;
3894aae7925SBjoern A. Zeeb 		if (mcs_rate == 0 || mcs_rate == 1)
3904aae7925SBjoern A. Zeeb 			mcs_rate += 14;
3914aae7925SBjoern A. Zeeb 		else
3924aae7925SBjoern A. Zeeb 			mcs_rate -= 2;
3934aae7925SBjoern A. Zeeb 		break;
3944aae7925SBjoern A. Zeeb 	default:
3954aae7925SBjoern A. Zeeb 		return mode_type;
3964aae7925SBjoern A. Zeeb 	}
3974aae7925SBjoern A. Zeeb 	return ((mode_type << 8) | ((nss & 0x7) << 5) | (mcs_rate & 0x1F));
3984aae7925SBjoern A. Zeeb }
3994aae7925SBjoern A. Zeeb 
ath12k_he_supports_extra_mcs(struct ath12k * ar,int freq)4004aae7925SBjoern A. Zeeb static bool ath12k_he_supports_extra_mcs(struct ath12k *ar, int freq)
4014aae7925SBjoern A. Zeeb {
4024aae7925SBjoern A. Zeeb 	struct ath12k_pdev_cap *cap = &ar->pdev->cap;
4034aae7925SBjoern A. Zeeb 	struct ath12k_band_cap *cap_band;
4044aae7925SBjoern A. Zeeb 	bool extra_mcs_supported;
4054aae7925SBjoern A. Zeeb 
4064aae7925SBjoern A. Zeeb 	if (freq <= ATH12K_2GHZ_MAX_FREQUENCY)
4074aae7925SBjoern A. Zeeb 		cap_band = &cap->band[NL80211_BAND_2GHZ];
4084aae7925SBjoern A. Zeeb 	else if (freq <= ATH12K_5GHZ_MAX_FREQUENCY)
4094aae7925SBjoern A. Zeeb 		cap_band = &cap->band[NL80211_BAND_5GHZ];
4104aae7925SBjoern A. Zeeb 	else
4114aae7925SBjoern A. Zeeb 		cap_band = &cap->band[NL80211_BAND_6GHZ];
4124aae7925SBjoern A. Zeeb 
4134aae7925SBjoern A. Zeeb 	extra_mcs_supported = u32_get_bits(cap_band->he_cap_info[1],
4144aae7925SBjoern A. Zeeb 					   HE_EXTRA_MCS_SUPPORT);
4154aae7925SBjoern A. Zeeb 	return extra_mcs_supported;
4164aae7925SBjoern A. Zeeb }
4174aae7925SBjoern A. Zeeb 
ath12k_tpc_fill_pream(struct ath12k * ar,char * buf,int buf_len,int len,enum wmi_tpc_pream_bw pream_bw,u32 max_rix,int max_nss,int max_rates,int pream_type,enum wmi_halphy_ctrl_path_stats_id tpc_type,int rate_idx,int eht_rate_idx)4184aae7925SBjoern A. Zeeb static int ath12k_tpc_fill_pream(struct ath12k *ar, char *buf, int buf_len, int len,
4194aae7925SBjoern A. Zeeb 				 enum wmi_tpc_pream_bw pream_bw, u32 max_rix,
4204aae7925SBjoern A. Zeeb 				 int max_nss, int max_rates, int pream_type,
4214aae7925SBjoern A. Zeeb 				 enum wmi_halphy_ctrl_path_stats_id tpc_type,
4224aae7925SBjoern A. Zeeb 				 int rate_idx, int eht_rate_idx)
4234aae7925SBjoern A. Zeeb {
4244aae7925SBjoern A. Zeeb 	struct wmi_tpc_stats_arg *tpc_stats = ar->debug.tpc_stats;
4254aae7925SBjoern A. Zeeb 	int nss, rates, chains;
4264aae7925SBjoern A. Zeeb 	u8 active_tx_chains;
4274aae7925SBjoern A. Zeeb 	u16 rate_code;
4284aae7925SBjoern A. Zeeb 	s16 tpc;
4294aae7925SBjoern A. Zeeb 
4304aae7925SBjoern A. Zeeb 	static const char *const pream_str[] = {
4314aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = "CCK",
4324aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = "OFDM",
4334aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = "HT20",
4344aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = "HT40",
4354aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = "VHT20",
4364aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = "VHT40",
4374aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = "VHT80",
4384aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = "VHT160",
4394aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = "HE20",
4404aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = "HE40",
4414aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = "HE80",
4424aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = "HE160",
4434aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = "EHT20",
4444aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = "EHT40",
4454aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = "EHT60",
4464aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = "EHT80",
4474aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]   = "EHT120",
4484aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]   = "EHT140",
4494aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]   = "EHT160",
4504aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]   = "EHT200",
4514aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]   = "EHT240",
4524aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]   = "EHT280",
4534aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]   = "EHT320"};
4544aae7925SBjoern A. Zeeb 
4554aae7925SBjoern A. Zeeb 	active_tx_chains = ar->num_tx_chains;
4564aae7925SBjoern A. Zeeb 
4574aae7925SBjoern A. Zeeb 	for (nss = 0; nss < max_nss; nss++) {
4584aae7925SBjoern A. Zeeb 		for (rates = 0; rates < max_rates; rates++, rate_idx++, max_rix++) {
4594aae7925SBjoern A. Zeeb 			/* FW send extra MCS(10&11) for VHT and HE rates,
4604aae7925SBjoern A. Zeeb 			 *  this is not used. Hence skipping it here
4614aae7925SBjoern A. Zeeb 			 */
4624aae7925SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_VHT &&
4634aae7925SBjoern A. Zeeb 			    rates > ATH12K_VHT_MCS_MAX)
4644aae7925SBjoern A. Zeeb 				continue;
4654aae7925SBjoern A. Zeeb 
4664aae7925SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_HE &&
4674aae7925SBjoern A. Zeeb 			    rates > ATH12K_HE_MCS_MAX)
4684aae7925SBjoern A. Zeeb 				continue;
4694aae7925SBjoern A. Zeeb 
4704aae7925SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_EHT &&
4714aae7925SBjoern A. Zeeb 			    rates > ATH12K_EHT_MCS_MAX)
4724aae7925SBjoern A. Zeeb 				continue;
4734aae7925SBjoern A. Zeeb 
4744aae7925SBjoern A. Zeeb 			rate_code = ath12k_get_ratecode(pream_bw, nss, rates);
4754aae7925SBjoern A. Zeeb 			len += scnprintf(buf + len, buf_len - len,
4764aae7925SBjoern A. Zeeb 					 "%d\t %s\t 0x%03x\t", max_rix,
4774aae7925SBjoern A. Zeeb 					 pream_str[pream_bw], rate_code);
4784aae7925SBjoern A. Zeeb 
4794aae7925SBjoern A. Zeeb 			for (chains = 0; chains < active_tx_chains; chains++) {
4804aae7925SBjoern A. Zeeb 				if (nss > chains) {
4814aae7925SBjoern A. Zeeb 					len += scnprintf(buf + len,
4824aae7925SBjoern A. Zeeb 							 buf_len - len,
4834aae7925SBjoern A. Zeeb 							 "\t%s", "NA");
4844aae7925SBjoern A. Zeeb 				} else {
4854aae7925SBjoern A. Zeeb 					tpc = ath12k_tpc_get_rate(ar, tpc_stats,
4864aae7925SBjoern A. Zeeb 								  rate_idx, chains + 1,
4874aae7925SBjoern A. Zeeb 								  rate_code, pream_bw,
4884aae7925SBjoern A. Zeeb 								  tpc_type,
4894aae7925SBjoern A. Zeeb 								  eht_rate_idx);
4904aae7925SBjoern A. Zeeb 
4914aae7925SBjoern A. Zeeb 					if (tpc == TPC_INVAL) {
4924aae7925SBjoern A. Zeeb 						len += scnprintf(buf + len,
4934aae7925SBjoern A. Zeeb 								 buf_len - len, "\tNA");
4944aae7925SBjoern A. Zeeb 					} else {
4954aae7925SBjoern A. Zeeb 						len += scnprintf(buf + len,
4964aae7925SBjoern A. Zeeb 								 buf_len - len, "\t%d",
4974aae7925SBjoern A. Zeeb 								 tpc);
4984aae7925SBjoern A. Zeeb 					}
4994aae7925SBjoern A. Zeeb 				}
5004aae7925SBjoern A. Zeeb 			}
5014aae7925SBjoern A. Zeeb 			len += scnprintf(buf + len, buf_len - len, "\n");
5024aae7925SBjoern A. Zeeb 
5034aae7925SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_EHT)
5044aae7925SBjoern A. Zeeb 				/*For fetching the next eht rates pwr from rates array2*/
5054aae7925SBjoern A. Zeeb 				++eht_rate_idx;
5064aae7925SBjoern A. Zeeb 		}
5074aae7925SBjoern A. Zeeb 	}
5084aae7925SBjoern A. Zeeb 
5094aae7925SBjoern A. Zeeb 	return len;
5104aae7925SBjoern A. Zeeb }
5114aae7925SBjoern A. Zeeb 
ath12k_tpc_stats_print(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,char * buf,size_t len,enum wmi_halphy_ctrl_path_stats_id type)5124aae7925SBjoern A. Zeeb static int ath12k_tpc_stats_print(struct ath12k *ar,
5134aae7925SBjoern A. Zeeb 				  struct wmi_tpc_stats_arg *tpc_stats,
5144aae7925SBjoern A. Zeeb 				  char *buf, size_t len,
5154aae7925SBjoern A. Zeeb 				  enum wmi_halphy_ctrl_path_stats_id type)
5164aae7925SBjoern A. Zeeb {
5174aae7925SBjoern A. Zeeb 	u32 eht_idx = 0, pream_idx = 0, rate_pream_idx = 0, total_rates = 0, max_rix = 0;
5184aae7925SBjoern A. Zeeb 	u32 chan_freq, num_tx_chain, caps, i, j = 1;
5194aae7925SBjoern A. Zeeb 	size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
5204aae7925SBjoern A. Zeeb 	u8 nss, active_tx_chains;
5214aae7925SBjoern A. Zeeb 	bool he_ext_mcs;
5224aae7925SBjoern A. Zeeb 	static const char *const type_str[WMI_HALPHY_PDEV_TX_STATS_MAX] = {
5234aae7925SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_SU_STATS]		= "SU",
5244aae7925SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_SUTXBF_STATS]	= "SU WITH TXBF",
5254aae7925SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_MU_STATS]		= "MU",
5264aae7925SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_MUTXBF_STATS]	= "MU WITH TXBF"};
5274aae7925SBjoern A. Zeeb 
5284aae7925SBjoern A. Zeeb 	u8 max_rates[WMI_TPC_PREAM_MAX] = {
5294aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = ATH12K_CCK_RATES,
5304aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = ATH12K_OFDM_RATES,
5314aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = ATH12K_HT_RATES,
5324aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = ATH12K_HT_RATES,
5334aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = ATH12K_VHT_RATES,
5344aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = ATH12K_VHT_RATES,
5354aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = ATH12K_VHT_RATES,
5364aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = ATH12K_VHT_RATES,
5374aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = ATH12K_HE_RATES,
5384aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = ATH12K_HE_RATES,
5394aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = ATH12K_HE_RATES,
5404aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = ATH12K_HE_RATES,
5414aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = ATH12K_EHT_RATES,
5424aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = ATH12K_EHT_RATES,
5434aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = ATH12K_EHT_RATES,
5444aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = ATH12K_EHT_RATES,
5454aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]  = ATH12K_EHT_RATES,
5464aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]  = ATH12K_EHT_RATES,
5474aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]  = ATH12K_EHT_RATES,
5484aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]  = ATH12K_EHT_RATES,
5494aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]  = ATH12K_EHT_RATES,
5504aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]  = ATH12K_EHT_RATES,
5514aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]  = ATH12K_EHT_RATES};
5524aae7925SBjoern A. Zeeb 	static const u8 max_nss[WMI_TPC_PREAM_MAX] = {
5534aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = ATH12K_NSS_1,
5544aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = ATH12K_NSS_1,
5554aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = ATH12K_NSS_4,
5564aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = ATH12K_NSS_4,
5574aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = ATH12K_NSS_8,
5584aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = ATH12K_NSS_8,
5594aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = ATH12K_NSS_8,
5604aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = ATH12K_NSS_4,
5614aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = ATH12K_NSS_8,
5624aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = ATH12K_NSS_8,
5634aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = ATH12K_NSS_8,
5644aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = ATH12K_NSS_4,
5654aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = ATH12K_NSS_4,
5664aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = ATH12K_NSS_4,
5674aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = ATH12K_NSS_4,
5684aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = ATH12K_NSS_4,
5694aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]  = ATH12K_NSS_4,
5704aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]  = ATH12K_NSS_4,
5714aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]  = ATH12K_NSS_4,
5724aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]  = ATH12K_NSS_4,
5734aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]  = ATH12K_NSS_4,
5744aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]  = ATH12K_NSS_4,
5754aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]  = ATH12K_NSS_4};
5764aae7925SBjoern A. Zeeb 
5774aae7925SBjoern A. Zeeb 	u16 rate_idx[WMI_TPC_PREAM_MAX] = {}, eht_rate_idx[WMI_TPC_PREAM_MAX] = {};
5784aae7925SBjoern A. Zeeb 	static const u8 pream_type[WMI_TPC_PREAM_MAX] = {
5794aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = WMI_RATE_PREAMBLE_CCK,
5804aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = WMI_RATE_PREAMBLE_OFDM,
5814aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = WMI_RATE_PREAMBLE_HT,
5824aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = WMI_RATE_PREAMBLE_HT,
5834aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = WMI_RATE_PREAMBLE_VHT,
5844aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = WMI_RATE_PREAMBLE_VHT,
5854aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = WMI_RATE_PREAMBLE_VHT,
5864aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = WMI_RATE_PREAMBLE_VHT,
5874aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = WMI_RATE_PREAMBLE_HE,
5884aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = WMI_RATE_PREAMBLE_HE,
5894aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = WMI_RATE_PREAMBLE_HE,
5904aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = WMI_RATE_PREAMBLE_HE,
5914aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = WMI_RATE_PREAMBLE_EHT,
5924aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = WMI_RATE_PREAMBLE_EHT,
5934aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = WMI_RATE_PREAMBLE_EHT,
5944aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = WMI_RATE_PREAMBLE_EHT,
5954aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]  = WMI_RATE_PREAMBLE_EHT,
5964aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]  = WMI_RATE_PREAMBLE_EHT,
5974aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]  = WMI_RATE_PREAMBLE_EHT,
5984aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]  = WMI_RATE_PREAMBLE_EHT,
5994aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]  = WMI_RATE_PREAMBLE_EHT,
6004aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]  = WMI_RATE_PREAMBLE_EHT,
6014aae7925SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]  = WMI_RATE_PREAMBLE_EHT};
6024aae7925SBjoern A. Zeeb 
6034aae7925SBjoern A. Zeeb 	chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
6044aae7925SBjoern A. Zeeb 	num_tx_chain = le32_to_cpu(tpc_stats->tpc_config.num_tx_chain);
6054aae7925SBjoern A. Zeeb 	caps = le32_to_cpu(tpc_stats->tpc_config.caps);
6064aae7925SBjoern A. Zeeb 
6074aae7925SBjoern A. Zeeb 	active_tx_chains = ar->num_tx_chains;
6084aae7925SBjoern A. Zeeb 	he_ext_mcs = ath12k_he_supports_extra_mcs(ar, chan_freq);
6094aae7925SBjoern A. Zeeb 
6104aae7925SBjoern A. Zeeb 	/* mcs 12&13 is sent by FW for certain HWs in rate array, skipping it as
6114aae7925SBjoern A. Zeeb 	 * it is not supported
6124aae7925SBjoern A. Zeeb 	 */
6134aae7925SBjoern A. Zeeb 	if (he_ext_mcs) {
6144aae7925SBjoern A. Zeeb 		for (i = WMI_TPC_PREAM_HE20; i <= WMI_TPC_PREAM_HE160; ++i)
6154aae7925SBjoern A. Zeeb 			max_rates[i] = ATH12K_HE_RATES;
6164aae7925SBjoern A. Zeeb 	}
6174aae7925SBjoern A. Zeeb 
6184aae7925SBjoern A. Zeeb 	if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
6194aae7925SBjoern A. Zeeb 	    type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
6204aae7925SBjoern A. Zeeb 		pream_idx = WMI_TPC_PREAM_VHT20;
6214aae7925SBjoern A. Zeeb 
6224aae7925SBjoern A. Zeeb 		for (i = WMI_TPC_PREAM_CCK; i <= WMI_TPC_PREAM_HT40; ++i)
6234aae7925SBjoern A. Zeeb 			max_rix += max_nss[i] * max_rates[i];
6244aae7925SBjoern A. Zeeb 	}
6254aae7925SBjoern A. Zeeb 	/* Enumerate all the rate indices */
6264aae7925SBjoern A. Zeeb 	for (i = rate_pream_idx + 1; i < WMI_TPC_PREAM_MAX; i++) {
6274aae7925SBjoern A. Zeeb 		nss = (max_nss[i - 1] < num_tx_chain ?
6284aae7925SBjoern A. Zeeb 		       max_nss[i - 1] : num_tx_chain);
6294aae7925SBjoern A. Zeeb 
6304aae7925SBjoern A. Zeeb 		rate_idx[i] = rate_idx[i - 1] + max_rates[i - 1] * nss;
6314aae7925SBjoern A. Zeeb 
6324aae7925SBjoern A. Zeeb 		if (pream_type[i] == WMI_RATE_PREAMBLE_EHT) {
6334aae7925SBjoern A. Zeeb 			eht_rate_idx[j] = eht_rate_idx[j - 1] + max_rates[i] * nss;
6344aae7925SBjoern A. Zeeb 			++j;
6354aae7925SBjoern A. Zeeb 		}
6364aae7925SBjoern A. Zeeb 	}
6374aae7925SBjoern A. Zeeb 
6384aae7925SBjoern A. Zeeb 	for (i = 0; i < WMI_TPC_PREAM_MAX; i++) {
6394aae7925SBjoern A. Zeeb 		nss = (max_nss[i] < num_tx_chain ?
6404aae7925SBjoern A. Zeeb 		       max_nss[i] : num_tx_chain);
6414aae7925SBjoern A. Zeeb 		total_rates += max_rates[i] * nss;
6424aae7925SBjoern A. Zeeb 	}
6434aae7925SBjoern A. Zeeb 
6444aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
6454aae7925SBjoern A. Zeeb 			 "No.of rates-%d\n", total_rates);
6464aae7925SBjoern A. Zeeb 
6474aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
6484aae7925SBjoern A. Zeeb 			 "**************** %s ****************\n",
6494aae7925SBjoern A. Zeeb 			 type_str[type]);
6504aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
6514aae7925SBjoern A. Zeeb 			 "\t\t\t\tTPC values for Active chains\n");
6524aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
6534aae7925SBjoern A. Zeeb 			 "Rate idx Preamble Rate code");
6544aae7925SBjoern A. Zeeb 
6554aae7925SBjoern A. Zeeb 	for (i = 1; i <= active_tx_chains; ++i) {
6564aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
6574aae7925SBjoern A. Zeeb 				 "\t%d-Chain", i);
6584aae7925SBjoern A. Zeeb 	}
6594aae7925SBjoern A. Zeeb 
6604aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "\n");
6614aae7925SBjoern A. Zeeb 	for (i = pream_idx; i < WMI_TPC_PREAM_MAX; i++) {
6624aae7925SBjoern A. Zeeb 		if (chan_freq <= 2483) {
6634aae7925SBjoern A. Zeeb 			if (i == WMI_TPC_PREAM_VHT80 ||
6644aae7925SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_VHT160 ||
6654aae7925SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_HE80 ||
6664aae7925SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_HE160 ||
6674aae7925SBjoern A. Zeeb 			    (i >= WMI_TPC_PREAM_EHT60 &&
6684aae7925SBjoern A. Zeeb 			     i <= WMI_TPC_PREAM_EHT320)) {
6694aae7925SBjoern A. Zeeb 				max_rix += max_nss[i] * max_rates[i];
6704aae7925SBjoern A. Zeeb 				continue;
6714aae7925SBjoern A. Zeeb 			}
6724aae7925SBjoern A. Zeeb 		} else {
6734aae7925SBjoern A. Zeeb 			if (i == WMI_TPC_PREAM_CCK) {
6744aae7925SBjoern A. Zeeb 				max_rix += max_rates[i];
6754aae7925SBjoern A. Zeeb 				continue;
6764aae7925SBjoern A. Zeeb 			}
6774aae7925SBjoern A. Zeeb 		}
6784aae7925SBjoern A. Zeeb 
6794aae7925SBjoern A. Zeeb 		nss = (max_nss[i] < ar->num_tx_chains ? max_nss[i] : ar->num_tx_chains);
6804aae7925SBjoern A. Zeeb 
6814aae7925SBjoern A. Zeeb 		if (!(caps &
6824aae7925SBjoern A. Zeeb 		    (1 << ATH12K_TPC_STATS_SUPPORT_BE_PUNC))) {
6834aae7925SBjoern A. Zeeb 			if (i == WMI_TPC_PREAM_EHT60 || i == WMI_TPC_PREAM_EHT120 ||
6844aae7925SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_EHT140 || i == WMI_TPC_PREAM_EHT200 ||
6854aae7925SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_EHT240 || i == WMI_TPC_PREAM_EHT280) {
6864aae7925SBjoern A. Zeeb 				max_rix += max_nss[i] * max_rates[i];
6874aae7925SBjoern A. Zeeb 				continue;
6884aae7925SBjoern A. Zeeb 			}
6894aae7925SBjoern A. Zeeb 		}
6904aae7925SBjoern A. Zeeb 
6914aae7925SBjoern A. Zeeb 		len = ath12k_tpc_fill_pream(ar, buf, buf_len, len, i, max_rix, nss,
6924aae7925SBjoern A. Zeeb 					    max_rates[i], pream_type[i],
6934aae7925SBjoern A. Zeeb 					    type, rate_idx[i], eht_rate_idx[eht_idx]);
6944aae7925SBjoern A. Zeeb 
6954aae7925SBjoern A. Zeeb 		if (pream_type[i] == WMI_RATE_PREAMBLE_EHT)
6964aae7925SBjoern A. Zeeb 			/*For fetch the next index eht rates from rates array2*/
6974aae7925SBjoern A. Zeeb 			++eht_idx;
6984aae7925SBjoern A. Zeeb 
6994aae7925SBjoern A. Zeeb 		max_rix += max_nss[i] * max_rates[i];
7004aae7925SBjoern A. Zeeb 	}
7014aae7925SBjoern A. Zeeb 	return len;
7024aae7925SBjoern A. Zeeb }
7034aae7925SBjoern A. Zeeb 
ath12k_tpc_stats_fill(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,char * buf)7044aae7925SBjoern A. Zeeb static void ath12k_tpc_stats_fill(struct ath12k *ar,
7054aae7925SBjoern A. Zeeb 				  struct wmi_tpc_stats_arg *tpc_stats,
7064aae7925SBjoern A. Zeeb 				  char *buf)
7074aae7925SBjoern A. Zeeb {
7084aae7925SBjoern A. Zeeb 	size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
7094aae7925SBjoern A. Zeeb 	struct wmi_tpc_config_params *tpc;
7104aae7925SBjoern A. Zeeb 	size_t len = 0;
7114aae7925SBjoern A. Zeeb 
7124aae7925SBjoern A. Zeeb 	if (!tpc_stats) {
7134aae7925SBjoern A. Zeeb 		ath12k_warn(ar->ab, "failed to find tpc stats\n");
7144aae7925SBjoern A. Zeeb 		return;
7154aae7925SBjoern A. Zeeb 	}
7164aae7925SBjoern A. Zeeb 
7174aae7925SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
7184aae7925SBjoern A. Zeeb 
7194aae7925SBjoern A. Zeeb 	tpc = &tpc_stats->tpc_config;
7204aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "\n");
7214aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
7224aae7925SBjoern A. Zeeb 			 "*************** TPC config **************\n");
7234aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
7244aae7925SBjoern A. Zeeb 			 "* powers are in 0.25 dBm steps\n");
7254aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
7264aae7925SBjoern A. Zeeb 			 "reg domain-%d\t\tchan freq-%d\n",
7274aae7925SBjoern A. Zeeb 			 tpc->reg_domain, tpc->chan_freq);
7284aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
7294aae7925SBjoern A. Zeeb 			 "power limit-%d\t\tmax reg-domain Power-%d\n",
7304aae7925SBjoern A. Zeeb 			 le32_to_cpu(tpc->twice_max_reg_power) / 2, tpc->power_limit);
7314aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
7324aae7925SBjoern A. Zeeb 			 "No.of tx chain-%d\t",
7334aae7925SBjoern A. Zeeb 			 ar->num_tx_chains);
7344aae7925SBjoern A. Zeeb 
7354aae7925SBjoern A. Zeeb 	ath12k_tpc_stats_print(ar, tpc_stats, buf, len,
7364aae7925SBjoern A. Zeeb 			       ar->debug.tpc_stats_type);
7374aae7925SBjoern A. Zeeb 
7384aae7925SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
7394aae7925SBjoern A. Zeeb }
7404aae7925SBjoern A. Zeeb 
ath12k_open_tpc_stats(struct inode * inode,struct file * file)7414aae7925SBjoern A. Zeeb static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)
7424aae7925SBjoern A. Zeeb {
7434aae7925SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
7444aae7925SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
7454aae7925SBjoern A. Zeeb 	int ret;
7464aae7925SBjoern A. Zeeb 
7474aae7925SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
7484aae7925SBjoern A. Zeeb 
7494aae7925SBjoern A. Zeeb 	if (ah->state != ATH12K_HW_STATE_ON) {
7504aae7925SBjoern A. Zeeb 		ath12k_warn(ar->ab, "Interface not up\n");
7514aae7925SBjoern A. Zeeb 		return -ENETDOWN;
7524aae7925SBjoern A. Zeeb 	}
7534aae7925SBjoern A. Zeeb 
7544aae7925SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_TPC_STATS_BUF_SIZE, GFP_KERNEL);
7554aae7925SBjoern A. Zeeb 	if (!buf)
7564aae7925SBjoern A. Zeeb 		return -ENOMEM;
7574aae7925SBjoern A. Zeeb 
7584aae7925SBjoern A. Zeeb 	ret = ath12k_debug_tpc_stats_request(ar);
7594aae7925SBjoern A. Zeeb 	if (ret) {
7604aae7925SBjoern A. Zeeb 		ath12k_warn(ar->ab, "failed to request tpc stats: %d\n",
7614aae7925SBjoern A. Zeeb 			    ret);
7624aae7925SBjoern A. Zeeb 		return ret;
7634aae7925SBjoern A. Zeeb 	}
7644aae7925SBjoern A. Zeeb 
7654aae7925SBjoern A. Zeeb 	if (!wait_for_completion_timeout(&ar->debug.tpc_complete, TPC_STATS_WAIT_TIME)) {
7664aae7925SBjoern A. Zeeb 		spin_lock_bh(&ar->data_lock);
7674aae7925SBjoern A. Zeeb 		ath12k_wmi_free_tpc_stats_mem(ar);
7684aae7925SBjoern A. Zeeb 		ar->debug.tpc_request = false;
7694aae7925SBjoern A. Zeeb 		spin_unlock_bh(&ar->data_lock);
7704aae7925SBjoern A. Zeeb 		return -ETIMEDOUT;
7714aae7925SBjoern A. Zeeb 	}
7724aae7925SBjoern A. Zeeb 
7734aae7925SBjoern A. Zeeb 	ath12k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
7744aae7925SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
7754aae7925SBjoern A. Zeeb 
7764aae7925SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
7774aae7925SBjoern A. Zeeb 	ath12k_wmi_free_tpc_stats_mem(ar);
7784aae7925SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
7794aae7925SBjoern A. Zeeb 
7804aae7925SBjoern A. Zeeb 	return 0;
7814aae7925SBjoern A. Zeeb }
7824aae7925SBjoern A. Zeeb 
ath12k_read_tpc_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)7834aae7925SBjoern A. Zeeb static ssize_t ath12k_read_tpc_stats(struct file *file,
7844aae7925SBjoern A. Zeeb 				     char __user *user_buf,
7854aae7925SBjoern A. Zeeb 				     size_t count, loff_t *ppos)
7864aae7925SBjoern A. Zeeb {
7874aae7925SBjoern A. Zeeb 	const char *buf = file->private_data;
7884aae7925SBjoern A. Zeeb 	size_t len = strlen(buf);
7894aae7925SBjoern A. Zeeb 
7904aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
7914aae7925SBjoern A. Zeeb }
7924aae7925SBjoern A. Zeeb 
ath12k_release_tpc_stats(struct inode * inode,struct file * file)7934aae7925SBjoern A. Zeeb static int ath12k_release_tpc_stats(struct inode *inode,
7944aae7925SBjoern A. Zeeb 				    struct file *file)
7954aae7925SBjoern A. Zeeb {
7964aae7925SBjoern A. Zeeb 	kfree(file->private_data);
7974aae7925SBjoern A. Zeeb 	return 0;
7984aae7925SBjoern A. Zeeb }
7994aae7925SBjoern A. Zeeb 
8004aae7925SBjoern A. Zeeb static const struct file_operations fops_tpc_stats = {
8014aae7925SBjoern A. Zeeb 	.open = ath12k_open_tpc_stats,
8024aae7925SBjoern A. Zeeb 	.release = ath12k_release_tpc_stats,
8034aae7925SBjoern A. Zeeb 	.read = ath12k_read_tpc_stats,
8044aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
8054aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
8064aae7925SBjoern A. Zeeb };
8074aae7925SBjoern A. Zeeb 
8084aae7925SBjoern A. Zeeb static const struct file_operations fops_tpc_stats_type = {
8094aae7925SBjoern A. Zeeb 	.write = ath12k_write_tpc_stats_type,
8104aae7925SBjoern A. Zeeb 	.open = simple_open,
8114aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
8124aae7925SBjoern A. Zeeb };
8134aae7925SBjoern A. Zeeb 
ath12k_write_extd_rx_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)8144aae7925SBjoern A. Zeeb static ssize_t ath12k_write_extd_rx_stats(struct file *file,
8154aae7925SBjoern A. Zeeb 					  const char __user *ubuf,
8164aae7925SBjoern A. Zeeb 					  size_t count, loff_t *ppos)
8174aae7925SBjoern A. Zeeb {
8184aae7925SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
819fa442f39SBjoern A. Zeeb 	struct htt_rx_ring_tlv_filter tlv_filter = {};
8204aae7925SBjoern A. Zeeb 	u32 ring_id, rx_filter = 0;
8214aae7925SBjoern A. Zeeb 	bool enable;
8224aae7925SBjoern A. Zeeb 	int ret, i;
8234aae7925SBjoern A. Zeeb 
8244aae7925SBjoern A. Zeeb 	if (kstrtobool_from_user(ubuf, count, &enable))
8254aae7925SBjoern A. Zeeb 		return -EINVAL;
8264aae7925SBjoern A. Zeeb 
8274aae7925SBjoern A. Zeeb 	wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
8284aae7925SBjoern A. Zeeb 
8294aae7925SBjoern A. Zeeb 	if (!ar->ab->hw_params->rxdma1_enable) {
8304aae7925SBjoern A. Zeeb 		ret = count;
8314aae7925SBjoern A. Zeeb 		goto exit;
8324aae7925SBjoern A. Zeeb 	}
8334aae7925SBjoern A. Zeeb 
8344aae7925SBjoern A. Zeeb 	if (ar->ah->state != ATH12K_HW_STATE_ON) {
8354aae7925SBjoern A. Zeeb 		ret = -ENETDOWN;
8364aae7925SBjoern A. Zeeb 		goto exit;
8374aae7925SBjoern A. Zeeb 	}
8384aae7925SBjoern A. Zeeb 
8394aae7925SBjoern A. Zeeb 	if (enable == ar->debug.extd_rx_stats) {
8404aae7925SBjoern A. Zeeb 		ret = count;
8414aae7925SBjoern A. Zeeb 		goto exit;
8424aae7925SBjoern A. Zeeb 	}
8434aae7925SBjoern A. Zeeb 
8444aae7925SBjoern A. Zeeb 	if (enable) {
8454aae7925SBjoern A. Zeeb 		rx_filter =  HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
8464aae7925SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
8474aae7925SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
8484aae7925SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
8494aae7925SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
8504aae7925SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
8514aae7925SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START_USER_INFO;
8524aae7925SBjoern A. Zeeb 
8534aae7925SBjoern A. Zeeb 		tlv_filter.rx_filter = rx_filter;
8544aae7925SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
8554aae7925SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
8564aae7925SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
8574aae7925SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
8584aae7925SBjoern A. Zeeb 			HTT_RX_FP_DATA_FILTER_FLASG3;
8594aae7925SBjoern A. Zeeb 	} else {
8604aae7925SBjoern A. Zeeb 		tlv_filter = ath12k_mac_mon_status_filter_default;
8614aae7925SBjoern A. Zeeb 	}
8624aae7925SBjoern A. Zeeb 
8634aae7925SBjoern A. Zeeb 	ar->debug.rx_filter = tlv_filter.rx_filter;
8644aae7925SBjoern A. Zeeb 
8654aae7925SBjoern A. Zeeb 	for (i = 0; i < ar->ab->hw_params->num_rxdma_per_pdev; i++) {
8664aae7925SBjoern A. Zeeb 		ring_id = ar->dp.rxdma_mon_dst_ring[i].ring_id;
8674aae7925SBjoern A. Zeeb 		ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id + i,
8684aae7925SBjoern A. Zeeb 						       HAL_RXDMA_MONITOR_DST,
8694aae7925SBjoern A. Zeeb 						       DP_RXDMA_REFILL_RING_SIZE,
8704aae7925SBjoern A. Zeeb 						       &tlv_filter);
8714aae7925SBjoern A. Zeeb 		if (ret) {
8724aae7925SBjoern A. Zeeb 			ath12k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
8734aae7925SBjoern A. Zeeb 			goto exit;
8744aae7925SBjoern A. Zeeb 		}
8754aae7925SBjoern A. Zeeb 	}
8764aae7925SBjoern A. Zeeb 
8774aae7925SBjoern A. Zeeb 	ar->debug.extd_rx_stats = !!enable;
8784aae7925SBjoern A. Zeeb 	ret = count;
8794aae7925SBjoern A. Zeeb exit:
8804aae7925SBjoern A. Zeeb 	wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
8814aae7925SBjoern A. Zeeb 	return ret;
8824aae7925SBjoern A. Zeeb }
8834aae7925SBjoern A. Zeeb 
ath12k_read_extd_rx_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)8844aae7925SBjoern A. Zeeb static ssize_t ath12k_read_extd_rx_stats(struct file *file,
8854aae7925SBjoern A. Zeeb 					 char __user *ubuf,
8864aae7925SBjoern A. Zeeb 					 size_t count, loff_t *ppos)
8874aae7925SBjoern A. Zeeb {
8884aae7925SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
8894aae7925SBjoern A. Zeeb 	char buf[32];
8904aae7925SBjoern A. Zeeb 	int len = 0;
8914aae7925SBjoern A. Zeeb 
8924aae7925SBjoern A. Zeeb 	wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
8934aae7925SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
8944aae7925SBjoern A. Zeeb 			ar->debug.extd_rx_stats);
8954aae7925SBjoern A. Zeeb 	wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
8964aae7925SBjoern A. Zeeb 
8974aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
8984aae7925SBjoern A. Zeeb }
8994aae7925SBjoern A. Zeeb 
9004aae7925SBjoern A. Zeeb static const struct file_operations fops_extd_rx_stats = {
9014aae7925SBjoern A. Zeeb 	.read = ath12k_read_extd_rx_stats,
9024aae7925SBjoern A. Zeeb 	.write = ath12k_write_extd_rx_stats,
9034aae7925SBjoern A. Zeeb 	.open = simple_open,
9044aae7925SBjoern A. Zeeb };
9054aae7925SBjoern A. Zeeb 
ath12k_open_link_stats(struct inode * inode,struct file * file)9064aae7925SBjoern A. Zeeb static int ath12k_open_link_stats(struct inode *inode, struct file *file)
9074aae7925SBjoern A. Zeeb {
9084aae7925SBjoern A. Zeeb 	struct ath12k_vif *ahvif = inode->i_private;
9094aae7925SBjoern A. Zeeb 	size_t len = 0, buf_len = (PAGE_SIZE * 2);
9104aae7925SBjoern A. Zeeb 	struct ath12k_link_stats linkstat;
9114aae7925SBjoern A. Zeeb 	struct ath12k_link_vif *arvif;
9124aae7925SBjoern A. Zeeb 	unsigned long links_map;
9134aae7925SBjoern A. Zeeb 	struct wiphy *wiphy;
9144aae7925SBjoern A. Zeeb 	int link_id, i;
9154aae7925SBjoern A. Zeeb 	char *buf;
9164aae7925SBjoern A. Zeeb 
9174aae7925SBjoern A. Zeeb 	if (!ahvif)
9184aae7925SBjoern A. Zeeb 		return -EINVAL;
9194aae7925SBjoern A. Zeeb 
9204aae7925SBjoern A. Zeeb 	buf = kzalloc(buf_len, GFP_KERNEL);
9214aae7925SBjoern A. Zeeb 	if (!buf)
9224aae7925SBjoern A. Zeeb 		return -ENOMEM;
9234aae7925SBjoern A. Zeeb 
9244aae7925SBjoern A. Zeeb 	wiphy = ahvif->ah->hw->wiphy;
9254aae7925SBjoern A. Zeeb 	wiphy_lock(wiphy);
9264aae7925SBjoern A. Zeeb 
9274aae7925SBjoern A. Zeeb 	links_map = ahvif->links_map;
9284aae7925SBjoern A. Zeeb 	for_each_set_bit(link_id, &links_map,
9294aae7925SBjoern A. Zeeb 			 IEEE80211_MLD_MAX_NUM_LINKS) {
9304aae7925SBjoern A. Zeeb 		arvif = rcu_dereference_protected(ahvif->link[link_id],
9314aae7925SBjoern A. Zeeb 						  lockdep_is_held(&wiphy->mtx));
9324aae7925SBjoern A. Zeeb 
9334aae7925SBjoern A. Zeeb 		spin_lock_bh(&arvif->link_stats_lock);
9344aae7925SBjoern A. Zeeb 		linkstat = arvif->link_stats;
9354aae7925SBjoern A. Zeeb 		spin_unlock_bh(&arvif->link_stats_lock);
9364aae7925SBjoern A. Zeeb 
9374aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9384aae7925SBjoern A. Zeeb 				 "link[%d] Tx Unicast Frames Enqueued  = %d\n",
9394aae7925SBjoern A. Zeeb 				 link_id, linkstat.tx_enqueued);
9404aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9414aae7925SBjoern A. Zeeb 				 "link[%d] Tx Broadcast Frames Enqueued = %d\n",
9424aae7925SBjoern A. Zeeb 				 link_id, linkstat.tx_bcast_mcast);
9434aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9444aae7925SBjoern A. Zeeb 				 "link[%d] Tx Frames Completed = %d\n",
9454aae7925SBjoern A. Zeeb 				 link_id, linkstat.tx_completed);
9464aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9474aae7925SBjoern A. Zeeb 				 "link[%d] Tx Frames Dropped = %d\n",
9484aae7925SBjoern A. Zeeb 				 link_id, linkstat.tx_dropped);
9494aae7925SBjoern A. Zeeb 
9504aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9514aae7925SBjoern A. Zeeb 				 "link[%d] Tx Frame descriptor Encap Type = ",
9524aae7925SBjoern A. Zeeb 				 link_id);
9534aae7925SBjoern A. Zeeb 
9544aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9554aae7925SBjoern A. Zeeb 					 " raw:%d",
9564aae7925SBjoern A. Zeeb 					 linkstat.tx_encap_type[0]);
9574aae7925SBjoern A. Zeeb 
9584aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9594aae7925SBjoern A. Zeeb 					 " native_wifi:%d",
9604aae7925SBjoern A. Zeeb 					 linkstat.tx_encap_type[1]);
9614aae7925SBjoern A. Zeeb 
9624aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9634aae7925SBjoern A. Zeeb 					 " ethernet:%d",
9644aae7925SBjoern A. Zeeb 					 linkstat.tx_encap_type[2]);
9654aae7925SBjoern A. Zeeb 
9664aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9674aae7925SBjoern A. Zeeb 				 "\nlink[%d] Tx Frame descriptor Encrypt Type = ",
9684aae7925SBjoern A. Zeeb 				 link_id);
9694aae7925SBjoern A. Zeeb 
9704aae7925SBjoern A. Zeeb 		for (i = 0; i < HAL_ENCRYPT_TYPE_MAX; i++) {
9714aae7925SBjoern A. Zeeb 			len += scnprintf(buf + len, buf_len - len,
9724aae7925SBjoern A. Zeeb 					 " %d:%d", i,
9734aae7925SBjoern A. Zeeb 					 linkstat.tx_encrypt_type[i]);
9744aae7925SBjoern A. Zeeb 		}
9754aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9764aae7925SBjoern A. Zeeb 				 "\nlink[%d] Tx Frame descriptor Type = buffer:%d extension:%d\n",
9774aae7925SBjoern A. Zeeb 				 link_id, linkstat.tx_desc_type[0],
9784aae7925SBjoern A. Zeeb 				 linkstat.tx_desc_type[1]);
9794aae7925SBjoern A. Zeeb 
9804aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
9814aae7925SBjoern A. Zeeb 				"------------------------------------------------------\n");
9824aae7925SBjoern A. Zeeb 	}
9834aae7925SBjoern A. Zeeb 
9844aae7925SBjoern A. Zeeb 	wiphy_unlock(wiphy);
9854aae7925SBjoern A. Zeeb 
9864aae7925SBjoern A. Zeeb 	file->private_data = buf;
9874aae7925SBjoern A. Zeeb 
9884aae7925SBjoern A. Zeeb 	return 0;
9894aae7925SBjoern A. Zeeb }
9904aae7925SBjoern A. Zeeb 
ath12k_release_link_stats(struct inode * inode,struct file * file)9914aae7925SBjoern A. Zeeb static int ath12k_release_link_stats(struct inode *inode, struct file *file)
9924aae7925SBjoern A. Zeeb {
9934aae7925SBjoern A. Zeeb 	kfree(file->private_data);
9944aae7925SBjoern A. Zeeb 	return 0;
9954aae7925SBjoern A. Zeeb }
9964aae7925SBjoern A. Zeeb 
ath12k_read_link_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)9974aae7925SBjoern A. Zeeb static ssize_t ath12k_read_link_stats(struct file *file,
9984aae7925SBjoern A. Zeeb 				      char __user *user_buf,
9994aae7925SBjoern A. Zeeb 				      size_t count, loff_t *ppos)
10004aae7925SBjoern A. Zeeb {
10014aae7925SBjoern A. Zeeb 	const char *buf = file->private_data;
10024aae7925SBjoern A. Zeeb 	size_t len = strlen(buf);
10034aae7925SBjoern A. Zeeb 
10044aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
10054aae7925SBjoern A. Zeeb }
10064aae7925SBjoern A. Zeeb 
10074aae7925SBjoern A. Zeeb static const struct file_operations ath12k_fops_link_stats = {
10084aae7925SBjoern A. Zeeb 	.open = ath12k_open_link_stats,
10094aae7925SBjoern A. Zeeb 	.release = ath12k_release_link_stats,
10104aae7925SBjoern A. Zeeb 	.read = ath12k_read_link_stats,
10114aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
10124aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
10134aae7925SBjoern A. Zeeb };
10144aae7925SBjoern A. Zeeb 
ath12k_debugfs_op_vif_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif)10154aae7925SBjoern A. Zeeb void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
10164aae7925SBjoern A. Zeeb 			       struct ieee80211_vif *vif)
10174aae7925SBjoern A. Zeeb {
10184aae7925SBjoern A. Zeeb 	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
10194aae7925SBjoern A. Zeeb 
10204aae7925SBjoern A. Zeeb 	debugfs_create_file("link_stats", 0400, vif->debugfs_dir, ahvif,
10214aae7925SBjoern A. Zeeb 			    &ath12k_fops_link_stats);
10224aae7925SBjoern A. Zeeb }
10234aae7925SBjoern A. Zeeb 
ath12k_debugfs_dump_device_dp_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)10244aae7925SBjoern A. Zeeb static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
10254aae7925SBjoern A. Zeeb 						   char __user *user_buf,
10264aae7925SBjoern A. Zeeb 						   size_t count, loff_t *ppos)
10274aae7925SBjoern A. Zeeb {
10284aae7925SBjoern A. Zeeb 	struct ath12k_base *ab = file->private_data;
10294aae7925SBjoern A. Zeeb 	struct ath12k_device_dp_stats *device_stats = &ab->device_stats;
10304aae7925SBjoern A. Zeeb 	int len = 0, i, j, ret;
10314aae7925SBjoern A. Zeeb 	struct ath12k *ar;
10324aae7925SBjoern A. Zeeb 	const int size = 4096;
10334aae7925SBjoern A. Zeeb 	static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
10344aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR] = "Overflow",
10354aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR] = "MPDU len",
10364aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_FCS_ERR] = "FCS",
10374aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR] = "Decrypt",
10384aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR] = "TKIP MIC",
10394aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_UNECRYPTED_ERR] = "Unencrypt",
10404aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LEN_ERR] = "MSDU len",
10414aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LIMIT_ERR] = "MSDU limit",
10424aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_WIFI_PARSE_ERR] = "WiFi parse",
10434aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_PARSE_ERR] = "AMSDU parse",
10444aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_SA_TIMEOUT_ERR] = "SA timeout",
10454aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_DA_TIMEOUT_ERR] = "DA timeout",
10464aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_FLOW_TIMEOUT_ERR] = "Flow timeout",
10474aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR] = "Flush req",
10484aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_FRAG_ERR] = "AMSDU frag",
10494aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MULTICAST_ECHO_ERR] = "Multicast echo",
10504aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_MISMATCH_ERR] = "AMSDU mismatch",
10514aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR] = "Unauth WDS",
10524aae7925SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_GRPCAST_AMSDU_WDS_ERR] = "AMSDU or WDS"};
10534aae7925SBjoern A. Zeeb 
10544aae7925SBjoern A. Zeeb 	static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
10554aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO] = "Desc addr zero",
10564aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_DESC_INVALID] = "Desc inval",
10574aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_AMPDU_IN_NON_BA] =  "AMPDU in non BA",
10584aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_NON_BA_DUPLICATE] = "Non BA dup",
10594aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_BA_DUPLICATE] = "BA dup",
10604aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_FRAME_2K_JUMP] = "Frame 2k jump",
10614aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_BAR_2K_JUMP] = "BAR 2k jump",
10624aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_FRAME_OOR] = "Frame OOR",
10634aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_BAR_OOR] = "BAR OOR",
10644aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_NO_BA_SESSION] = "No BA session",
10654aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_FRAME_SN_EQUALS_SSN] = "Frame SN equal SSN",
10664aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED] = "PN check fail",
10674aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_2K_ERR_FLAG_SET] = "2k err",
10684aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET] = "PN err",
10694aae7925SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED] = "Desc blocked"};
10704aae7925SBjoern A. Zeeb 
10714aae7925SBjoern A. Zeeb 	static const char *wbm_rel_src[HAL_WBM_REL_SRC_MODULE_MAX] = {
10724aae7925SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_TQM] = "TQM",
10734aae7925SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_RXDMA] = "Rxdma",
10744aae7925SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_REO] = "Reo",
10754aae7925SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_FW] = "FW",
10764aae7925SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_SW] = "SW"};
10774aae7925SBjoern A. Zeeb 
10784aae7925SBjoern A. Zeeb 	char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
10794aae7925SBjoern A. Zeeb 
10804aae7925SBjoern A. Zeeb 	if (!buf)
10814aae7925SBjoern A. Zeeb 		return -ENOMEM;
10824aae7925SBjoern A. Zeeb 
10834aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "DEVICE RX STATS:\n\n");
10844aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
10854aae7925SBjoern A. Zeeb 			 device_stats->err_ring_pkts);
10864aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
10874aae7925SBjoern A. Zeeb 			 device_stats->invalid_rbm);
10884aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
10894aae7925SBjoern A. Zeeb 
10904aae7925SBjoern A. Zeeb 	for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
10914aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "%s: %u\n",
10924aae7925SBjoern A. Zeeb 				 rxdma_err[i], device_stats->rxdma_error[i]);
10934aae7925SBjoern A. Zeeb 
10944aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nREO errors:\n");
10954aae7925SBjoern A. Zeeb 
10964aae7925SBjoern A. Zeeb 	for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
10974aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "%s: %u\n",
10984aae7925SBjoern A. Zeeb 				 reo_err[i], device_stats->reo_error[i]);
10994aae7925SBjoern A. Zeeb 
11004aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
11014aae7925SBjoern A. Zeeb 
11024aae7925SBjoern A. Zeeb 	for (i = 0; i < DP_REO_DST_RING_MAX; i++)
11034aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len,
11044aae7925SBjoern A. Zeeb 				 "ring%d: %u\n", i,
11054aae7925SBjoern A. Zeeb 				 device_stats->hal_reo_error[i]);
11064aae7925SBjoern A. Zeeb 
11074aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nDEVICE TX STATS:\n");
11084aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
11094aae7925SBjoern A. Zeeb 
11104aae7925SBjoern A. Zeeb 	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
11114aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "ring%d: %u\n",
11124aae7925SBjoern A. Zeeb 				 i, device_stats->tx_err.desc_na[i]);
11134aae7925SBjoern A. Zeeb 
11144aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len,
11154aae7925SBjoern A. Zeeb 			 "\nMisc Transmit Failures: %d\n",
11164aae7925SBjoern A. Zeeb 			 atomic_read(&device_stats->tx_err.misc_fail));
11174aae7925SBjoern A. Zeeb 
11184aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntx_wbm_rel_source:");
11194aae7925SBjoern A. Zeeb 
11204aae7925SBjoern A. Zeeb 	for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++)
11214aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
11224aae7925SBjoern A. Zeeb 				 i, device_stats->tx_wbm_rel_source[i]);
11234aae7925SBjoern A. Zeeb 
11244aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
11254aae7925SBjoern A. Zeeb 
11264aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntqm_rel_reason:");
11274aae7925SBjoern A. Zeeb 
11284aae7925SBjoern A. Zeeb 	for (i = 0; i < MAX_TQM_RELEASE_REASON; i++)
11294aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
11304aae7925SBjoern A. Zeeb 				 i, device_stats->tqm_rel_reason[i]);
11314aae7925SBjoern A. Zeeb 
11324aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
11334aae7925SBjoern A. Zeeb 
11344aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nfw_tx_status:");
11354aae7925SBjoern A. Zeeb 
11364aae7925SBjoern A. Zeeb 	for (i = 0; i < MAX_FW_TX_STATUS; i++)
11374aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
11384aae7925SBjoern A. Zeeb 				 i, device_stats->fw_tx_status[i]);
11394aae7925SBjoern A. Zeeb 
11404aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
11414aae7925SBjoern A. Zeeb 
11424aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntx_enqueued:");
11434aae7925SBjoern A. Zeeb 
11444aae7925SBjoern A. Zeeb 	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
11454aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u", i,
11464aae7925SBjoern A. Zeeb 				 device_stats->tx_enqueued[i]);
11474aae7925SBjoern A. Zeeb 
11484aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
11494aae7925SBjoern A. Zeeb 
11504aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntx_completed:");
11514aae7925SBjoern A. Zeeb 
11524aae7925SBjoern A. Zeeb 	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
11534aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
11544aae7925SBjoern A. Zeeb 				 i, device_stats->tx_completed[i]);
11554aae7925SBjoern A. Zeeb 
11564aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
11574aae7925SBjoern A. Zeeb 
11584aae7925SBjoern A. Zeeb 	for (i = 0; i < ab->num_radios; i++) {
11594aae7925SBjoern A. Zeeb 		ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i));
11604aae7925SBjoern A. Zeeb 		if (ar) {
11614aae7925SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
11624aae7925SBjoern A. Zeeb 					"\nradio%d tx_pending: %u\n", i,
11634aae7925SBjoern A. Zeeb 					atomic_read(&ar->dp.num_tx_pending));
11644aae7925SBjoern A. Zeeb 		}
11654aae7925SBjoern A. Zeeb 	}
11664aae7925SBjoern A. Zeeb 
11674aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nREO Rx Received:\n");
11684aae7925SBjoern A. Zeeb 
11694aae7925SBjoern A. Zeeb 	for (i = 0; i < DP_REO_DST_RING_MAX; i++) {
11704aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "Ring%d:", i + 1);
11714aae7925SBjoern A. Zeeb 
11724aae7925SBjoern A. Zeeb 		for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
11734aae7925SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
11744aae7925SBjoern A. Zeeb 					"\t%d:%u", j,
11754aae7925SBjoern A. Zeeb 					 device_stats->reo_rx[i][j]);
11764aae7925SBjoern A. Zeeb 		}
11774aae7925SBjoern A. Zeeb 
11784aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "\n");
11794aae7925SBjoern A. Zeeb 	}
11804aae7925SBjoern A. Zeeb 
1181025f935eSBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nREO excep MSDU buf type:%u\n",
1182025f935eSBjoern A. Zeeb 			 device_stats->reo_excep_msdu_buf_type);
1183025f935eSBjoern A. Zeeb 
11844aae7925SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nRx WBM REL SRC Errors:\n");
11854aae7925SBjoern A. Zeeb 
11864aae7925SBjoern A. Zeeb 	for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++) {
11874aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "%s:", wbm_rel_src[i]);
11884aae7925SBjoern A. Zeeb 
11894aae7925SBjoern A. Zeeb 		for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
11904aae7925SBjoern A. Zeeb 			len += scnprintf(buf + len,
11914aae7925SBjoern A. Zeeb 					 size - len,
11924aae7925SBjoern A. Zeeb 					 "\t%d:%u", j,
11934aae7925SBjoern A. Zeeb 					 device_stats->rx_wbm_rel_source[i][j]);
11944aae7925SBjoern A. Zeeb 		}
11954aae7925SBjoern A. Zeeb 
11964aae7925SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "\n");
11974aae7925SBjoern A. Zeeb 	}
11984aae7925SBjoern A. Zeeb 
11994aae7925SBjoern A. Zeeb 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
12004aae7925SBjoern A. Zeeb 
12014aae7925SBjoern A. Zeeb 	return ret;
12024aae7925SBjoern A. Zeeb }
12034aae7925SBjoern A. Zeeb 
12044aae7925SBjoern A. Zeeb static const struct file_operations fops_device_dp_stats = {
12054aae7925SBjoern A. Zeeb 	.read = ath12k_debugfs_dump_device_dp_stats,
12064aae7925SBjoern A. Zeeb 	.open = simple_open,
12074aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
12084aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
12094aae7925SBjoern A. Zeeb };
12104aae7925SBjoern A. Zeeb 
ath12k_debugfs_pdev_create(struct ath12k_base * ab)12114aae7925SBjoern A. Zeeb void ath12k_debugfs_pdev_create(struct ath12k_base *ab)
12124aae7925SBjoern A. Zeeb {
12134aae7925SBjoern A. Zeeb 	debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
12144aae7925SBjoern A. Zeeb 			    &fops_simulate_fw_crash);
12154aae7925SBjoern A. Zeeb 
12164aae7925SBjoern A. Zeeb 	debugfs_create_file("device_dp_stats", 0400, ab->debugfs_soc, ab,
12174aae7925SBjoern A. Zeeb 			    &fops_device_dp_stats);
12184aae7925SBjoern A. Zeeb }
12194aae7925SBjoern A. Zeeb 
ath12k_debugfs_soc_create(struct ath12k_base * ab)122007b9f6ccSBjoern A. Zeeb void ath12k_debugfs_soc_create(struct ath12k_base *ab)
122107b9f6ccSBjoern A. Zeeb {
122207b9f6ccSBjoern A. Zeeb 	bool dput_needed;
1223fa442f39SBjoern A. Zeeb 	char soc_name[64] = {};
122407b9f6ccSBjoern A. Zeeb 	struct dentry *debugfs_ath12k;
122507b9f6ccSBjoern A. Zeeb 
122607b9f6ccSBjoern A. Zeeb 	debugfs_ath12k = debugfs_lookup("ath12k", NULL);
122707b9f6ccSBjoern A. Zeeb 	if (debugfs_ath12k) {
122807b9f6ccSBjoern A. Zeeb 		/* a dentry from lookup() needs dput() after we don't use it */
122907b9f6ccSBjoern A. Zeeb 		dput_needed = true;
123007b9f6ccSBjoern A. Zeeb 	} else {
123107b9f6ccSBjoern A. Zeeb 		debugfs_ath12k = debugfs_create_dir("ath12k", NULL);
123207b9f6ccSBjoern A. Zeeb 		if (IS_ERR_OR_NULL(debugfs_ath12k))
123307b9f6ccSBjoern A. Zeeb 			return;
123407b9f6ccSBjoern A. Zeeb 		dput_needed = false;
123507b9f6ccSBjoern A. Zeeb 	}
123607b9f6ccSBjoern A. Zeeb 
123707b9f6ccSBjoern A. Zeeb 	scnprintf(soc_name, sizeof(soc_name), "%s-%s", ath12k_bus_str(ab->hif.bus),
123807b9f6ccSBjoern A. Zeeb 		  dev_name(ab->dev));
123907b9f6ccSBjoern A. Zeeb 
124007b9f6ccSBjoern A. Zeeb 	ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath12k);
124107b9f6ccSBjoern A. Zeeb 
124207b9f6ccSBjoern A. Zeeb 	if (dput_needed)
124307b9f6ccSBjoern A. Zeeb 		dput(debugfs_ath12k);
124407b9f6ccSBjoern A. Zeeb }
124507b9f6ccSBjoern A. Zeeb 
ath12k_debugfs_soc_destroy(struct ath12k_base * ab)124607b9f6ccSBjoern A. Zeeb void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
124707b9f6ccSBjoern A. Zeeb {
124807b9f6ccSBjoern A. Zeeb 	debugfs_remove_recursive(ab->debugfs_soc);
124907b9f6ccSBjoern A. Zeeb 	ab->debugfs_soc = NULL;
125007b9f6ccSBjoern A. Zeeb 	/* We are not removing ath12k directory on purpose, even if it
125107b9f6ccSBjoern A. Zeeb 	 * would be empty. This simplifies the directory handling and it's
125207b9f6ccSBjoern A. Zeeb 	 * a minor cosmetic issue to leave an empty ath12k directory to
125307b9f6ccSBjoern A. Zeeb 	 * debugfs.
125407b9f6ccSBjoern A. Zeeb 	 */
125507b9f6ccSBjoern A. Zeeb }
125607b9f6ccSBjoern A. Zeeb 
ath12k_open_vdev_stats(struct inode * inode,struct file * file)12574aae7925SBjoern A. Zeeb static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
12584aae7925SBjoern A. Zeeb {
12594aae7925SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
12604aae7925SBjoern A. Zeeb 	struct ath12k_fw_stats_req_params param;
12614aae7925SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
12624aae7925SBjoern A. Zeeb 	int ret;
12634aae7925SBjoern A. Zeeb 
12644aae7925SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
12654aae7925SBjoern A. Zeeb 
12664aae7925SBjoern A. Zeeb 	if (!ah)
12674aae7925SBjoern A. Zeeb 		return -ENETDOWN;
12684aae7925SBjoern A. Zeeb 
12694aae7925SBjoern A. Zeeb 	if (ah->state != ATH12K_HW_STATE_ON)
12704aae7925SBjoern A. Zeeb 		return -ENETDOWN;
12714aae7925SBjoern A. Zeeb 
12724aae7925SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
12734aae7925SBjoern A. Zeeb 	if (!buf)
12744aae7925SBjoern A. Zeeb 		return -ENOMEM;
12754aae7925SBjoern A. Zeeb 
12764aae7925SBjoern A. Zeeb 	param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
12774aae7925SBjoern A. Zeeb 	/* VDEV stats is always sent for all active VDEVs from FW */
12784aae7925SBjoern A. Zeeb 	param.vdev_id = 0;
12794aae7925SBjoern A. Zeeb 	param.stats_id = WMI_REQUEST_VDEV_STAT;
12804aae7925SBjoern A. Zeeb 
12814aae7925SBjoern A. Zeeb 	ret = ath12k_mac_get_fw_stats(ar, &param);
12824aae7925SBjoern A. Zeeb 	if (ret) {
12834aae7925SBjoern A. Zeeb 		ath12k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
12844aae7925SBjoern A. Zeeb 		return ret;
12854aae7925SBjoern A. Zeeb 	}
12864aae7925SBjoern A. Zeeb 
12874aae7925SBjoern A. Zeeb 	ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
12884aae7925SBjoern A. Zeeb 				 buf);
1289025f935eSBjoern A. Zeeb 	ath12k_fw_stats_reset(ar);
12904aae7925SBjoern A. Zeeb 
12914aae7925SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
12924aae7925SBjoern A. Zeeb 
12934aae7925SBjoern A. Zeeb 	return 0;
12944aae7925SBjoern A. Zeeb }
12954aae7925SBjoern A. Zeeb 
ath12k_release_vdev_stats(struct inode * inode,struct file * file)12964aae7925SBjoern A. Zeeb static int ath12k_release_vdev_stats(struct inode *inode, struct file *file)
12974aae7925SBjoern A. Zeeb {
12984aae7925SBjoern A. Zeeb 	kfree(file->private_data);
12994aae7925SBjoern A. Zeeb 
13004aae7925SBjoern A. Zeeb 	return 0;
13014aae7925SBjoern A. Zeeb }
13024aae7925SBjoern A. Zeeb 
ath12k_read_vdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)13034aae7925SBjoern A. Zeeb static ssize_t ath12k_read_vdev_stats(struct file *file,
13044aae7925SBjoern A. Zeeb 				      char __user *user_buf,
13054aae7925SBjoern A. Zeeb 				      size_t count, loff_t *ppos)
13064aae7925SBjoern A. Zeeb {
13074aae7925SBjoern A. Zeeb 	const char *buf = file->private_data;
13084aae7925SBjoern A. Zeeb 	size_t len = strlen(buf);
13094aae7925SBjoern A. Zeeb 
13104aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
13114aae7925SBjoern A. Zeeb }
13124aae7925SBjoern A. Zeeb 
13134aae7925SBjoern A. Zeeb static const struct file_operations fops_vdev_stats = {
13144aae7925SBjoern A. Zeeb 	.open = ath12k_open_vdev_stats,
13154aae7925SBjoern A. Zeeb 	.release = ath12k_release_vdev_stats,
13164aae7925SBjoern A. Zeeb 	.read = ath12k_read_vdev_stats,
13174aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
13184aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
13194aae7925SBjoern A. Zeeb };
13204aae7925SBjoern A. Zeeb 
ath12k_open_bcn_stats(struct inode * inode,struct file * file)13214aae7925SBjoern A. Zeeb static int ath12k_open_bcn_stats(struct inode *inode, struct file *file)
13224aae7925SBjoern A. Zeeb {
13234aae7925SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
13244aae7925SBjoern A. Zeeb 	struct ath12k_link_vif *arvif;
13254aae7925SBjoern A. Zeeb 	struct ath12k_fw_stats_req_params param;
13264aae7925SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
13274aae7925SBjoern A. Zeeb 	int ret;
13284aae7925SBjoern A. Zeeb 
13294aae7925SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
13304aae7925SBjoern A. Zeeb 
13314aae7925SBjoern A. Zeeb 	if (ah && ah->state != ATH12K_HW_STATE_ON)
13324aae7925SBjoern A. Zeeb 		return -ENETDOWN;
13334aae7925SBjoern A. Zeeb 
13344aae7925SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
13354aae7925SBjoern A. Zeeb 	if (!buf)
13364aae7925SBjoern A. Zeeb 		return -ENOMEM;
13374aae7925SBjoern A. Zeeb 
13384aae7925SBjoern A. Zeeb 	param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
13394aae7925SBjoern A. Zeeb 	param.stats_id = WMI_REQUEST_BCN_STAT;
13404aae7925SBjoern A. Zeeb 
13414aae7925SBjoern A. Zeeb 	/* loop all active VDEVs for bcn stats */
13424aae7925SBjoern A. Zeeb 	list_for_each_entry(arvif, &ar->arvifs, list) {
13434aae7925SBjoern A. Zeeb 		if (!arvif->is_up)
13444aae7925SBjoern A. Zeeb 			continue;
13454aae7925SBjoern A. Zeeb 
13464aae7925SBjoern A. Zeeb 		param.vdev_id = arvif->vdev_id;
13474aae7925SBjoern A. Zeeb 		ret = ath12k_mac_get_fw_stats(ar, &param);
13484aae7925SBjoern A. Zeeb 		if (ret) {
13494aae7925SBjoern A. Zeeb 			ath12k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
13504aae7925SBjoern A. Zeeb 			return ret;
13514aae7925SBjoern A. Zeeb 		}
13524aae7925SBjoern A. Zeeb 	}
13534aae7925SBjoern A. Zeeb 
13544aae7925SBjoern A. Zeeb 	ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
13554aae7925SBjoern A. Zeeb 				 buf);
1356025f935eSBjoern A. Zeeb 	ath12k_fw_stats_reset(ar);
13574aae7925SBjoern A. Zeeb 
13584aae7925SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
13594aae7925SBjoern A. Zeeb 
13604aae7925SBjoern A. Zeeb 	return 0;
13614aae7925SBjoern A. Zeeb }
13624aae7925SBjoern A. Zeeb 
ath12k_release_bcn_stats(struct inode * inode,struct file * file)13634aae7925SBjoern A. Zeeb static int ath12k_release_bcn_stats(struct inode *inode, struct file *file)
13644aae7925SBjoern A. Zeeb {
13654aae7925SBjoern A. Zeeb 	kfree(file->private_data);
13664aae7925SBjoern A. Zeeb 
13674aae7925SBjoern A. Zeeb 	return 0;
13684aae7925SBjoern A. Zeeb }
13694aae7925SBjoern A. Zeeb 
ath12k_read_bcn_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)13704aae7925SBjoern A. Zeeb static ssize_t ath12k_read_bcn_stats(struct file *file,
13714aae7925SBjoern A. Zeeb 				     char __user *user_buf,
13724aae7925SBjoern A. Zeeb 				     size_t count, loff_t *ppos)
13734aae7925SBjoern A. Zeeb {
13744aae7925SBjoern A. Zeeb 	const char *buf = file->private_data;
13754aae7925SBjoern A. Zeeb 	size_t len = strlen(buf);
13764aae7925SBjoern A. Zeeb 
13774aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
13784aae7925SBjoern A. Zeeb }
13794aae7925SBjoern A. Zeeb 
13804aae7925SBjoern A. Zeeb static const struct file_operations fops_bcn_stats = {
13814aae7925SBjoern A. Zeeb 	.open = ath12k_open_bcn_stats,
13824aae7925SBjoern A. Zeeb 	.release = ath12k_release_bcn_stats,
13834aae7925SBjoern A. Zeeb 	.read = ath12k_read_bcn_stats,
13844aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
13854aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
13864aae7925SBjoern A. Zeeb };
13874aae7925SBjoern A. Zeeb 
ath12k_open_pdev_stats(struct inode * inode,struct file * file)13884aae7925SBjoern A. Zeeb static int ath12k_open_pdev_stats(struct inode *inode, struct file *file)
13894aae7925SBjoern A. Zeeb {
13904aae7925SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
13914aae7925SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
13924aae7925SBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
13934aae7925SBjoern A. Zeeb 	struct ath12k_fw_stats_req_params param;
13944aae7925SBjoern A. Zeeb 	int ret;
13954aae7925SBjoern A. Zeeb 
13964aae7925SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
13974aae7925SBjoern A. Zeeb 
13984aae7925SBjoern A. Zeeb 	if (ah && ah->state != ATH12K_HW_STATE_ON)
13994aae7925SBjoern A. Zeeb 		return -ENETDOWN;
14004aae7925SBjoern A. Zeeb 
14014aae7925SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
14024aae7925SBjoern A. Zeeb 	if (!buf)
14034aae7925SBjoern A. Zeeb 		return -ENOMEM;
14044aae7925SBjoern A. Zeeb 
14054aae7925SBjoern A. Zeeb 	param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
14064aae7925SBjoern A. Zeeb 	param.vdev_id = 0;
14074aae7925SBjoern A. Zeeb 	param.stats_id = WMI_REQUEST_PDEV_STAT;
14084aae7925SBjoern A. Zeeb 
14094aae7925SBjoern A. Zeeb 	ret = ath12k_mac_get_fw_stats(ar, &param);
14104aae7925SBjoern A. Zeeb 	if (ret) {
14114aae7925SBjoern A. Zeeb 		ath12k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
14124aae7925SBjoern A. Zeeb 		return ret;
14134aae7925SBjoern A. Zeeb 	}
14144aae7925SBjoern A. Zeeb 
14154aae7925SBjoern A. Zeeb 	ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
14164aae7925SBjoern A. Zeeb 				 buf);
1417025f935eSBjoern A. Zeeb 	ath12k_fw_stats_reset(ar);
14184aae7925SBjoern A. Zeeb 
14194aae7925SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
14204aae7925SBjoern A. Zeeb 
14214aae7925SBjoern A. Zeeb 	return 0;
14224aae7925SBjoern A. Zeeb }
14234aae7925SBjoern A. Zeeb 
ath12k_release_pdev_stats(struct inode * inode,struct file * file)14244aae7925SBjoern A. Zeeb static int ath12k_release_pdev_stats(struct inode *inode, struct file *file)
14254aae7925SBjoern A. Zeeb {
14264aae7925SBjoern A. Zeeb 	kfree(file->private_data);
14274aae7925SBjoern A. Zeeb 
14284aae7925SBjoern A. Zeeb 	return 0;
14294aae7925SBjoern A. Zeeb }
14304aae7925SBjoern A. Zeeb 
ath12k_read_pdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)14314aae7925SBjoern A. Zeeb static ssize_t ath12k_read_pdev_stats(struct file *file,
14324aae7925SBjoern A. Zeeb 				      char __user *user_buf,
14334aae7925SBjoern A. Zeeb 				      size_t count, loff_t *ppos)
14344aae7925SBjoern A. Zeeb {
14354aae7925SBjoern A. Zeeb 	const char *buf = file->private_data;
14364aae7925SBjoern A. Zeeb 	size_t len = strlen(buf);
14374aae7925SBjoern A. Zeeb 
14384aae7925SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
14394aae7925SBjoern A. Zeeb }
14404aae7925SBjoern A. Zeeb 
14414aae7925SBjoern A. Zeeb static const struct file_operations fops_pdev_stats = {
14424aae7925SBjoern A. Zeeb 	.open = ath12k_open_pdev_stats,
14434aae7925SBjoern A. Zeeb 	.release = ath12k_release_pdev_stats,
14444aae7925SBjoern A. Zeeb 	.read = ath12k_read_pdev_stats,
14454aae7925SBjoern A. Zeeb 	.owner = THIS_MODULE,
14464aae7925SBjoern A. Zeeb 	.llseek = default_llseek,
14474aae7925SBjoern A. Zeeb };
14484aae7925SBjoern A. Zeeb 
14494aae7925SBjoern A. Zeeb static
ath12k_debugfs_fw_stats_register(struct ath12k * ar)14504aae7925SBjoern A. Zeeb void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
14514aae7925SBjoern A. Zeeb {
14524aae7925SBjoern A. Zeeb 	struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
14534aae7925SBjoern A. Zeeb 							ar->debug.debugfs_pdev);
14544aae7925SBjoern A. Zeeb 
14554aae7925SBjoern A. Zeeb 	/* all stats debugfs files created are under "fw_stats" directory
14564aae7925SBjoern A. Zeeb 	 * created per PDEV
14574aae7925SBjoern A. Zeeb 	 */
14584aae7925SBjoern A. Zeeb 	debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
14594aae7925SBjoern A. Zeeb 			    &fops_vdev_stats);
14604aae7925SBjoern A. Zeeb 	debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
14614aae7925SBjoern A. Zeeb 			    &fops_bcn_stats);
14624aae7925SBjoern A. Zeeb 	debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
14634aae7925SBjoern A. Zeeb 			    &fops_pdev_stats);
14644aae7925SBjoern A. Zeeb 
14654aae7925SBjoern A. Zeeb 	ath12k_fw_stats_init(ar);
14664aae7925SBjoern A. Zeeb }
14674aae7925SBjoern A. Zeeb 
ath12k_debugfs_register(struct ath12k * ar)146807b9f6ccSBjoern A. Zeeb void ath12k_debugfs_register(struct ath12k *ar)
146907b9f6ccSBjoern A. Zeeb {
147007b9f6ccSBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
147107b9f6ccSBjoern A. Zeeb 	struct ieee80211_hw *hw = ar->ah->hw;
147207b9f6ccSBjoern A. Zeeb 	char pdev_name[5];
1473fa442f39SBjoern A. Zeeb 	char buf[100] = {};
147407b9f6ccSBjoern A. Zeeb 
147507b9f6ccSBjoern A. Zeeb 	scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
147607b9f6ccSBjoern A. Zeeb 
147707b9f6ccSBjoern A. Zeeb 	ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
147807b9f6ccSBjoern A. Zeeb 
147907b9f6ccSBjoern A. Zeeb 	/* Create a symlink under ieee80211/phy* */
148007b9f6ccSBjoern A. Zeeb 	scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev);
148107b9f6ccSBjoern A. Zeeb 	ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k",
148207b9f6ccSBjoern A. Zeeb 								hw->wiphy->debugfsdir,
148307b9f6ccSBjoern A. Zeeb 								buf);
148407b9f6ccSBjoern A. Zeeb 
148507b9f6ccSBjoern A. Zeeb 	if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) {
148607b9f6ccSBjoern A. Zeeb 		debugfs_create_file("dfs_simulate_radar", 0200,
148707b9f6ccSBjoern A. Zeeb 				    ar->debug.debugfs_pdev, ar,
148807b9f6ccSBjoern A. Zeeb 				    &fops_simulate_radar);
148907b9f6ccSBjoern A. Zeeb 	}
149007b9f6ccSBjoern A. Zeeb 
14914aae7925SBjoern A. Zeeb 	debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_pdev, ar,
14924aae7925SBjoern A. Zeeb 			    &fops_tpc_stats);
14934aae7925SBjoern A. Zeeb 	debugfs_create_file("tpc_stats_type", 0200, ar->debug.debugfs_pdev,
14944aae7925SBjoern A. Zeeb 			    ar, &fops_tpc_stats_type);
14954aae7925SBjoern A. Zeeb 	init_completion(&ar->debug.tpc_complete);
14964aae7925SBjoern A. Zeeb 
149707b9f6ccSBjoern A. Zeeb 	ath12k_debugfs_htt_stats_register(ar);
14984aae7925SBjoern A. Zeeb 	ath12k_debugfs_fw_stats_register(ar);
14994aae7925SBjoern A. Zeeb 
15004aae7925SBjoern A. Zeeb 	debugfs_create_file("ext_rx_stats", 0644,
15014aae7925SBjoern A. Zeeb 			    ar->debug.debugfs_pdev, ar,
15024aae7925SBjoern A. Zeeb 			    &fops_extd_rx_stats);
150307b9f6ccSBjoern A. Zeeb }
150407b9f6ccSBjoern A. Zeeb 
ath12k_debugfs_unregister(struct ath12k * ar)150507b9f6ccSBjoern A. Zeeb void ath12k_debugfs_unregister(struct ath12k *ar)
150607b9f6ccSBjoern A. Zeeb {
150707b9f6ccSBjoern A. Zeeb 	if (!ar->debug.debugfs_pdev)
150807b9f6ccSBjoern A. Zeeb 		return;
150907b9f6ccSBjoern A. Zeeb 
151007b9f6ccSBjoern A. Zeeb 	/* Remove symlink under ieee80211/phy* */
151107b9f6ccSBjoern A. Zeeb 	debugfs_remove(ar->debug.debugfs_pdev_symlink);
151207b9f6ccSBjoern A. Zeeb 	debugfs_remove_recursive(ar->debug.debugfs_pdev);
151307b9f6ccSBjoern A. Zeeb 	ar->debug.debugfs_pdev_symlink = NULL;
151407b9f6ccSBjoern A. Zeeb 	ar->debug.debugfs_pdev = NULL;
151507b9f6ccSBjoern A. Zeeb }
1516