xref: /freebsd/sys/contrib/dev/athk/ath12k/debugfs.c (revision a96550206e4bde15bf615ff2127b80404a7ec41f)
1*a9655020SBjoern A. Zeeb // SPDX-License-Identifier: BSD-3-Clause-Clear
2*a9655020SBjoern A. Zeeb /*
3*a9655020SBjoern A. Zeeb  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
4*a9655020SBjoern A. Zeeb  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5*a9655020SBjoern A. Zeeb  */
6*a9655020SBjoern A. Zeeb 
7*a9655020SBjoern A. Zeeb #include "core.h"
8*a9655020SBjoern A. Zeeb #include "dp_tx.h"
9*a9655020SBjoern A. Zeeb #include "debug.h"
10*a9655020SBjoern A. Zeeb #include "debugfs.h"
11*a9655020SBjoern A. Zeeb #include "debugfs_htt_stats.h"
12*a9655020SBjoern A. Zeeb 
ath12k_write_simulate_radar(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)13*a9655020SBjoern A. Zeeb static ssize_t ath12k_write_simulate_radar(struct file *file,
14*a9655020SBjoern A. Zeeb 					   const char __user *user_buf,
15*a9655020SBjoern A. Zeeb 					   size_t count, loff_t *ppos)
16*a9655020SBjoern A. Zeeb {
17*a9655020SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
18*a9655020SBjoern A. Zeeb 	int ret;
19*a9655020SBjoern A. Zeeb 
20*a9655020SBjoern A. Zeeb 	wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
21*a9655020SBjoern A. Zeeb 	ret = ath12k_wmi_simulate_radar(ar);
22*a9655020SBjoern A. Zeeb 	if (ret)
23*a9655020SBjoern A. Zeeb 		goto exit;
24*a9655020SBjoern A. Zeeb 
25*a9655020SBjoern A. Zeeb 	ret = count;
26*a9655020SBjoern A. Zeeb exit:
27*a9655020SBjoern A. Zeeb 	wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
28*a9655020SBjoern A. Zeeb 	return ret;
29*a9655020SBjoern A. Zeeb }
30*a9655020SBjoern A. Zeeb 
31*a9655020SBjoern A. Zeeb static const struct file_operations fops_simulate_radar = {
32*a9655020SBjoern A. Zeeb 	.write = ath12k_write_simulate_radar,
33*a9655020SBjoern A. Zeeb 	.open = simple_open
34*a9655020SBjoern A. Zeeb };
35*a9655020SBjoern A. Zeeb 
ath12k_read_simulate_fw_crash(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)36*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_simulate_fw_crash(struct file *file,
37*a9655020SBjoern A. Zeeb 					     char __user *user_buf,
38*a9655020SBjoern A. Zeeb 					     size_t count, loff_t *ppos)
39*a9655020SBjoern A. Zeeb {
40*a9655020SBjoern A. Zeeb 	const char buf[] =
41*a9655020SBjoern A. Zeeb 		"To simulate firmware crash write one of the keywords to this file:\n"
42*a9655020SBjoern A. Zeeb 		"`assert` - send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n";
43*a9655020SBjoern A. Zeeb 
44*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
45*a9655020SBjoern A. Zeeb }
46*a9655020SBjoern A. Zeeb 
47*a9655020SBjoern A. Zeeb static ssize_t
ath12k_write_simulate_fw_crash(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)48*a9655020SBjoern A. Zeeb ath12k_write_simulate_fw_crash(struct file *file,
49*a9655020SBjoern A. Zeeb 			       const char __user *user_buf,
50*a9655020SBjoern A. Zeeb 			       size_t count, loff_t *ppos)
51*a9655020SBjoern A. Zeeb {
52*a9655020SBjoern A. Zeeb 	struct ath12k_base *ab = file->private_data;
53*a9655020SBjoern A. Zeeb 	struct ath12k_pdev *pdev;
54*a9655020SBjoern A. Zeeb 	struct ath12k *ar = NULL;
55*a9655020SBjoern A. Zeeb 	char buf[32] = {};
56*a9655020SBjoern A. Zeeb 	int i, ret;
57*a9655020SBjoern A. Zeeb 	ssize_t rc;
58*a9655020SBjoern A. Zeeb 
59*a9655020SBjoern A. Zeeb 	/* filter partial writes and invalid commands */
60*a9655020SBjoern A. Zeeb 	if (*ppos != 0 || count >= sizeof(buf) || count == 0)
61*a9655020SBjoern A. Zeeb 		return -EINVAL;
62*a9655020SBjoern A. Zeeb 
63*a9655020SBjoern A. Zeeb 	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
64*a9655020SBjoern A. Zeeb 	if (rc < 0)
65*a9655020SBjoern A. Zeeb 		return rc;
66*a9655020SBjoern A. Zeeb 
67*a9655020SBjoern A. Zeeb 	/* drop the possible '\n' from the end */
68*a9655020SBjoern A. Zeeb 	if (buf[*ppos - 1] == '\n')
69*a9655020SBjoern A. Zeeb 		buf[*ppos - 1] = '\0';
70*a9655020SBjoern A. Zeeb 
71*a9655020SBjoern A. Zeeb 	for (i = 0; i < ab->num_radios; i++) {
72*a9655020SBjoern A. Zeeb 		pdev = &ab->pdevs[i];
73*a9655020SBjoern A. Zeeb 		ar = pdev->ar;
74*a9655020SBjoern A. Zeeb 		if (ar)
75*a9655020SBjoern A. Zeeb 			break;
76*a9655020SBjoern A. Zeeb 	}
77*a9655020SBjoern A. Zeeb 
78*a9655020SBjoern A. Zeeb 	if (!ar)
79*a9655020SBjoern A. Zeeb 		return -ENETDOWN;
80*a9655020SBjoern A. Zeeb 
81*a9655020SBjoern A. Zeeb 	if (!strcmp(buf, "assert")) {
82*a9655020SBjoern A. Zeeb 		ath12k_info(ab, "simulating firmware assert crash\n");
83*a9655020SBjoern A. Zeeb 		ret = ath12k_wmi_force_fw_hang_cmd(ar,
84*a9655020SBjoern A. Zeeb 						   ATH12K_WMI_FW_HANG_ASSERT_TYPE,
85*a9655020SBjoern A. Zeeb 						   ATH12K_WMI_FW_HANG_DELAY);
86*a9655020SBjoern A. Zeeb 	} else {
87*a9655020SBjoern A. Zeeb 		return -EINVAL;
88*a9655020SBjoern A. Zeeb 	}
89*a9655020SBjoern A. Zeeb 
90*a9655020SBjoern A. Zeeb 	if (ret) {
91*a9655020SBjoern A. Zeeb 		ath12k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
92*a9655020SBjoern A. Zeeb 		return ret;
93*a9655020SBjoern A. Zeeb 	}
94*a9655020SBjoern A. Zeeb 
95*a9655020SBjoern A. Zeeb 	return count;
96*a9655020SBjoern A. Zeeb }
97*a9655020SBjoern A. Zeeb 
98*a9655020SBjoern A. Zeeb static const struct file_operations fops_simulate_fw_crash = {
99*a9655020SBjoern A. Zeeb 	.read = ath12k_read_simulate_fw_crash,
100*a9655020SBjoern A. Zeeb 	.write = ath12k_write_simulate_fw_crash,
101*a9655020SBjoern A. Zeeb 	.open = simple_open,
102*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
103*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
104*a9655020SBjoern A. Zeeb };
105*a9655020SBjoern A. Zeeb 
ath12k_write_tpc_stats_type(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)106*a9655020SBjoern A. Zeeb static ssize_t ath12k_write_tpc_stats_type(struct file *file,
107*a9655020SBjoern A. Zeeb 					   const char __user *user_buf,
108*a9655020SBjoern A. Zeeb 					   size_t count, loff_t *ppos)
109*a9655020SBjoern A. Zeeb {
110*a9655020SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
111*a9655020SBjoern A. Zeeb 	u8 type;
112*a9655020SBjoern A. Zeeb 	int ret;
113*a9655020SBjoern A. Zeeb 
114*a9655020SBjoern A. Zeeb 	ret = kstrtou8_from_user(user_buf, count, 0, &type);
115*a9655020SBjoern A. Zeeb 	if (ret)
116*a9655020SBjoern A. Zeeb 		return ret;
117*a9655020SBjoern A. Zeeb 
118*a9655020SBjoern A. Zeeb 	if (type >= WMI_HALPHY_PDEV_TX_STATS_MAX)
119*a9655020SBjoern A. Zeeb 		return -EINVAL;
120*a9655020SBjoern A. Zeeb 
121*a9655020SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
122*a9655020SBjoern A. Zeeb 	ar->debug.tpc_stats_type = type;
123*a9655020SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
124*a9655020SBjoern A. Zeeb 
125*a9655020SBjoern A. Zeeb 	return count;
126*a9655020SBjoern A. Zeeb }
127*a9655020SBjoern A. Zeeb 
ath12k_debug_tpc_stats_request(struct ath12k * ar)128*a9655020SBjoern A. Zeeb static int ath12k_debug_tpc_stats_request(struct ath12k *ar)
129*a9655020SBjoern A. Zeeb {
130*a9655020SBjoern A. Zeeb 	enum wmi_halphy_ctrl_path_stats_id tpc_stats_sub_id;
131*a9655020SBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
132*a9655020SBjoern A. Zeeb 	int ret;
133*a9655020SBjoern A. Zeeb 
134*a9655020SBjoern A. Zeeb 	lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
135*a9655020SBjoern A. Zeeb 
136*a9655020SBjoern A. Zeeb 	reinit_completion(&ar->debug.tpc_complete);
137*a9655020SBjoern A. Zeeb 
138*a9655020SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
139*a9655020SBjoern A. Zeeb 	ar->debug.tpc_request = true;
140*a9655020SBjoern A. Zeeb 	tpc_stats_sub_id = ar->debug.tpc_stats_type;
141*a9655020SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
142*a9655020SBjoern A. Zeeb 
143*a9655020SBjoern A. Zeeb 	ret = ath12k_wmi_send_tpc_stats_request(ar, tpc_stats_sub_id);
144*a9655020SBjoern A. Zeeb 	if (ret) {
145*a9655020SBjoern A. Zeeb 		ath12k_warn(ab, "failed to request pdev tpc stats: %d\n", ret);
146*a9655020SBjoern A. Zeeb 		spin_lock_bh(&ar->data_lock);
147*a9655020SBjoern A. Zeeb 		ar->debug.tpc_request = false;
148*a9655020SBjoern A. Zeeb 		spin_unlock_bh(&ar->data_lock);
149*a9655020SBjoern A. Zeeb 		return ret;
150*a9655020SBjoern A. Zeeb 	}
151*a9655020SBjoern A. Zeeb 
152*a9655020SBjoern A. Zeeb 	return 0;
153*a9655020SBjoern A. Zeeb }
154*a9655020SBjoern 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)155*a9655020SBjoern A. Zeeb static int ath12k_get_tpc_ctl_mode_idx(struct wmi_tpc_stats_arg *tpc_stats,
156*a9655020SBjoern A. Zeeb 				       enum wmi_tpc_pream_bw pream_bw, int *mode_idx)
157*a9655020SBjoern A. Zeeb {
158*a9655020SBjoern A. Zeeb 	u32 chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
159*a9655020SBjoern A. Zeeb 	u8 band;
160*a9655020SBjoern A. Zeeb 
161*a9655020SBjoern A. Zeeb 	band = ((chan_freq > ATH12K_MIN_6GHZ_FREQ) ? NL80211_BAND_6GHZ :
162*a9655020SBjoern A. Zeeb 		((chan_freq > ATH12K_MIN_5GHZ_FREQ) ? NL80211_BAND_5GHZ :
163*a9655020SBjoern A. Zeeb 		NL80211_BAND_2GHZ));
164*a9655020SBjoern A. Zeeb 
165*a9655020SBjoern A. Zeeb 	if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {
166*a9655020SBjoern A. Zeeb 		switch (pream_bw) {
167*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT20:
168*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT20:
169*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT20_5GHZ_6GHZ;
170*a9655020SBjoern A. Zeeb 			break;
171*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE20:
172*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT20:
173*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT20_5GHZ_6GHZ;
174*a9655020SBjoern A. Zeeb 			break;
175*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT40:
176*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT40:
177*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT_VHT40_5GHZ_6GHZ;
178*a9655020SBjoern A. Zeeb 			break;
179*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE40:
180*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT40:
181*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT40_5GHZ_6GHZ;
182*a9655020SBjoern A. Zeeb 			break;
183*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT80:
184*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT80_5GHZ_6GHZ;
185*a9655020SBjoern A. Zeeb 			break;
186*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT60:
187*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT80_SU_PUNC20;
188*a9655020SBjoern A. Zeeb 			break;
189*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE80:
190*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT80:
191*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT80_5GHZ_6GHZ;
192*a9655020SBjoern A. Zeeb 			break;
193*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT160:
194*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_VHT160_5GHZ_6GHZ;
195*a9655020SBjoern A. Zeeb 			break;
196*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT120:
197*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT140:
198*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT160_SU_PUNC20;
199*a9655020SBjoern A. Zeeb 			break;
200*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE160:
201*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT160:
202*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT160_5GHZ_6GHZ;
203*a9655020SBjoern A. Zeeb 			break;
204*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT200:
205*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC120;
206*a9655020SBjoern A. Zeeb 			break;
207*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT240:
208*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC80;
209*a9655020SBjoern A. Zeeb 			break;
210*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT280:
211*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_EHT320_SU_PUNC40;
212*a9655020SBjoern A. Zeeb 			break;
213*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT320:
214*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HE_EHT320_5GHZ_6GHZ;
215*a9655020SBjoern A. Zeeb 			break;
216*a9655020SBjoern A. Zeeb 		default:
217*a9655020SBjoern A. Zeeb 			/* for 5GHZ and 6GHZ, default case will be for OFDM */
218*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_5GHZ_6GHZ;
219*a9655020SBjoern A. Zeeb 			break;
220*a9655020SBjoern A. Zeeb 		}
221*a9655020SBjoern A. Zeeb 	} else {
222*a9655020SBjoern A. Zeeb 		switch (pream_bw) {
223*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_OFDM:
224*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_LEGACY_2GHZ;
225*a9655020SBjoern A. Zeeb 			break;
226*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT20:
227*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT20:
228*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE20:
229*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT20:
230*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT20_2GHZ;
231*a9655020SBjoern A. Zeeb 			break;
232*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HT40:
233*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_VHT40:
234*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_HE40:
235*a9655020SBjoern A. Zeeb 		case WMI_TPC_PREAM_EHT40:
236*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_HT40_2GHZ;
237*a9655020SBjoern A. Zeeb 			break;
238*a9655020SBjoern A. Zeeb 		default:
239*a9655020SBjoern A. Zeeb 			/* for 2GHZ, default case will be CCK */
240*a9655020SBjoern A. Zeeb 			*mode_idx = ATH12K_TPC_STATS_CTL_MODE_CCK_2GHZ;
241*a9655020SBjoern A. Zeeb 			break;
242*a9655020SBjoern A. Zeeb 		}
243*a9655020SBjoern A. Zeeb 	}
244*a9655020SBjoern A. Zeeb 
245*a9655020SBjoern A. Zeeb 	return 0;
246*a9655020SBjoern A. Zeeb }
247*a9655020SBjoern 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)248*a9655020SBjoern A. Zeeb static s16 ath12k_tpc_get_rate(struct ath12k *ar,
249*a9655020SBjoern A. Zeeb 			       struct wmi_tpc_stats_arg *tpc_stats,
250*a9655020SBjoern A. Zeeb 			       u32 rate_idx, u32 num_chains, u32 rate_code,
251*a9655020SBjoern A. Zeeb 			       enum wmi_tpc_pream_bw pream_bw,
252*a9655020SBjoern A. Zeeb 			       enum wmi_halphy_ctrl_path_stats_id type,
253*a9655020SBjoern A. Zeeb 			       u32 eht_rate_idx)
254*a9655020SBjoern A. Zeeb {
255*a9655020SBjoern A. Zeeb 	u32 tot_nss, tot_modes, txbf_on_off, index_offset1, index_offset2, index_offset3;
256*a9655020SBjoern A. Zeeb 	u8 chain_idx, stm_idx, num_streams;
257*a9655020SBjoern A. Zeeb 	bool is_mu, txbf_enabled = 0;
258*a9655020SBjoern A. Zeeb 	s8 rates_ctl_min, tpc_ctl;
259*a9655020SBjoern A. Zeeb 	s16 rates, tpc, reg_pwr;
260*a9655020SBjoern A. Zeeb 	u16 rate1, rate2;
261*a9655020SBjoern A. Zeeb 	int mode, ret;
262*a9655020SBjoern A. Zeeb 
263*a9655020SBjoern A. Zeeb 	num_streams = 1 + ATH12K_HW_NSS(rate_code);
264*a9655020SBjoern A. Zeeb 	chain_idx = num_chains - 1;
265*a9655020SBjoern A. Zeeb 	stm_idx = num_streams - 1;
266*a9655020SBjoern A. Zeeb 	mode = -1;
267*a9655020SBjoern A. Zeeb 
268*a9655020SBjoern A. Zeeb 	ret = ath12k_get_tpc_ctl_mode_idx(tpc_stats, pream_bw, &mode);
269*a9655020SBjoern A. Zeeb 	if (ret) {
270*a9655020SBjoern A. Zeeb 		ath12k_warn(ar->ab, "Invalid mode index received\n");
271*a9655020SBjoern A. Zeeb 		tpc = TPC_INVAL;
272*a9655020SBjoern A. Zeeb 		goto out;
273*a9655020SBjoern A. Zeeb 	}
274*a9655020SBjoern A. Zeeb 
275*a9655020SBjoern A. Zeeb 	if (num_chains < num_streams) {
276*a9655020SBjoern A. Zeeb 		tpc = TPC_INVAL;
277*a9655020SBjoern A. Zeeb 		goto out;
278*a9655020SBjoern A. Zeeb 	}
279*a9655020SBjoern A. Zeeb 
280*a9655020SBjoern A. Zeeb 	if (le32_to_cpu(tpc_stats->tpc_config.num_tx_chain) <= 1) {
281*a9655020SBjoern A. Zeeb 		tpc = TPC_INVAL;
282*a9655020SBjoern A. Zeeb 		goto out;
283*a9655020SBjoern A. Zeeb 	}
284*a9655020SBjoern A. Zeeb 
285*a9655020SBjoern A. Zeeb 	if (type == WMI_HALPHY_PDEV_TX_SUTXBF_STATS ||
286*a9655020SBjoern A. Zeeb 	    type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS)
287*a9655020SBjoern A. Zeeb 		txbf_enabled = 1;
288*a9655020SBjoern A. Zeeb 
289*a9655020SBjoern A. Zeeb 	if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
290*a9655020SBjoern A. Zeeb 	    type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
291*a9655020SBjoern A. Zeeb 		is_mu = true;
292*a9655020SBjoern A. Zeeb 	} else {
293*a9655020SBjoern A. Zeeb 		is_mu = false;
294*a9655020SBjoern A. Zeeb 	}
295*a9655020SBjoern A. Zeeb 
296*a9655020SBjoern A. Zeeb 	/* Below is the min calculation of ctl array, rates array and
297*a9655020SBjoern A. Zeeb 	 * regulator power table. tpc is minimum of all 3
298*a9655020SBjoern A. Zeeb 	 */
299*a9655020SBjoern A. Zeeb 	if (pream_bw >= WMI_TPC_PREAM_EHT20 && pream_bw <= WMI_TPC_PREAM_EHT320) {
300*a9655020SBjoern A. Zeeb 		rate2 = tpc_stats->rates_array2.rate_array[eht_rate_idx];
301*a9655020SBjoern A. Zeeb 		if (is_mu)
302*a9655020SBjoern A. Zeeb 			rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_MU);
303*a9655020SBjoern A. Zeeb 		else
304*a9655020SBjoern A. Zeeb 			rates = u32_get_bits(rate2, ATH12K_TPC_RATE_ARRAY_SU);
305*a9655020SBjoern A. Zeeb 	} else {
306*a9655020SBjoern A. Zeeb 		rate1 = tpc_stats->rates_array1.rate_array[rate_idx];
307*a9655020SBjoern A. Zeeb 		if (is_mu)
308*a9655020SBjoern A. Zeeb 			rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_MU);
309*a9655020SBjoern A. Zeeb 		else
310*a9655020SBjoern A. Zeeb 			rates = u32_get_bits(rate1, ATH12K_TPC_RATE_ARRAY_SU);
311*a9655020SBjoern A. Zeeb 	}
312*a9655020SBjoern A. Zeeb 
313*a9655020SBjoern A. Zeeb 	if (tpc_stats->tlvs_rcvd & WMI_TPC_CTL_PWR_ARRAY) {
314*a9655020SBjoern A. Zeeb 		tot_nss = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d1);
315*a9655020SBjoern A. Zeeb 		tot_modes = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d2);
316*a9655020SBjoern A. Zeeb 		txbf_on_off = le32_to_cpu(tpc_stats->ctl_array.tpc_ctl_pwr.d3);
317*a9655020SBjoern A. Zeeb 		index_offset1 = txbf_on_off * tot_modes * tot_nss;
318*a9655020SBjoern A. Zeeb 		index_offset2 = tot_modes * tot_nss;
319*a9655020SBjoern A. Zeeb 		index_offset3 = tot_nss;
320*a9655020SBjoern A. Zeeb 
321*a9655020SBjoern A. Zeeb 		tpc_ctl = *(tpc_stats->ctl_array.ctl_pwr_table +
322*a9655020SBjoern A. Zeeb 			    chain_idx * index_offset1 + txbf_enabled * index_offset2
323*a9655020SBjoern A. Zeeb 			    + mode * index_offset3 + stm_idx);
324*a9655020SBjoern A. Zeeb 	} else {
325*a9655020SBjoern A. Zeeb 		tpc_ctl = TPC_MAX;
326*a9655020SBjoern A. Zeeb 		ath12k_warn(ar->ab,
327*a9655020SBjoern A. Zeeb 			    "ctl array for tpc stats not received from fw\n");
328*a9655020SBjoern A. Zeeb 	}
329*a9655020SBjoern A. Zeeb 
330*a9655020SBjoern A. Zeeb 	rates_ctl_min = min_t(s16, rates, tpc_ctl);
331*a9655020SBjoern A. Zeeb 
332*a9655020SBjoern A. Zeeb 	reg_pwr = tpc_stats->max_reg_allowed_power.reg_pwr_array[chain_idx];
333*a9655020SBjoern A. Zeeb 
334*a9655020SBjoern A. Zeeb 	if (reg_pwr < 0)
335*a9655020SBjoern A. Zeeb 		reg_pwr = TPC_INVAL;
336*a9655020SBjoern A. Zeeb 
337*a9655020SBjoern A. Zeeb 	tpc = min_t(s16, rates_ctl_min, reg_pwr);
338*a9655020SBjoern A. Zeeb 
339*a9655020SBjoern A. Zeeb 	/* MODULATION_LIMIT is the maximum power limit,tpc should not exceed
340*a9655020SBjoern A. Zeeb 	 * modulation limit even if min tpc of all three array is greater
341*a9655020SBjoern A. Zeeb 	 * modulation limit
342*a9655020SBjoern A. Zeeb 	 */
343*a9655020SBjoern A. Zeeb 	tpc = min_t(s16, tpc, MODULATION_LIMIT);
344*a9655020SBjoern A. Zeeb 
345*a9655020SBjoern A. Zeeb out:
346*a9655020SBjoern A. Zeeb 	return tpc;
347*a9655020SBjoern A. Zeeb }
348*a9655020SBjoern A. Zeeb 
ath12k_get_ratecode(u16 pream_idx,u16 nss,u16 mcs_rate)349*a9655020SBjoern A. Zeeb static u16 ath12k_get_ratecode(u16 pream_idx, u16 nss, u16 mcs_rate)
350*a9655020SBjoern A. Zeeb {
351*a9655020SBjoern A. Zeeb 	u16 mode_type = ~0;
352*a9655020SBjoern A. Zeeb 
353*a9655020SBjoern A. Zeeb 	/* Below assignments are just for printing purpose only */
354*a9655020SBjoern A. Zeeb 	switch (pream_idx) {
355*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_CCK:
356*a9655020SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_CCK;
357*a9655020SBjoern A. Zeeb 		break;
358*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_OFDM:
359*a9655020SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_OFDM;
360*a9655020SBjoern A. Zeeb 		break;
361*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_HT20:
362*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_HT40:
363*a9655020SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_HT;
364*a9655020SBjoern A. Zeeb 		break;
365*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT20:
366*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT40:
367*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT80:
368*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_VHT160:
369*a9655020SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_VHT;
370*a9655020SBjoern A. Zeeb 		break;
371*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE20:
372*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE40:
373*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE80:
374*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_HE160:
375*a9655020SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_HE;
376*a9655020SBjoern A. Zeeb 		break;
377*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT20:
378*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT40:
379*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT60:
380*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT80:
381*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT120:
382*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT140:
383*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT160:
384*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT200:
385*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT240:
386*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT280:
387*a9655020SBjoern A. Zeeb 	case WMI_TPC_PREAM_EHT320:
388*a9655020SBjoern A. Zeeb 		mode_type = WMI_RATE_PREAMBLE_EHT;
389*a9655020SBjoern A. Zeeb 		if (mcs_rate == 0 || mcs_rate == 1)
390*a9655020SBjoern A. Zeeb 			mcs_rate += 14;
391*a9655020SBjoern A. Zeeb 		else
392*a9655020SBjoern A. Zeeb 			mcs_rate -= 2;
393*a9655020SBjoern A. Zeeb 		break;
394*a9655020SBjoern A. Zeeb 	default:
395*a9655020SBjoern A. Zeeb 		return mode_type;
396*a9655020SBjoern A. Zeeb 	}
397*a9655020SBjoern A. Zeeb 	return ((mode_type << 8) | ((nss & 0x7) << 5) | (mcs_rate & 0x1F));
398*a9655020SBjoern A. Zeeb }
399*a9655020SBjoern A. Zeeb 
ath12k_he_supports_extra_mcs(struct ath12k * ar,int freq)400*a9655020SBjoern A. Zeeb static bool ath12k_he_supports_extra_mcs(struct ath12k *ar, int freq)
401*a9655020SBjoern A. Zeeb {
402*a9655020SBjoern A. Zeeb 	struct ath12k_pdev_cap *cap = &ar->pdev->cap;
403*a9655020SBjoern A. Zeeb 	struct ath12k_band_cap *cap_band;
404*a9655020SBjoern A. Zeeb 	bool extra_mcs_supported;
405*a9655020SBjoern A. Zeeb 
406*a9655020SBjoern A. Zeeb 	if (freq <= ATH12K_2GHZ_MAX_FREQUENCY)
407*a9655020SBjoern A. Zeeb 		cap_band = &cap->band[NL80211_BAND_2GHZ];
408*a9655020SBjoern A. Zeeb 	else if (freq <= ATH12K_5GHZ_MAX_FREQUENCY)
409*a9655020SBjoern A. Zeeb 		cap_band = &cap->band[NL80211_BAND_5GHZ];
410*a9655020SBjoern A. Zeeb 	else
411*a9655020SBjoern A. Zeeb 		cap_band = &cap->band[NL80211_BAND_6GHZ];
412*a9655020SBjoern A. Zeeb 
413*a9655020SBjoern A. Zeeb 	extra_mcs_supported = u32_get_bits(cap_band->he_cap_info[1],
414*a9655020SBjoern A. Zeeb 					   HE_EXTRA_MCS_SUPPORT);
415*a9655020SBjoern A. Zeeb 	return extra_mcs_supported;
416*a9655020SBjoern A. Zeeb }
417*a9655020SBjoern 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)418*a9655020SBjoern A. Zeeb static int ath12k_tpc_fill_pream(struct ath12k *ar, char *buf, int buf_len, int len,
419*a9655020SBjoern A. Zeeb 				 enum wmi_tpc_pream_bw pream_bw, u32 max_rix,
420*a9655020SBjoern A. Zeeb 				 int max_nss, int max_rates, int pream_type,
421*a9655020SBjoern A. Zeeb 				 enum wmi_halphy_ctrl_path_stats_id tpc_type,
422*a9655020SBjoern A. Zeeb 				 int rate_idx, int eht_rate_idx)
423*a9655020SBjoern A. Zeeb {
424*a9655020SBjoern A. Zeeb 	struct wmi_tpc_stats_arg *tpc_stats = ar->debug.tpc_stats;
425*a9655020SBjoern A. Zeeb 	int nss, rates, chains;
426*a9655020SBjoern A. Zeeb 	u8 active_tx_chains;
427*a9655020SBjoern A. Zeeb 	u16 rate_code;
428*a9655020SBjoern A. Zeeb 	s16 tpc;
429*a9655020SBjoern A. Zeeb 
430*a9655020SBjoern A. Zeeb 	static const char *const pream_str[] = {
431*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = "CCK",
432*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = "OFDM",
433*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = "HT20",
434*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = "HT40",
435*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = "VHT20",
436*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = "VHT40",
437*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = "VHT80",
438*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = "VHT160",
439*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = "HE20",
440*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = "HE40",
441*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = "HE80",
442*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = "HE160",
443*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = "EHT20",
444*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = "EHT40",
445*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = "EHT60",
446*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = "EHT80",
447*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]   = "EHT120",
448*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]   = "EHT140",
449*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]   = "EHT160",
450*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]   = "EHT200",
451*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]   = "EHT240",
452*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]   = "EHT280",
453*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]   = "EHT320"};
454*a9655020SBjoern A. Zeeb 
455*a9655020SBjoern A. Zeeb 	active_tx_chains = ar->num_tx_chains;
456*a9655020SBjoern A. Zeeb 
457*a9655020SBjoern A. Zeeb 	for (nss = 0; nss < max_nss; nss++) {
458*a9655020SBjoern A. Zeeb 		for (rates = 0; rates < max_rates; rates++, rate_idx++, max_rix++) {
459*a9655020SBjoern A. Zeeb 			/* FW send extra MCS(10&11) for VHT and HE rates,
460*a9655020SBjoern A. Zeeb 			 *  this is not used. Hence skipping it here
461*a9655020SBjoern A. Zeeb 			 */
462*a9655020SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_VHT &&
463*a9655020SBjoern A. Zeeb 			    rates > ATH12K_VHT_MCS_MAX)
464*a9655020SBjoern A. Zeeb 				continue;
465*a9655020SBjoern A. Zeeb 
466*a9655020SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_HE &&
467*a9655020SBjoern A. Zeeb 			    rates > ATH12K_HE_MCS_MAX)
468*a9655020SBjoern A. Zeeb 				continue;
469*a9655020SBjoern A. Zeeb 
470*a9655020SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_EHT &&
471*a9655020SBjoern A. Zeeb 			    rates > ATH12K_EHT_MCS_MAX)
472*a9655020SBjoern A. Zeeb 				continue;
473*a9655020SBjoern A. Zeeb 
474*a9655020SBjoern A. Zeeb 			rate_code = ath12k_get_ratecode(pream_bw, nss, rates);
475*a9655020SBjoern A. Zeeb 			len += scnprintf(buf + len, buf_len - len,
476*a9655020SBjoern A. Zeeb 					 "%d\t %s\t 0x%03x\t", max_rix,
477*a9655020SBjoern A. Zeeb 					 pream_str[pream_bw], rate_code);
478*a9655020SBjoern A. Zeeb 
479*a9655020SBjoern A. Zeeb 			for (chains = 0; chains < active_tx_chains; chains++) {
480*a9655020SBjoern A. Zeeb 				if (nss > chains) {
481*a9655020SBjoern A. Zeeb 					len += scnprintf(buf + len,
482*a9655020SBjoern A. Zeeb 							 buf_len - len,
483*a9655020SBjoern A. Zeeb 							 "\t%s", "NA");
484*a9655020SBjoern A. Zeeb 				} else {
485*a9655020SBjoern A. Zeeb 					tpc = ath12k_tpc_get_rate(ar, tpc_stats,
486*a9655020SBjoern A. Zeeb 								  rate_idx, chains + 1,
487*a9655020SBjoern A. Zeeb 								  rate_code, pream_bw,
488*a9655020SBjoern A. Zeeb 								  tpc_type,
489*a9655020SBjoern A. Zeeb 								  eht_rate_idx);
490*a9655020SBjoern A. Zeeb 
491*a9655020SBjoern A. Zeeb 					if (tpc == TPC_INVAL) {
492*a9655020SBjoern A. Zeeb 						len += scnprintf(buf + len,
493*a9655020SBjoern A. Zeeb 								 buf_len - len, "\tNA");
494*a9655020SBjoern A. Zeeb 					} else {
495*a9655020SBjoern A. Zeeb 						len += scnprintf(buf + len,
496*a9655020SBjoern A. Zeeb 								 buf_len - len, "\t%d",
497*a9655020SBjoern A. Zeeb 								 tpc);
498*a9655020SBjoern A. Zeeb 					}
499*a9655020SBjoern A. Zeeb 				}
500*a9655020SBjoern A. Zeeb 			}
501*a9655020SBjoern A. Zeeb 			len += scnprintf(buf + len, buf_len - len, "\n");
502*a9655020SBjoern A. Zeeb 
503*a9655020SBjoern A. Zeeb 			if (pream_type == WMI_RATE_PREAMBLE_EHT)
504*a9655020SBjoern A. Zeeb 				/*For fetching the next eht rates pwr from rates array2*/
505*a9655020SBjoern A. Zeeb 				++eht_rate_idx;
506*a9655020SBjoern A. Zeeb 		}
507*a9655020SBjoern A. Zeeb 	}
508*a9655020SBjoern A. Zeeb 
509*a9655020SBjoern A. Zeeb 	return len;
510*a9655020SBjoern A. Zeeb }
511*a9655020SBjoern 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)512*a9655020SBjoern A. Zeeb static int ath12k_tpc_stats_print(struct ath12k *ar,
513*a9655020SBjoern A. Zeeb 				  struct wmi_tpc_stats_arg *tpc_stats,
514*a9655020SBjoern A. Zeeb 				  char *buf, size_t len,
515*a9655020SBjoern A. Zeeb 				  enum wmi_halphy_ctrl_path_stats_id type)
516*a9655020SBjoern A. Zeeb {
517*a9655020SBjoern A. Zeeb 	u32 eht_idx = 0, pream_idx = 0, rate_pream_idx = 0, total_rates = 0, max_rix = 0;
518*a9655020SBjoern A. Zeeb 	u32 chan_freq, num_tx_chain, caps, i, j = 1;
519*a9655020SBjoern A. Zeeb 	size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
520*a9655020SBjoern A. Zeeb 	u8 nss, active_tx_chains;
521*a9655020SBjoern A. Zeeb 	bool he_ext_mcs;
522*a9655020SBjoern A. Zeeb 	static const char *const type_str[WMI_HALPHY_PDEV_TX_STATS_MAX] = {
523*a9655020SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_SU_STATS]		= "SU",
524*a9655020SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_SUTXBF_STATS]	= "SU WITH TXBF",
525*a9655020SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_MU_STATS]		= "MU",
526*a9655020SBjoern A. Zeeb 		[WMI_HALPHY_PDEV_TX_MUTXBF_STATS]	= "MU WITH TXBF"};
527*a9655020SBjoern A. Zeeb 
528*a9655020SBjoern A. Zeeb 	u8 max_rates[WMI_TPC_PREAM_MAX] = {
529*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = ATH12K_CCK_RATES,
530*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = ATH12K_OFDM_RATES,
531*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = ATH12K_HT_RATES,
532*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = ATH12K_HT_RATES,
533*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = ATH12K_VHT_RATES,
534*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = ATH12K_VHT_RATES,
535*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = ATH12K_VHT_RATES,
536*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = ATH12K_VHT_RATES,
537*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = ATH12K_HE_RATES,
538*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = ATH12K_HE_RATES,
539*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = ATH12K_HE_RATES,
540*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = ATH12K_HE_RATES,
541*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = ATH12K_EHT_RATES,
542*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = ATH12K_EHT_RATES,
543*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = ATH12K_EHT_RATES,
544*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = ATH12K_EHT_RATES,
545*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]  = ATH12K_EHT_RATES,
546*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]  = ATH12K_EHT_RATES,
547*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]  = ATH12K_EHT_RATES,
548*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]  = ATH12K_EHT_RATES,
549*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]  = ATH12K_EHT_RATES,
550*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]  = ATH12K_EHT_RATES,
551*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]  = ATH12K_EHT_RATES};
552*a9655020SBjoern A. Zeeb 	static const u8 max_nss[WMI_TPC_PREAM_MAX] = {
553*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = ATH12K_NSS_1,
554*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = ATH12K_NSS_1,
555*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = ATH12K_NSS_4,
556*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = ATH12K_NSS_4,
557*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = ATH12K_NSS_8,
558*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = ATH12K_NSS_8,
559*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = ATH12K_NSS_8,
560*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = ATH12K_NSS_4,
561*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = ATH12K_NSS_8,
562*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = ATH12K_NSS_8,
563*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = ATH12K_NSS_8,
564*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = ATH12K_NSS_4,
565*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = ATH12K_NSS_4,
566*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = ATH12K_NSS_4,
567*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = ATH12K_NSS_4,
568*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = ATH12K_NSS_4,
569*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]  = ATH12K_NSS_4,
570*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]  = ATH12K_NSS_4,
571*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]  = ATH12K_NSS_4,
572*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]  = ATH12K_NSS_4,
573*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]  = ATH12K_NSS_4,
574*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]  = ATH12K_NSS_4,
575*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]  = ATH12K_NSS_4};
576*a9655020SBjoern A. Zeeb 
577*a9655020SBjoern A. Zeeb 	u16 rate_idx[WMI_TPC_PREAM_MAX] = {}, eht_rate_idx[WMI_TPC_PREAM_MAX] = {};
578*a9655020SBjoern A. Zeeb 	static const u8 pream_type[WMI_TPC_PREAM_MAX] = {
579*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_CCK]     = WMI_RATE_PREAMBLE_CCK,
580*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_OFDM]    = WMI_RATE_PREAMBLE_OFDM,
581*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT20]    = WMI_RATE_PREAMBLE_HT,
582*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HT40]    = WMI_RATE_PREAMBLE_HT,
583*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT20]   = WMI_RATE_PREAMBLE_VHT,
584*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT40]   = WMI_RATE_PREAMBLE_VHT,
585*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT80]   = WMI_RATE_PREAMBLE_VHT,
586*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_VHT160]  = WMI_RATE_PREAMBLE_VHT,
587*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE20]    = WMI_RATE_PREAMBLE_HE,
588*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE40]    = WMI_RATE_PREAMBLE_HE,
589*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE80]    = WMI_RATE_PREAMBLE_HE,
590*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_HE160]   = WMI_RATE_PREAMBLE_HE,
591*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT20]   = WMI_RATE_PREAMBLE_EHT,
592*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT40]   = WMI_RATE_PREAMBLE_EHT,
593*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT60]   = WMI_RATE_PREAMBLE_EHT,
594*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT80]   = WMI_RATE_PREAMBLE_EHT,
595*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT120]  = WMI_RATE_PREAMBLE_EHT,
596*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT140]  = WMI_RATE_PREAMBLE_EHT,
597*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT160]  = WMI_RATE_PREAMBLE_EHT,
598*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT200]  = WMI_RATE_PREAMBLE_EHT,
599*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT240]  = WMI_RATE_PREAMBLE_EHT,
600*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT280]  = WMI_RATE_PREAMBLE_EHT,
601*a9655020SBjoern A. Zeeb 		[WMI_TPC_PREAM_EHT320]  = WMI_RATE_PREAMBLE_EHT};
602*a9655020SBjoern A. Zeeb 
603*a9655020SBjoern A. Zeeb 	chan_freq = le32_to_cpu(tpc_stats->tpc_config.chan_freq);
604*a9655020SBjoern A. Zeeb 	num_tx_chain = le32_to_cpu(tpc_stats->tpc_config.num_tx_chain);
605*a9655020SBjoern A. Zeeb 	caps = le32_to_cpu(tpc_stats->tpc_config.caps);
606*a9655020SBjoern A. Zeeb 
607*a9655020SBjoern A. Zeeb 	active_tx_chains = ar->num_tx_chains;
608*a9655020SBjoern A. Zeeb 	he_ext_mcs = ath12k_he_supports_extra_mcs(ar, chan_freq);
609*a9655020SBjoern A. Zeeb 
610*a9655020SBjoern A. Zeeb 	/* mcs 12&13 is sent by FW for certain HWs in rate array, skipping it as
611*a9655020SBjoern A. Zeeb 	 * it is not supported
612*a9655020SBjoern A. Zeeb 	 */
613*a9655020SBjoern A. Zeeb 	if (he_ext_mcs) {
614*a9655020SBjoern A. Zeeb 		for (i = WMI_TPC_PREAM_HE20; i <= WMI_TPC_PREAM_HE160; ++i)
615*a9655020SBjoern A. Zeeb 			max_rates[i] = ATH12K_HE_RATES;
616*a9655020SBjoern A. Zeeb 	}
617*a9655020SBjoern A. Zeeb 
618*a9655020SBjoern A. Zeeb 	if (type == WMI_HALPHY_PDEV_TX_MU_STATS ||
619*a9655020SBjoern A. Zeeb 	    type == WMI_HALPHY_PDEV_TX_MUTXBF_STATS) {
620*a9655020SBjoern A. Zeeb 		pream_idx = WMI_TPC_PREAM_VHT20;
621*a9655020SBjoern A. Zeeb 
622*a9655020SBjoern A. Zeeb 		for (i = WMI_TPC_PREAM_CCK; i <= WMI_TPC_PREAM_HT40; ++i)
623*a9655020SBjoern A. Zeeb 			max_rix += max_nss[i] * max_rates[i];
624*a9655020SBjoern A. Zeeb 	}
625*a9655020SBjoern A. Zeeb 	/* Enumerate all the rate indices */
626*a9655020SBjoern A. Zeeb 	for (i = rate_pream_idx + 1; i < WMI_TPC_PREAM_MAX; i++) {
627*a9655020SBjoern A. Zeeb 		nss = (max_nss[i - 1] < num_tx_chain ?
628*a9655020SBjoern A. Zeeb 		       max_nss[i - 1] : num_tx_chain);
629*a9655020SBjoern A. Zeeb 
630*a9655020SBjoern A. Zeeb 		rate_idx[i] = rate_idx[i - 1] + max_rates[i - 1] * nss;
631*a9655020SBjoern A. Zeeb 
632*a9655020SBjoern A. Zeeb 		if (pream_type[i] == WMI_RATE_PREAMBLE_EHT) {
633*a9655020SBjoern A. Zeeb 			eht_rate_idx[j] = eht_rate_idx[j - 1] + max_rates[i] * nss;
634*a9655020SBjoern A. Zeeb 			++j;
635*a9655020SBjoern A. Zeeb 		}
636*a9655020SBjoern A. Zeeb 	}
637*a9655020SBjoern A. Zeeb 
638*a9655020SBjoern A. Zeeb 	for (i = 0; i < WMI_TPC_PREAM_MAX; i++) {
639*a9655020SBjoern A. Zeeb 		nss = (max_nss[i] < num_tx_chain ?
640*a9655020SBjoern A. Zeeb 		       max_nss[i] : num_tx_chain);
641*a9655020SBjoern A. Zeeb 		total_rates += max_rates[i] * nss;
642*a9655020SBjoern A. Zeeb 	}
643*a9655020SBjoern A. Zeeb 
644*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
645*a9655020SBjoern A. Zeeb 			 "No.of rates-%d\n", total_rates);
646*a9655020SBjoern A. Zeeb 
647*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
648*a9655020SBjoern A. Zeeb 			 "**************** %s ****************\n",
649*a9655020SBjoern A. Zeeb 			 type_str[type]);
650*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
651*a9655020SBjoern A. Zeeb 			 "\t\t\t\tTPC values for Active chains\n");
652*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
653*a9655020SBjoern A. Zeeb 			 "Rate idx Preamble Rate code");
654*a9655020SBjoern A. Zeeb 
655*a9655020SBjoern A. Zeeb 	for (i = 1; i <= active_tx_chains; ++i) {
656*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
657*a9655020SBjoern A. Zeeb 				 "\t%d-Chain", i);
658*a9655020SBjoern A. Zeeb 	}
659*a9655020SBjoern A. Zeeb 
660*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "\n");
661*a9655020SBjoern A. Zeeb 	for (i = pream_idx; i < WMI_TPC_PREAM_MAX; i++) {
662*a9655020SBjoern A. Zeeb 		if (chan_freq <= 2483) {
663*a9655020SBjoern A. Zeeb 			if (i == WMI_TPC_PREAM_VHT80 ||
664*a9655020SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_VHT160 ||
665*a9655020SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_HE80 ||
666*a9655020SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_HE160 ||
667*a9655020SBjoern A. Zeeb 			    (i >= WMI_TPC_PREAM_EHT60 &&
668*a9655020SBjoern A. Zeeb 			     i <= WMI_TPC_PREAM_EHT320)) {
669*a9655020SBjoern A. Zeeb 				max_rix += max_nss[i] * max_rates[i];
670*a9655020SBjoern A. Zeeb 				continue;
671*a9655020SBjoern A. Zeeb 			}
672*a9655020SBjoern A. Zeeb 		} else {
673*a9655020SBjoern A. Zeeb 			if (i == WMI_TPC_PREAM_CCK) {
674*a9655020SBjoern A. Zeeb 				max_rix += max_rates[i];
675*a9655020SBjoern A. Zeeb 				continue;
676*a9655020SBjoern A. Zeeb 			}
677*a9655020SBjoern A. Zeeb 		}
678*a9655020SBjoern A. Zeeb 
679*a9655020SBjoern A. Zeeb 		nss = (max_nss[i] < ar->num_tx_chains ? max_nss[i] : ar->num_tx_chains);
680*a9655020SBjoern A. Zeeb 
681*a9655020SBjoern A. Zeeb 		if (!(caps &
682*a9655020SBjoern A. Zeeb 		    (1 << ATH12K_TPC_STATS_SUPPORT_BE_PUNC))) {
683*a9655020SBjoern A. Zeeb 			if (i == WMI_TPC_PREAM_EHT60 || i == WMI_TPC_PREAM_EHT120 ||
684*a9655020SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_EHT140 || i == WMI_TPC_PREAM_EHT200 ||
685*a9655020SBjoern A. Zeeb 			    i == WMI_TPC_PREAM_EHT240 || i == WMI_TPC_PREAM_EHT280) {
686*a9655020SBjoern A. Zeeb 				max_rix += max_nss[i] * max_rates[i];
687*a9655020SBjoern A. Zeeb 				continue;
688*a9655020SBjoern A. Zeeb 			}
689*a9655020SBjoern A. Zeeb 		}
690*a9655020SBjoern A. Zeeb 
691*a9655020SBjoern A. Zeeb 		len = ath12k_tpc_fill_pream(ar, buf, buf_len, len, i, max_rix, nss,
692*a9655020SBjoern A. Zeeb 					    max_rates[i], pream_type[i],
693*a9655020SBjoern A. Zeeb 					    type, rate_idx[i], eht_rate_idx[eht_idx]);
694*a9655020SBjoern A. Zeeb 
695*a9655020SBjoern A. Zeeb 		if (pream_type[i] == WMI_RATE_PREAMBLE_EHT)
696*a9655020SBjoern A. Zeeb 			/*For fetch the next index eht rates from rates array2*/
697*a9655020SBjoern A. Zeeb 			++eht_idx;
698*a9655020SBjoern A. Zeeb 
699*a9655020SBjoern A. Zeeb 		max_rix += max_nss[i] * max_rates[i];
700*a9655020SBjoern A. Zeeb 	}
701*a9655020SBjoern A. Zeeb 	return len;
702*a9655020SBjoern A. Zeeb }
703*a9655020SBjoern A. Zeeb 
ath12k_tpc_stats_fill(struct ath12k * ar,struct wmi_tpc_stats_arg * tpc_stats,char * buf)704*a9655020SBjoern A. Zeeb static void ath12k_tpc_stats_fill(struct ath12k *ar,
705*a9655020SBjoern A. Zeeb 				  struct wmi_tpc_stats_arg *tpc_stats,
706*a9655020SBjoern A. Zeeb 				  char *buf)
707*a9655020SBjoern A. Zeeb {
708*a9655020SBjoern A. Zeeb 	size_t buf_len = ATH12K_TPC_STATS_BUF_SIZE;
709*a9655020SBjoern A. Zeeb 	struct wmi_tpc_config_params *tpc;
710*a9655020SBjoern A. Zeeb 	size_t len = 0;
711*a9655020SBjoern A. Zeeb 
712*a9655020SBjoern A. Zeeb 	if (!tpc_stats) {
713*a9655020SBjoern A. Zeeb 		ath12k_warn(ar->ab, "failed to find tpc stats\n");
714*a9655020SBjoern A. Zeeb 		return;
715*a9655020SBjoern A. Zeeb 	}
716*a9655020SBjoern A. Zeeb 
717*a9655020SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
718*a9655020SBjoern A. Zeeb 
719*a9655020SBjoern A. Zeeb 	tpc = &tpc_stats->tpc_config;
720*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "\n");
721*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
722*a9655020SBjoern A. Zeeb 			 "*************** TPC config **************\n");
723*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
724*a9655020SBjoern A. Zeeb 			 "* powers are in 0.25 dBm steps\n");
725*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
726*a9655020SBjoern A. Zeeb 			 "reg domain-%d\t\tchan freq-%d\n",
727*a9655020SBjoern A. Zeeb 			 tpc->reg_domain, tpc->chan_freq);
728*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
729*a9655020SBjoern A. Zeeb 			 "power limit-%d\t\tmax reg-domain Power-%d\n",
730*a9655020SBjoern A. Zeeb 			 le32_to_cpu(tpc->twice_max_reg_power) / 2, tpc->power_limit);
731*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
732*a9655020SBjoern A. Zeeb 			 "No.of tx chain-%d\t",
733*a9655020SBjoern A. Zeeb 			 ar->num_tx_chains);
734*a9655020SBjoern A. Zeeb 
735*a9655020SBjoern A. Zeeb 	ath12k_tpc_stats_print(ar, tpc_stats, buf, len,
736*a9655020SBjoern A. Zeeb 			       ar->debug.tpc_stats_type);
737*a9655020SBjoern A. Zeeb 
738*a9655020SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
739*a9655020SBjoern A. Zeeb }
740*a9655020SBjoern A. Zeeb 
ath12k_open_tpc_stats(struct inode * inode,struct file * file)741*a9655020SBjoern A. Zeeb static int ath12k_open_tpc_stats(struct inode *inode, struct file *file)
742*a9655020SBjoern A. Zeeb {
743*a9655020SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
744*a9655020SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
745*a9655020SBjoern A. Zeeb 	int ret;
746*a9655020SBjoern A. Zeeb 
747*a9655020SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
748*a9655020SBjoern A. Zeeb 
749*a9655020SBjoern A. Zeeb 	if (ah->state != ATH12K_HW_STATE_ON) {
750*a9655020SBjoern A. Zeeb 		ath12k_warn(ar->ab, "Interface not up\n");
751*a9655020SBjoern A. Zeeb 		return -ENETDOWN;
752*a9655020SBjoern A. Zeeb 	}
753*a9655020SBjoern A. Zeeb 
754*a9655020SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_TPC_STATS_BUF_SIZE, GFP_KERNEL);
755*a9655020SBjoern A. Zeeb 	if (!buf)
756*a9655020SBjoern A. Zeeb 		return -ENOMEM;
757*a9655020SBjoern A. Zeeb 
758*a9655020SBjoern A. Zeeb 	ret = ath12k_debug_tpc_stats_request(ar);
759*a9655020SBjoern A. Zeeb 	if (ret) {
760*a9655020SBjoern A. Zeeb 		ath12k_warn(ar->ab, "failed to request tpc stats: %d\n",
761*a9655020SBjoern A. Zeeb 			    ret);
762*a9655020SBjoern A. Zeeb 		return ret;
763*a9655020SBjoern A. Zeeb 	}
764*a9655020SBjoern A. Zeeb 
765*a9655020SBjoern A. Zeeb 	if (!wait_for_completion_timeout(&ar->debug.tpc_complete, TPC_STATS_WAIT_TIME)) {
766*a9655020SBjoern A. Zeeb 		spin_lock_bh(&ar->data_lock);
767*a9655020SBjoern A. Zeeb 		ath12k_wmi_free_tpc_stats_mem(ar);
768*a9655020SBjoern A. Zeeb 		ar->debug.tpc_request = false;
769*a9655020SBjoern A. Zeeb 		spin_unlock_bh(&ar->data_lock);
770*a9655020SBjoern A. Zeeb 		return -ETIMEDOUT;
771*a9655020SBjoern A. Zeeb 	}
772*a9655020SBjoern A. Zeeb 
773*a9655020SBjoern A. Zeeb 	ath12k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
774*a9655020SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
775*a9655020SBjoern A. Zeeb 
776*a9655020SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
777*a9655020SBjoern A. Zeeb 	ath12k_wmi_free_tpc_stats_mem(ar);
778*a9655020SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
779*a9655020SBjoern A. Zeeb 
780*a9655020SBjoern A. Zeeb 	return 0;
781*a9655020SBjoern A. Zeeb }
782*a9655020SBjoern A. Zeeb 
ath12k_read_tpc_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)783*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_tpc_stats(struct file *file,
784*a9655020SBjoern A. Zeeb 				     char __user *user_buf,
785*a9655020SBjoern A. Zeeb 				     size_t count, loff_t *ppos)
786*a9655020SBjoern A. Zeeb {
787*a9655020SBjoern A. Zeeb 	const char *buf = file->private_data;
788*a9655020SBjoern A. Zeeb 	size_t len = strlen(buf);
789*a9655020SBjoern A. Zeeb 
790*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
791*a9655020SBjoern A. Zeeb }
792*a9655020SBjoern A. Zeeb 
ath12k_release_tpc_stats(struct inode * inode,struct file * file)793*a9655020SBjoern A. Zeeb static int ath12k_release_tpc_stats(struct inode *inode,
794*a9655020SBjoern A. Zeeb 				    struct file *file)
795*a9655020SBjoern A. Zeeb {
796*a9655020SBjoern A. Zeeb 	kfree(file->private_data);
797*a9655020SBjoern A. Zeeb 	return 0;
798*a9655020SBjoern A. Zeeb }
799*a9655020SBjoern A. Zeeb 
800*a9655020SBjoern A. Zeeb static const struct file_operations fops_tpc_stats = {
801*a9655020SBjoern A. Zeeb 	.open = ath12k_open_tpc_stats,
802*a9655020SBjoern A. Zeeb 	.release = ath12k_release_tpc_stats,
803*a9655020SBjoern A. Zeeb 	.read = ath12k_read_tpc_stats,
804*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
805*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
806*a9655020SBjoern A. Zeeb };
807*a9655020SBjoern A. Zeeb 
808*a9655020SBjoern A. Zeeb static const struct file_operations fops_tpc_stats_type = {
809*a9655020SBjoern A. Zeeb 	.write = ath12k_write_tpc_stats_type,
810*a9655020SBjoern A. Zeeb 	.open = simple_open,
811*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
812*a9655020SBjoern A. Zeeb };
813*a9655020SBjoern A. Zeeb 
ath12k_write_extd_rx_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)814*a9655020SBjoern A. Zeeb static ssize_t ath12k_write_extd_rx_stats(struct file *file,
815*a9655020SBjoern A. Zeeb 					  const char __user *ubuf,
816*a9655020SBjoern A. Zeeb 					  size_t count, loff_t *ppos)
817*a9655020SBjoern A. Zeeb {
818*a9655020SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
819*a9655020SBjoern A. Zeeb 	struct htt_rx_ring_tlv_filter tlv_filter = {};
820*a9655020SBjoern A. Zeeb 	u32 ring_id, rx_filter = 0;
821*a9655020SBjoern A. Zeeb 	bool enable;
822*a9655020SBjoern A. Zeeb 	int ret, i;
823*a9655020SBjoern A. Zeeb 
824*a9655020SBjoern A. Zeeb 	if (kstrtobool_from_user(ubuf, count, &enable))
825*a9655020SBjoern A. Zeeb 		return -EINVAL;
826*a9655020SBjoern A. Zeeb 
827*a9655020SBjoern A. Zeeb 	wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
828*a9655020SBjoern A. Zeeb 
829*a9655020SBjoern A. Zeeb 	if (!ar->ab->hw_params->rxdma1_enable) {
830*a9655020SBjoern A. Zeeb 		ret = count;
831*a9655020SBjoern A. Zeeb 		goto exit;
832*a9655020SBjoern A. Zeeb 	}
833*a9655020SBjoern A. Zeeb 
834*a9655020SBjoern A. Zeeb 	if (ar->ah->state != ATH12K_HW_STATE_ON) {
835*a9655020SBjoern A. Zeeb 		ret = -ENETDOWN;
836*a9655020SBjoern A. Zeeb 		goto exit;
837*a9655020SBjoern A. Zeeb 	}
838*a9655020SBjoern A. Zeeb 
839*a9655020SBjoern A. Zeeb 	if (enable == ar->debug.extd_rx_stats) {
840*a9655020SBjoern A. Zeeb 		ret = count;
841*a9655020SBjoern A. Zeeb 		goto exit;
842*a9655020SBjoern A. Zeeb 	}
843*a9655020SBjoern A. Zeeb 
844*a9655020SBjoern A. Zeeb 	if (enable) {
845*a9655020SBjoern A. Zeeb 		rx_filter =  HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
846*a9655020SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
847*a9655020SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
848*a9655020SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
849*a9655020SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
850*a9655020SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
851*a9655020SBjoern A. Zeeb 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START_USER_INFO;
852*a9655020SBjoern A. Zeeb 
853*a9655020SBjoern A. Zeeb 		tlv_filter.rx_filter = rx_filter;
854*a9655020SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
855*a9655020SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
856*a9655020SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
857*a9655020SBjoern A. Zeeb 		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
858*a9655020SBjoern A. Zeeb 			HTT_RX_FP_DATA_FILTER_FLASG3;
859*a9655020SBjoern A. Zeeb 	} else {
860*a9655020SBjoern A. Zeeb 		tlv_filter = ath12k_mac_mon_status_filter_default;
861*a9655020SBjoern A. Zeeb 	}
862*a9655020SBjoern A. Zeeb 
863*a9655020SBjoern A. Zeeb 	ar->debug.rx_filter = tlv_filter.rx_filter;
864*a9655020SBjoern A. Zeeb 
865*a9655020SBjoern A. Zeeb 	for (i = 0; i < ar->ab->hw_params->num_rxdma_per_pdev; i++) {
866*a9655020SBjoern A. Zeeb 		ring_id = ar->dp.rxdma_mon_dst_ring[i].ring_id;
867*a9655020SBjoern A. Zeeb 		ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id + i,
868*a9655020SBjoern A. Zeeb 						       HAL_RXDMA_MONITOR_DST,
869*a9655020SBjoern A. Zeeb 						       DP_RXDMA_REFILL_RING_SIZE,
870*a9655020SBjoern A. Zeeb 						       &tlv_filter);
871*a9655020SBjoern A. Zeeb 		if (ret) {
872*a9655020SBjoern A. Zeeb 			ath12k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
873*a9655020SBjoern A. Zeeb 			goto exit;
874*a9655020SBjoern A. Zeeb 		}
875*a9655020SBjoern A. Zeeb 	}
876*a9655020SBjoern A. Zeeb 
877*a9655020SBjoern A. Zeeb 	ar->debug.extd_rx_stats = !!enable;
878*a9655020SBjoern A. Zeeb 	ret = count;
879*a9655020SBjoern A. Zeeb exit:
880*a9655020SBjoern A. Zeeb 	wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
881*a9655020SBjoern A. Zeeb 	return ret;
882*a9655020SBjoern A. Zeeb }
883*a9655020SBjoern A. Zeeb 
ath12k_read_extd_rx_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)884*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_extd_rx_stats(struct file *file,
885*a9655020SBjoern A. Zeeb 					 char __user *ubuf,
886*a9655020SBjoern A. Zeeb 					 size_t count, loff_t *ppos)
887*a9655020SBjoern A. Zeeb {
888*a9655020SBjoern A. Zeeb 	struct ath12k *ar = file->private_data;
889*a9655020SBjoern A. Zeeb 	char buf[32];
890*a9655020SBjoern A. Zeeb 	int len = 0;
891*a9655020SBjoern A. Zeeb 
892*a9655020SBjoern A. Zeeb 	wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
893*a9655020SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
894*a9655020SBjoern A. Zeeb 			ar->debug.extd_rx_stats);
895*a9655020SBjoern A. Zeeb 	wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
896*a9655020SBjoern A. Zeeb 
897*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
898*a9655020SBjoern A. Zeeb }
899*a9655020SBjoern A. Zeeb 
900*a9655020SBjoern A. Zeeb static const struct file_operations fops_extd_rx_stats = {
901*a9655020SBjoern A. Zeeb 	.read = ath12k_read_extd_rx_stats,
902*a9655020SBjoern A. Zeeb 	.write = ath12k_write_extd_rx_stats,
903*a9655020SBjoern A. Zeeb 	.open = simple_open,
904*a9655020SBjoern A. Zeeb };
905*a9655020SBjoern A. Zeeb 
ath12k_open_link_stats(struct inode * inode,struct file * file)906*a9655020SBjoern A. Zeeb static int ath12k_open_link_stats(struct inode *inode, struct file *file)
907*a9655020SBjoern A. Zeeb {
908*a9655020SBjoern A. Zeeb 	struct ath12k_vif *ahvif = inode->i_private;
909*a9655020SBjoern A. Zeeb 	size_t len = 0, buf_len = (PAGE_SIZE * 2);
910*a9655020SBjoern A. Zeeb 	struct ath12k_link_stats linkstat;
911*a9655020SBjoern A. Zeeb 	struct ath12k_link_vif *arvif;
912*a9655020SBjoern A. Zeeb 	unsigned long links_map;
913*a9655020SBjoern A. Zeeb 	struct wiphy *wiphy;
914*a9655020SBjoern A. Zeeb 	int link_id, i;
915*a9655020SBjoern A. Zeeb 	char *buf;
916*a9655020SBjoern A. Zeeb 
917*a9655020SBjoern A. Zeeb 	if (!ahvif)
918*a9655020SBjoern A. Zeeb 		return -EINVAL;
919*a9655020SBjoern A. Zeeb 
920*a9655020SBjoern A. Zeeb 	buf = kzalloc(buf_len, GFP_KERNEL);
921*a9655020SBjoern A. Zeeb 	if (!buf)
922*a9655020SBjoern A. Zeeb 		return -ENOMEM;
923*a9655020SBjoern A. Zeeb 
924*a9655020SBjoern A. Zeeb 	wiphy = ahvif->ah->hw->wiphy;
925*a9655020SBjoern A. Zeeb 	wiphy_lock(wiphy);
926*a9655020SBjoern A. Zeeb 
927*a9655020SBjoern A. Zeeb 	links_map = ahvif->links_map;
928*a9655020SBjoern A. Zeeb 	for_each_set_bit(link_id, &links_map,
929*a9655020SBjoern A. Zeeb 			 IEEE80211_MLD_MAX_NUM_LINKS) {
930*a9655020SBjoern A. Zeeb 		arvif = rcu_dereference_protected(ahvif->link[link_id],
931*a9655020SBjoern A. Zeeb 						  lockdep_is_held(&wiphy->mtx));
932*a9655020SBjoern A. Zeeb 
933*a9655020SBjoern A. Zeeb 		spin_lock_bh(&arvif->link_stats_lock);
934*a9655020SBjoern A. Zeeb 		linkstat = arvif->link_stats;
935*a9655020SBjoern A. Zeeb 		spin_unlock_bh(&arvif->link_stats_lock);
936*a9655020SBjoern A. Zeeb 
937*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
938*a9655020SBjoern A. Zeeb 				 "link[%d] Tx Unicast Frames Enqueued  = %d\n",
939*a9655020SBjoern A. Zeeb 				 link_id, linkstat.tx_enqueued);
940*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
941*a9655020SBjoern A. Zeeb 				 "link[%d] Tx Broadcast Frames Enqueued = %d\n",
942*a9655020SBjoern A. Zeeb 				 link_id, linkstat.tx_bcast_mcast);
943*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
944*a9655020SBjoern A. Zeeb 				 "link[%d] Tx Frames Completed = %d\n",
945*a9655020SBjoern A. Zeeb 				 link_id, linkstat.tx_completed);
946*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
947*a9655020SBjoern A. Zeeb 				 "link[%d] Tx Frames Dropped = %d\n",
948*a9655020SBjoern A. Zeeb 				 link_id, linkstat.tx_dropped);
949*a9655020SBjoern A. Zeeb 
950*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
951*a9655020SBjoern A. Zeeb 				 "link[%d] Tx Frame descriptor Encap Type = ",
952*a9655020SBjoern A. Zeeb 				 link_id);
953*a9655020SBjoern A. Zeeb 
954*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
955*a9655020SBjoern A. Zeeb 					 " raw:%d",
956*a9655020SBjoern A. Zeeb 					 linkstat.tx_encap_type[0]);
957*a9655020SBjoern A. Zeeb 
958*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
959*a9655020SBjoern A. Zeeb 					 " native_wifi:%d",
960*a9655020SBjoern A. Zeeb 					 linkstat.tx_encap_type[1]);
961*a9655020SBjoern A. Zeeb 
962*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
963*a9655020SBjoern A. Zeeb 					 " ethernet:%d",
964*a9655020SBjoern A. Zeeb 					 linkstat.tx_encap_type[2]);
965*a9655020SBjoern A. Zeeb 
966*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
967*a9655020SBjoern A. Zeeb 				 "\nlink[%d] Tx Frame descriptor Encrypt Type = ",
968*a9655020SBjoern A. Zeeb 				 link_id);
969*a9655020SBjoern A. Zeeb 
970*a9655020SBjoern A. Zeeb 		for (i = 0; i < HAL_ENCRYPT_TYPE_MAX; i++) {
971*a9655020SBjoern A. Zeeb 			len += scnprintf(buf + len, buf_len - len,
972*a9655020SBjoern A. Zeeb 					 " %d:%d", i,
973*a9655020SBjoern A. Zeeb 					 linkstat.tx_encrypt_type[i]);
974*a9655020SBjoern A. Zeeb 		}
975*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
976*a9655020SBjoern A. Zeeb 				 "\nlink[%d] Tx Frame descriptor Type = buffer:%d extension:%d\n",
977*a9655020SBjoern A. Zeeb 				 link_id, linkstat.tx_desc_type[0],
978*a9655020SBjoern A. Zeeb 				 linkstat.tx_desc_type[1]);
979*a9655020SBjoern A. Zeeb 
980*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
981*a9655020SBjoern A. Zeeb 				"------------------------------------------------------\n");
982*a9655020SBjoern A. Zeeb 	}
983*a9655020SBjoern A. Zeeb 
984*a9655020SBjoern A. Zeeb 	wiphy_unlock(wiphy);
985*a9655020SBjoern A. Zeeb 
986*a9655020SBjoern A. Zeeb 	file->private_data = buf;
987*a9655020SBjoern A. Zeeb 
988*a9655020SBjoern A. Zeeb 	return 0;
989*a9655020SBjoern A. Zeeb }
990*a9655020SBjoern A. Zeeb 
ath12k_release_link_stats(struct inode * inode,struct file * file)991*a9655020SBjoern A. Zeeb static int ath12k_release_link_stats(struct inode *inode, struct file *file)
992*a9655020SBjoern A. Zeeb {
993*a9655020SBjoern A. Zeeb 	kfree(file->private_data);
994*a9655020SBjoern A. Zeeb 	return 0;
995*a9655020SBjoern A. Zeeb }
996*a9655020SBjoern A. Zeeb 
ath12k_read_link_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)997*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_link_stats(struct file *file,
998*a9655020SBjoern A. Zeeb 				      char __user *user_buf,
999*a9655020SBjoern A. Zeeb 				      size_t count, loff_t *ppos)
1000*a9655020SBjoern A. Zeeb {
1001*a9655020SBjoern A. Zeeb 	const char *buf = file->private_data;
1002*a9655020SBjoern A. Zeeb 	size_t len = strlen(buf);
1003*a9655020SBjoern A. Zeeb 
1004*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1005*a9655020SBjoern A. Zeeb }
1006*a9655020SBjoern A. Zeeb 
1007*a9655020SBjoern A. Zeeb static const struct file_operations ath12k_fops_link_stats = {
1008*a9655020SBjoern A. Zeeb 	.open = ath12k_open_link_stats,
1009*a9655020SBjoern A. Zeeb 	.release = ath12k_release_link_stats,
1010*a9655020SBjoern A. Zeeb 	.read = ath12k_read_link_stats,
1011*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
1012*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
1013*a9655020SBjoern A. Zeeb };
1014*a9655020SBjoern A. Zeeb 
ath12k_debugfs_op_vif_add(struct ieee80211_hw * hw,struct ieee80211_vif * vif)1015*a9655020SBjoern A. Zeeb void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
1016*a9655020SBjoern A. Zeeb 			       struct ieee80211_vif *vif)
1017*a9655020SBjoern A. Zeeb {
1018*a9655020SBjoern A. Zeeb 	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
1019*a9655020SBjoern A. Zeeb 
1020*a9655020SBjoern A. Zeeb 	debugfs_create_file("link_stats", 0400, vif->debugfs_dir, ahvif,
1021*a9655020SBjoern A. Zeeb 			    &ath12k_fops_link_stats);
1022*a9655020SBjoern A. Zeeb }
1023*a9655020SBjoern A. Zeeb 
ath12k_debugfs_dump_device_dp_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1024*a9655020SBjoern A. Zeeb static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
1025*a9655020SBjoern A. Zeeb 						   char __user *user_buf,
1026*a9655020SBjoern A. Zeeb 						   size_t count, loff_t *ppos)
1027*a9655020SBjoern A. Zeeb {
1028*a9655020SBjoern A. Zeeb 	struct ath12k_base *ab = file->private_data;
1029*a9655020SBjoern A. Zeeb 	struct ath12k_device_dp_stats *device_stats = &ab->device_stats;
1030*a9655020SBjoern A. Zeeb 	int len = 0, i, j, ret;
1031*a9655020SBjoern A. Zeeb 	struct ath12k *ar;
1032*a9655020SBjoern A. Zeeb 	const int size = 4096;
1033*a9655020SBjoern A. Zeeb 	static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
1034*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR] = "Overflow",
1035*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR] = "MPDU len",
1036*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_FCS_ERR] = "FCS",
1037*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR] = "Decrypt",
1038*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR] = "TKIP MIC",
1039*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_UNECRYPTED_ERR] = "Unencrypt",
1040*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LEN_ERR] = "MSDU len",
1041*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LIMIT_ERR] = "MSDU limit",
1042*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_WIFI_PARSE_ERR] = "WiFi parse",
1043*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_PARSE_ERR] = "AMSDU parse",
1044*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_SA_TIMEOUT_ERR] = "SA timeout",
1045*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_DA_TIMEOUT_ERR] = "DA timeout",
1046*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_FLOW_TIMEOUT_ERR] = "Flow timeout",
1047*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR] = "Flush req",
1048*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_FRAG_ERR] = "AMSDU frag",
1049*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_MULTICAST_ECHO_ERR] = "Multicast echo",
1050*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_MISMATCH_ERR] = "AMSDU mismatch",
1051*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR] = "Unauth WDS",
1052*a9655020SBjoern A. Zeeb 		[HAL_REO_ENTR_RING_RXDMA_ECODE_GRPCAST_AMSDU_WDS_ERR] = "AMSDU or WDS"};
1053*a9655020SBjoern A. Zeeb 
1054*a9655020SBjoern A. Zeeb 	static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
1055*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO] = "Desc addr zero",
1056*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_DESC_INVALID] = "Desc inval",
1057*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_AMPDU_IN_NON_BA] =  "AMPDU in non BA",
1058*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_NON_BA_DUPLICATE] = "Non BA dup",
1059*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_BA_DUPLICATE] = "BA dup",
1060*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_FRAME_2K_JUMP] = "Frame 2k jump",
1061*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_BAR_2K_JUMP] = "BAR 2k jump",
1062*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_FRAME_OOR] = "Frame OOR",
1063*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_BAR_OOR] = "BAR OOR",
1064*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_NO_BA_SESSION] = "No BA session",
1065*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_FRAME_SN_EQUALS_SSN] = "Frame SN equal SSN",
1066*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED] = "PN check fail",
1067*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_2K_ERR_FLAG_SET] = "2k err",
1068*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET] = "PN err",
1069*a9655020SBjoern A. Zeeb 		[HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED] = "Desc blocked"};
1070*a9655020SBjoern A. Zeeb 
1071*a9655020SBjoern A. Zeeb 	static const char *wbm_rel_src[HAL_WBM_REL_SRC_MODULE_MAX] = {
1072*a9655020SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_TQM] = "TQM",
1073*a9655020SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_RXDMA] = "Rxdma",
1074*a9655020SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_REO] = "Reo",
1075*a9655020SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_FW] = "FW",
1076*a9655020SBjoern A. Zeeb 		[HAL_WBM_REL_SRC_MODULE_SW] = "SW"};
1077*a9655020SBjoern A. Zeeb 
1078*a9655020SBjoern A. Zeeb 	char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
1079*a9655020SBjoern A. Zeeb 
1080*a9655020SBjoern A. Zeeb 	if (!buf)
1081*a9655020SBjoern A. Zeeb 		return -ENOMEM;
1082*a9655020SBjoern A. Zeeb 
1083*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "DEVICE RX STATS:\n\n");
1084*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
1085*a9655020SBjoern A. Zeeb 			 device_stats->err_ring_pkts);
1086*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
1087*a9655020SBjoern A. Zeeb 			 device_stats->invalid_rbm);
1088*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
1089*a9655020SBjoern A. Zeeb 
1090*a9655020SBjoern A. Zeeb 	for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
1091*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "%s: %u\n",
1092*a9655020SBjoern A. Zeeb 				 rxdma_err[i], device_stats->rxdma_error[i]);
1093*a9655020SBjoern A. Zeeb 
1094*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nREO errors:\n");
1095*a9655020SBjoern A. Zeeb 
1096*a9655020SBjoern A. Zeeb 	for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
1097*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "%s: %u\n",
1098*a9655020SBjoern A. Zeeb 				 reo_err[i], device_stats->reo_error[i]);
1099*a9655020SBjoern A. Zeeb 
1100*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
1101*a9655020SBjoern A. Zeeb 
1102*a9655020SBjoern A. Zeeb 	for (i = 0; i < DP_REO_DST_RING_MAX; i++)
1103*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len,
1104*a9655020SBjoern A. Zeeb 				 "ring%d: %u\n", i,
1105*a9655020SBjoern A. Zeeb 				 device_stats->hal_reo_error[i]);
1106*a9655020SBjoern A. Zeeb 
1107*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nDEVICE TX STATS:\n");
1108*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
1109*a9655020SBjoern A. Zeeb 
1110*a9655020SBjoern A. Zeeb 	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
1111*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "ring%d: %u\n",
1112*a9655020SBjoern A. Zeeb 				 i, device_stats->tx_err.desc_na[i]);
1113*a9655020SBjoern A. Zeeb 
1114*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len,
1115*a9655020SBjoern A. Zeeb 			 "\nMisc Transmit Failures: %d\n",
1116*a9655020SBjoern A. Zeeb 			 atomic_read(&device_stats->tx_err.misc_fail));
1117*a9655020SBjoern A. Zeeb 
1118*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntx_wbm_rel_source:");
1119*a9655020SBjoern A. Zeeb 
1120*a9655020SBjoern A. Zeeb 	for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++)
1121*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
1122*a9655020SBjoern A. Zeeb 				 i, device_stats->tx_wbm_rel_source[i]);
1123*a9655020SBjoern A. Zeeb 
1124*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
1125*a9655020SBjoern A. Zeeb 
1126*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntqm_rel_reason:");
1127*a9655020SBjoern A. Zeeb 
1128*a9655020SBjoern A. Zeeb 	for (i = 0; i < MAX_TQM_RELEASE_REASON; i++)
1129*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
1130*a9655020SBjoern A. Zeeb 				 i, device_stats->tqm_rel_reason[i]);
1131*a9655020SBjoern A. Zeeb 
1132*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
1133*a9655020SBjoern A. Zeeb 
1134*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nfw_tx_status:");
1135*a9655020SBjoern A. Zeeb 
1136*a9655020SBjoern A. Zeeb 	for (i = 0; i < MAX_FW_TX_STATUS; i++)
1137*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
1138*a9655020SBjoern A. Zeeb 				 i, device_stats->fw_tx_status[i]);
1139*a9655020SBjoern A. Zeeb 
1140*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
1141*a9655020SBjoern A. Zeeb 
1142*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntx_enqueued:");
1143*a9655020SBjoern A. Zeeb 
1144*a9655020SBjoern A. Zeeb 	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
1145*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u", i,
1146*a9655020SBjoern A. Zeeb 				 device_stats->tx_enqueued[i]);
1147*a9655020SBjoern A. Zeeb 
1148*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
1149*a9655020SBjoern A. Zeeb 
1150*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\ntx_completed:");
1151*a9655020SBjoern A. Zeeb 
1152*a9655020SBjoern A. Zeeb 	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
1153*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, " %d:%u",
1154*a9655020SBjoern A. Zeeb 				 i, device_stats->tx_completed[i]);
1155*a9655020SBjoern A. Zeeb 
1156*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\n");
1157*a9655020SBjoern A. Zeeb 
1158*a9655020SBjoern A. Zeeb 	for (i = 0; i < ab->num_radios; i++) {
1159*a9655020SBjoern A. Zeeb 		ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i));
1160*a9655020SBjoern A. Zeeb 		if (ar) {
1161*a9655020SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
1162*a9655020SBjoern A. Zeeb 					"\nradio%d tx_pending: %u\n", i,
1163*a9655020SBjoern A. Zeeb 					atomic_read(&ar->dp.num_tx_pending));
1164*a9655020SBjoern A. Zeeb 		}
1165*a9655020SBjoern A. Zeeb 	}
1166*a9655020SBjoern A. Zeeb 
1167*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nREO Rx Received:\n");
1168*a9655020SBjoern A. Zeeb 
1169*a9655020SBjoern A. Zeeb 	for (i = 0; i < DP_REO_DST_RING_MAX; i++) {
1170*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "Ring%d:", i + 1);
1171*a9655020SBjoern A. Zeeb 
1172*a9655020SBjoern A. Zeeb 		for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
1173*a9655020SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
1174*a9655020SBjoern A. Zeeb 					"\t%d:%u", j,
1175*a9655020SBjoern A. Zeeb 					 device_stats->reo_rx[i][j]);
1176*a9655020SBjoern A. Zeeb 		}
1177*a9655020SBjoern A. Zeeb 
1178*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "\n");
1179*a9655020SBjoern A. Zeeb 	}
1180*a9655020SBjoern A. Zeeb 
1181*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nREO excep MSDU buf type:%u\n",
1182*a9655020SBjoern A. Zeeb 			 device_stats->reo_excep_msdu_buf_type);
1183*a9655020SBjoern A. Zeeb 
1184*a9655020SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len, "\nRx WBM REL SRC Errors:\n");
1185*a9655020SBjoern A. Zeeb 
1186*a9655020SBjoern A. Zeeb 	for (i = 0; i < HAL_WBM_REL_SRC_MODULE_MAX; i++) {
1187*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "%s:", wbm_rel_src[i]);
1188*a9655020SBjoern A. Zeeb 
1189*a9655020SBjoern A. Zeeb 		for (j = 0; j < ATH12K_MAX_DEVICES; j++) {
1190*a9655020SBjoern A. Zeeb 			len += scnprintf(buf + len,
1191*a9655020SBjoern A. Zeeb 					 size - len,
1192*a9655020SBjoern A. Zeeb 					 "\t%d:%u", j,
1193*a9655020SBjoern A. Zeeb 					 device_stats->rx_wbm_rel_source[i][j]);
1194*a9655020SBjoern A. Zeeb 		}
1195*a9655020SBjoern A. Zeeb 
1196*a9655020SBjoern A. Zeeb 		len += scnprintf(buf + len, size - len, "\n");
1197*a9655020SBjoern A. Zeeb 	}
1198*a9655020SBjoern A. Zeeb 
1199*a9655020SBjoern A. Zeeb 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1200*a9655020SBjoern A. Zeeb 
1201*a9655020SBjoern A. Zeeb 	return ret;
1202*a9655020SBjoern A. Zeeb }
1203*a9655020SBjoern A. Zeeb 
1204*a9655020SBjoern A. Zeeb static const struct file_operations fops_device_dp_stats = {
1205*a9655020SBjoern A. Zeeb 	.read = ath12k_debugfs_dump_device_dp_stats,
1206*a9655020SBjoern A. Zeeb 	.open = simple_open,
1207*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
1208*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
1209*a9655020SBjoern A. Zeeb };
1210*a9655020SBjoern A. Zeeb 
ath12k_debugfs_pdev_create(struct ath12k_base * ab)1211*a9655020SBjoern A. Zeeb void ath12k_debugfs_pdev_create(struct ath12k_base *ab)
1212*a9655020SBjoern A. Zeeb {
1213*a9655020SBjoern A. Zeeb 	debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
1214*a9655020SBjoern A. Zeeb 			    &fops_simulate_fw_crash);
1215*a9655020SBjoern A. Zeeb 
1216*a9655020SBjoern A. Zeeb 	debugfs_create_file("device_dp_stats", 0400, ab->debugfs_soc, ab,
1217*a9655020SBjoern A. Zeeb 			    &fops_device_dp_stats);
1218*a9655020SBjoern A. Zeeb }
1219*a9655020SBjoern A. Zeeb 
ath12k_debugfs_soc_create(struct ath12k_base * ab)1220*a9655020SBjoern A. Zeeb void ath12k_debugfs_soc_create(struct ath12k_base *ab)
1221*a9655020SBjoern A. Zeeb {
1222*a9655020SBjoern A. Zeeb 	bool dput_needed;
1223*a9655020SBjoern A. Zeeb 	char soc_name[64] = {};
1224*a9655020SBjoern A. Zeeb 	struct dentry *debugfs_ath12k;
1225*a9655020SBjoern A. Zeeb 
1226*a9655020SBjoern A. Zeeb 	debugfs_ath12k = debugfs_lookup("ath12k", NULL);
1227*a9655020SBjoern A. Zeeb 	if (debugfs_ath12k) {
1228*a9655020SBjoern A. Zeeb 		/* a dentry from lookup() needs dput() after we don't use it */
1229*a9655020SBjoern A. Zeeb 		dput_needed = true;
1230*a9655020SBjoern A. Zeeb 	} else {
1231*a9655020SBjoern A. Zeeb 		debugfs_ath12k = debugfs_create_dir("ath12k", NULL);
1232*a9655020SBjoern A. Zeeb 		if (IS_ERR_OR_NULL(debugfs_ath12k))
1233*a9655020SBjoern A. Zeeb 			return;
1234*a9655020SBjoern A. Zeeb 		dput_needed = false;
1235*a9655020SBjoern A. Zeeb 	}
1236*a9655020SBjoern A. Zeeb 
1237*a9655020SBjoern A. Zeeb 	scnprintf(soc_name, sizeof(soc_name), "%s-%s", ath12k_bus_str(ab->hif.bus),
1238*a9655020SBjoern A. Zeeb 		  dev_name(ab->dev));
1239*a9655020SBjoern A. Zeeb 
1240*a9655020SBjoern A. Zeeb 	ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath12k);
1241*a9655020SBjoern A. Zeeb 
1242*a9655020SBjoern A. Zeeb 	if (dput_needed)
1243*a9655020SBjoern A. Zeeb 		dput(debugfs_ath12k);
1244*a9655020SBjoern A. Zeeb }
1245*a9655020SBjoern A. Zeeb 
ath12k_debugfs_soc_destroy(struct ath12k_base * ab)1246*a9655020SBjoern A. Zeeb void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
1247*a9655020SBjoern A. Zeeb {
1248*a9655020SBjoern A. Zeeb 	debugfs_remove_recursive(ab->debugfs_soc);
1249*a9655020SBjoern A. Zeeb 	ab->debugfs_soc = NULL;
1250*a9655020SBjoern A. Zeeb 	/* We are not removing ath12k directory on purpose, even if it
1251*a9655020SBjoern A. Zeeb 	 * would be empty. This simplifies the directory handling and it's
1252*a9655020SBjoern A. Zeeb 	 * a minor cosmetic issue to leave an empty ath12k directory to
1253*a9655020SBjoern A. Zeeb 	 * debugfs.
1254*a9655020SBjoern A. Zeeb 	 */
1255*a9655020SBjoern A. Zeeb }
1256*a9655020SBjoern A. Zeeb 
ath12k_open_vdev_stats(struct inode * inode,struct file * file)1257*a9655020SBjoern A. Zeeb static int ath12k_open_vdev_stats(struct inode *inode, struct file *file)
1258*a9655020SBjoern A. Zeeb {
1259*a9655020SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
1260*a9655020SBjoern A. Zeeb 	struct ath12k_fw_stats_req_params param;
1261*a9655020SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
1262*a9655020SBjoern A. Zeeb 	int ret;
1263*a9655020SBjoern A. Zeeb 
1264*a9655020SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
1265*a9655020SBjoern A. Zeeb 
1266*a9655020SBjoern A. Zeeb 	if (!ah)
1267*a9655020SBjoern A. Zeeb 		return -ENETDOWN;
1268*a9655020SBjoern A. Zeeb 
1269*a9655020SBjoern A. Zeeb 	if (ah->state != ATH12K_HW_STATE_ON)
1270*a9655020SBjoern A. Zeeb 		return -ENETDOWN;
1271*a9655020SBjoern A. Zeeb 
1272*a9655020SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
1273*a9655020SBjoern A. Zeeb 	if (!buf)
1274*a9655020SBjoern A. Zeeb 		return -ENOMEM;
1275*a9655020SBjoern A. Zeeb 
1276*a9655020SBjoern A. Zeeb 	param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
1277*a9655020SBjoern A. Zeeb 	/* VDEV stats is always sent for all active VDEVs from FW */
1278*a9655020SBjoern A. Zeeb 	param.vdev_id = 0;
1279*a9655020SBjoern A. Zeeb 	param.stats_id = WMI_REQUEST_VDEV_STAT;
1280*a9655020SBjoern A. Zeeb 
1281*a9655020SBjoern A. Zeeb 	ret = ath12k_mac_get_fw_stats(ar, &param);
1282*a9655020SBjoern A. Zeeb 	if (ret) {
1283*a9655020SBjoern A. Zeeb 		ath12k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
1284*a9655020SBjoern A. Zeeb 		return ret;
1285*a9655020SBjoern A. Zeeb 	}
1286*a9655020SBjoern A. Zeeb 
1287*a9655020SBjoern A. Zeeb 	ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
1288*a9655020SBjoern A. Zeeb 				 buf);
1289*a9655020SBjoern A. Zeeb 	ath12k_fw_stats_reset(ar);
1290*a9655020SBjoern A. Zeeb 
1291*a9655020SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
1292*a9655020SBjoern A. Zeeb 
1293*a9655020SBjoern A. Zeeb 	return 0;
1294*a9655020SBjoern A. Zeeb }
1295*a9655020SBjoern A. Zeeb 
ath12k_release_vdev_stats(struct inode * inode,struct file * file)1296*a9655020SBjoern A. Zeeb static int ath12k_release_vdev_stats(struct inode *inode, struct file *file)
1297*a9655020SBjoern A. Zeeb {
1298*a9655020SBjoern A. Zeeb 	kfree(file->private_data);
1299*a9655020SBjoern A. Zeeb 
1300*a9655020SBjoern A. Zeeb 	return 0;
1301*a9655020SBjoern A. Zeeb }
1302*a9655020SBjoern A. Zeeb 
ath12k_read_vdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1303*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_vdev_stats(struct file *file,
1304*a9655020SBjoern A. Zeeb 				      char __user *user_buf,
1305*a9655020SBjoern A. Zeeb 				      size_t count, loff_t *ppos)
1306*a9655020SBjoern A. Zeeb {
1307*a9655020SBjoern A. Zeeb 	const char *buf = file->private_data;
1308*a9655020SBjoern A. Zeeb 	size_t len = strlen(buf);
1309*a9655020SBjoern A. Zeeb 
1310*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1311*a9655020SBjoern A. Zeeb }
1312*a9655020SBjoern A. Zeeb 
1313*a9655020SBjoern A. Zeeb static const struct file_operations fops_vdev_stats = {
1314*a9655020SBjoern A. Zeeb 	.open = ath12k_open_vdev_stats,
1315*a9655020SBjoern A. Zeeb 	.release = ath12k_release_vdev_stats,
1316*a9655020SBjoern A. Zeeb 	.read = ath12k_read_vdev_stats,
1317*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
1318*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
1319*a9655020SBjoern A. Zeeb };
1320*a9655020SBjoern A. Zeeb 
ath12k_open_bcn_stats(struct inode * inode,struct file * file)1321*a9655020SBjoern A. Zeeb static int ath12k_open_bcn_stats(struct inode *inode, struct file *file)
1322*a9655020SBjoern A. Zeeb {
1323*a9655020SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
1324*a9655020SBjoern A. Zeeb 	struct ath12k_link_vif *arvif;
1325*a9655020SBjoern A. Zeeb 	struct ath12k_fw_stats_req_params param;
1326*a9655020SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
1327*a9655020SBjoern A. Zeeb 	int ret;
1328*a9655020SBjoern A. Zeeb 
1329*a9655020SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
1330*a9655020SBjoern A. Zeeb 
1331*a9655020SBjoern A. Zeeb 	if (ah && ah->state != ATH12K_HW_STATE_ON)
1332*a9655020SBjoern A. Zeeb 		return -ENETDOWN;
1333*a9655020SBjoern A. Zeeb 
1334*a9655020SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
1335*a9655020SBjoern A. Zeeb 	if (!buf)
1336*a9655020SBjoern A. Zeeb 		return -ENOMEM;
1337*a9655020SBjoern A. Zeeb 
1338*a9655020SBjoern A. Zeeb 	param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
1339*a9655020SBjoern A. Zeeb 	param.stats_id = WMI_REQUEST_BCN_STAT;
1340*a9655020SBjoern A. Zeeb 
1341*a9655020SBjoern A. Zeeb 	/* loop all active VDEVs for bcn stats */
1342*a9655020SBjoern A. Zeeb 	list_for_each_entry(arvif, &ar->arvifs, list) {
1343*a9655020SBjoern A. Zeeb 		if (!arvif->is_up)
1344*a9655020SBjoern A. Zeeb 			continue;
1345*a9655020SBjoern A. Zeeb 
1346*a9655020SBjoern A. Zeeb 		param.vdev_id = arvif->vdev_id;
1347*a9655020SBjoern A. Zeeb 		ret = ath12k_mac_get_fw_stats(ar, &param);
1348*a9655020SBjoern A. Zeeb 		if (ret) {
1349*a9655020SBjoern A. Zeeb 			ath12k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
1350*a9655020SBjoern A. Zeeb 			return ret;
1351*a9655020SBjoern A. Zeeb 		}
1352*a9655020SBjoern A. Zeeb 	}
1353*a9655020SBjoern A. Zeeb 
1354*a9655020SBjoern A. Zeeb 	ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
1355*a9655020SBjoern A. Zeeb 				 buf);
1356*a9655020SBjoern A. Zeeb 	ath12k_fw_stats_reset(ar);
1357*a9655020SBjoern A. Zeeb 
1358*a9655020SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
1359*a9655020SBjoern A. Zeeb 
1360*a9655020SBjoern A. Zeeb 	return 0;
1361*a9655020SBjoern A. Zeeb }
1362*a9655020SBjoern A. Zeeb 
ath12k_release_bcn_stats(struct inode * inode,struct file * file)1363*a9655020SBjoern A. Zeeb static int ath12k_release_bcn_stats(struct inode *inode, struct file *file)
1364*a9655020SBjoern A. Zeeb {
1365*a9655020SBjoern A. Zeeb 	kfree(file->private_data);
1366*a9655020SBjoern A. Zeeb 
1367*a9655020SBjoern A. Zeeb 	return 0;
1368*a9655020SBjoern A. Zeeb }
1369*a9655020SBjoern A. Zeeb 
ath12k_read_bcn_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1370*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_bcn_stats(struct file *file,
1371*a9655020SBjoern A. Zeeb 				     char __user *user_buf,
1372*a9655020SBjoern A. Zeeb 				     size_t count, loff_t *ppos)
1373*a9655020SBjoern A. Zeeb {
1374*a9655020SBjoern A. Zeeb 	const char *buf = file->private_data;
1375*a9655020SBjoern A. Zeeb 	size_t len = strlen(buf);
1376*a9655020SBjoern A. Zeeb 
1377*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1378*a9655020SBjoern A. Zeeb }
1379*a9655020SBjoern A. Zeeb 
1380*a9655020SBjoern A. Zeeb static const struct file_operations fops_bcn_stats = {
1381*a9655020SBjoern A. Zeeb 	.open = ath12k_open_bcn_stats,
1382*a9655020SBjoern A. Zeeb 	.release = ath12k_release_bcn_stats,
1383*a9655020SBjoern A. Zeeb 	.read = ath12k_read_bcn_stats,
1384*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
1385*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
1386*a9655020SBjoern A. Zeeb };
1387*a9655020SBjoern A. Zeeb 
ath12k_open_pdev_stats(struct inode * inode,struct file * file)1388*a9655020SBjoern A. Zeeb static int ath12k_open_pdev_stats(struct inode *inode, struct file *file)
1389*a9655020SBjoern A. Zeeb {
1390*a9655020SBjoern A. Zeeb 	struct ath12k *ar = inode->i_private;
1391*a9655020SBjoern A. Zeeb 	struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
1392*a9655020SBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
1393*a9655020SBjoern A. Zeeb 	struct ath12k_fw_stats_req_params param;
1394*a9655020SBjoern A. Zeeb 	int ret;
1395*a9655020SBjoern A. Zeeb 
1396*a9655020SBjoern A. Zeeb 	guard(wiphy)(ath12k_ar_to_hw(ar)->wiphy);
1397*a9655020SBjoern A. Zeeb 
1398*a9655020SBjoern A. Zeeb 	if (ah && ah->state != ATH12K_HW_STATE_ON)
1399*a9655020SBjoern A. Zeeb 		return -ENETDOWN;
1400*a9655020SBjoern A. Zeeb 
1401*a9655020SBjoern A. Zeeb 	void *buf __free(kfree) = kzalloc(ATH12K_FW_STATS_BUF_SIZE, GFP_ATOMIC);
1402*a9655020SBjoern A. Zeeb 	if (!buf)
1403*a9655020SBjoern A. Zeeb 		return -ENOMEM;
1404*a9655020SBjoern A. Zeeb 
1405*a9655020SBjoern A. Zeeb 	param.pdev_id = ath12k_mac_get_target_pdev_id(ar);
1406*a9655020SBjoern A. Zeeb 	param.vdev_id = 0;
1407*a9655020SBjoern A. Zeeb 	param.stats_id = WMI_REQUEST_PDEV_STAT;
1408*a9655020SBjoern A. Zeeb 
1409*a9655020SBjoern A. Zeeb 	ret = ath12k_mac_get_fw_stats(ar, &param);
1410*a9655020SBjoern A. Zeeb 	if (ret) {
1411*a9655020SBjoern A. Zeeb 		ath12k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
1412*a9655020SBjoern A. Zeeb 		return ret;
1413*a9655020SBjoern A. Zeeb 	}
1414*a9655020SBjoern A. Zeeb 
1415*a9655020SBjoern A. Zeeb 	ath12k_wmi_fw_stats_dump(ar, &ar->fw_stats, param.stats_id,
1416*a9655020SBjoern A. Zeeb 				 buf);
1417*a9655020SBjoern A. Zeeb 	ath12k_fw_stats_reset(ar);
1418*a9655020SBjoern A. Zeeb 
1419*a9655020SBjoern A. Zeeb 	file->private_data = no_free_ptr(buf);
1420*a9655020SBjoern A. Zeeb 
1421*a9655020SBjoern A. Zeeb 	return 0;
1422*a9655020SBjoern A. Zeeb }
1423*a9655020SBjoern A. Zeeb 
ath12k_release_pdev_stats(struct inode * inode,struct file * file)1424*a9655020SBjoern A. Zeeb static int ath12k_release_pdev_stats(struct inode *inode, struct file *file)
1425*a9655020SBjoern A. Zeeb {
1426*a9655020SBjoern A. Zeeb 	kfree(file->private_data);
1427*a9655020SBjoern A. Zeeb 
1428*a9655020SBjoern A. Zeeb 	return 0;
1429*a9655020SBjoern A. Zeeb }
1430*a9655020SBjoern A. Zeeb 
ath12k_read_pdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1431*a9655020SBjoern A. Zeeb static ssize_t ath12k_read_pdev_stats(struct file *file,
1432*a9655020SBjoern A. Zeeb 				      char __user *user_buf,
1433*a9655020SBjoern A. Zeeb 				      size_t count, loff_t *ppos)
1434*a9655020SBjoern A. Zeeb {
1435*a9655020SBjoern A. Zeeb 	const char *buf = file->private_data;
1436*a9655020SBjoern A. Zeeb 	size_t len = strlen(buf);
1437*a9655020SBjoern A. Zeeb 
1438*a9655020SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1439*a9655020SBjoern A. Zeeb }
1440*a9655020SBjoern A. Zeeb 
1441*a9655020SBjoern A. Zeeb static const struct file_operations fops_pdev_stats = {
1442*a9655020SBjoern A. Zeeb 	.open = ath12k_open_pdev_stats,
1443*a9655020SBjoern A. Zeeb 	.release = ath12k_release_pdev_stats,
1444*a9655020SBjoern A. Zeeb 	.read = ath12k_read_pdev_stats,
1445*a9655020SBjoern A. Zeeb 	.owner = THIS_MODULE,
1446*a9655020SBjoern A. Zeeb 	.llseek = default_llseek,
1447*a9655020SBjoern A. Zeeb };
1448*a9655020SBjoern A. Zeeb 
1449*a9655020SBjoern A. Zeeb static
ath12k_debugfs_fw_stats_register(struct ath12k * ar)1450*a9655020SBjoern A. Zeeb void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
1451*a9655020SBjoern A. Zeeb {
1452*a9655020SBjoern A. Zeeb 	struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
1453*a9655020SBjoern A. Zeeb 							ar->debug.debugfs_pdev);
1454*a9655020SBjoern A. Zeeb 
1455*a9655020SBjoern A. Zeeb 	/* all stats debugfs files created are under "fw_stats" directory
1456*a9655020SBjoern A. Zeeb 	 * created per PDEV
1457*a9655020SBjoern A. Zeeb 	 */
1458*a9655020SBjoern A. Zeeb 	debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
1459*a9655020SBjoern A. Zeeb 			    &fops_vdev_stats);
1460*a9655020SBjoern A. Zeeb 	debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
1461*a9655020SBjoern A. Zeeb 			    &fops_bcn_stats);
1462*a9655020SBjoern A. Zeeb 	debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
1463*a9655020SBjoern A. Zeeb 			    &fops_pdev_stats);
1464*a9655020SBjoern A. Zeeb 
1465*a9655020SBjoern A. Zeeb 	ath12k_fw_stats_init(ar);
1466*a9655020SBjoern A. Zeeb }
1467*a9655020SBjoern A. Zeeb 
ath12k_debugfs_register(struct ath12k * ar)1468*a9655020SBjoern A. Zeeb void ath12k_debugfs_register(struct ath12k *ar)
1469*a9655020SBjoern A. Zeeb {
1470*a9655020SBjoern A. Zeeb 	struct ath12k_base *ab = ar->ab;
1471*a9655020SBjoern A. Zeeb 	struct ieee80211_hw *hw = ar->ah->hw;
1472*a9655020SBjoern A. Zeeb 	char pdev_name[5];
1473*a9655020SBjoern A. Zeeb 	char buf[100] = {};
1474*a9655020SBjoern A. Zeeb 
1475*a9655020SBjoern A. Zeeb 	scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
1476*a9655020SBjoern A. Zeeb 
1477*a9655020SBjoern A. Zeeb 	ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
1478*a9655020SBjoern A. Zeeb 
1479*a9655020SBjoern A. Zeeb 	/* Create a symlink under ieee80211/phy* */
1480*a9655020SBjoern A. Zeeb 	scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev);
1481*a9655020SBjoern A. Zeeb 	ar->debug.debugfs_pdev_symlink = debugfs_create_symlink("ath12k",
1482*a9655020SBjoern A. Zeeb 								hw->wiphy->debugfsdir,
1483*a9655020SBjoern A. Zeeb 								buf);
1484*a9655020SBjoern A. Zeeb 
1485*a9655020SBjoern A. Zeeb 	if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) {
1486*a9655020SBjoern A. Zeeb 		debugfs_create_file("dfs_simulate_radar", 0200,
1487*a9655020SBjoern A. Zeeb 				    ar->debug.debugfs_pdev, ar,
1488*a9655020SBjoern A. Zeeb 				    &fops_simulate_radar);
1489*a9655020SBjoern A. Zeeb 	}
1490*a9655020SBjoern A. Zeeb 
1491*a9655020SBjoern A. Zeeb 	debugfs_create_file("tpc_stats", 0400, ar->debug.debugfs_pdev, ar,
1492*a9655020SBjoern A. Zeeb 			    &fops_tpc_stats);
1493*a9655020SBjoern A. Zeeb 	debugfs_create_file("tpc_stats_type", 0200, ar->debug.debugfs_pdev,
1494*a9655020SBjoern A. Zeeb 			    ar, &fops_tpc_stats_type);
1495*a9655020SBjoern A. Zeeb 	init_completion(&ar->debug.tpc_complete);
1496*a9655020SBjoern A. Zeeb 
1497*a9655020SBjoern A. Zeeb 	ath12k_debugfs_htt_stats_register(ar);
1498*a9655020SBjoern A. Zeeb 	ath12k_debugfs_fw_stats_register(ar);
1499*a9655020SBjoern A. Zeeb 
1500*a9655020SBjoern A. Zeeb 	debugfs_create_file("ext_rx_stats", 0644,
1501*a9655020SBjoern A. Zeeb 			    ar->debug.debugfs_pdev, ar,
1502*a9655020SBjoern A. Zeeb 			    &fops_extd_rx_stats);
1503*a9655020SBjoern A. Zeeb }
1504*a9655020SBjoern A. Zeeb 
ath12k_debugfs_unregister(struct ath12k * ar)1505*a9655020SBjoern A. Zeeb void ath12k_debugfs_unregister(struct ath12k *ar)
1506*a9655020SBjoern A. Zeeb {
1507*a9655020SBjoern A. Zeeb 	if (!ar->debug.debugfs_pdev)
1508*a9655020SBjoern A. Zeeb 		return;
1509*a9655020SBjoern A. Zeeb 
1510*a9655020SBjoern A. Zeeb 	/* Remove symlink under ieee80211/phy* */
1511*a9655020SBjoern A. Zeeb 	debugfs_remove(ar->debug.debugfs_pdev_symlink);
1512*a9655020SBjoern A. Zeeb 	debugfs_remove_recursive(ar->debug.debugfs_pdev);
1513*a9655020SBjoern A. Zeeb 	ar->debug.debugfs_pdev_symlink = NULL;
1514*a9655020SBjoern A. Zeeb 	ar->debug.debugfs_pdev = NULL;
1515*a9655020SBjoern A. Zeeb }
1516