1da8fa4e3SBjoern A. Zeeb // SPDX-License-Identifier: ISC
2da8fa4e3SBjoern A. Zeeb /*
3da8fa4e3SBjoern A. Zeeb  * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
4da8fa4e3SBjoern A. Zeeb  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
5da8fa4e3SBjoern A. Zeeb  */
6da8fa4e3SBjoern A. Zeeb 
7da8fa4e3SBjoern A. Zeeb #include "core.h"
8da8fa4e3SBjoern A. Zeeb #include "wmi-ops.h"
9da8fa4e3SBjoern A. Zeeb #include "txrx.h"
10da8fa4e3SBjoern A. Zeeb #include "debug.h"
11da8fa4e3SBjoern A. Zeeb 
ath10k_rx_stats_update_amsdu_subfrm(struct ath10k * ar,struct ath10k_sta_tid_stats * stats,u32 msdu_count)12da8fa4e3SBjoern A. Zeeb static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
13da8fa4e3SBjoern A. Zeeb 						struct ath10k_sta_tid_stats *stats,
14da8fa4e3SBjoern A. Zeeb 						u32 msdu_count)
15da8fa4e3SBjoern A. Zeeb {
16da8fa4e3SBjoern A. Zeeb 	if (msdu_count == 1)
17da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
18da8fa4e3SBjoern A. Zeeb 	else if (msdu_count == 2)
19da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
20da8fa4e3SBjoern A. Zeeb 	else if (msdu_count == 3)
21da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
22da8fa4e3SBjoern A. Zeeb 	else if (msdu_count == 4)
23da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
24da8fa4e3SBjoern A. Zeeb 	else if (msdu_count > 4)
25da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
26da8fa4e3SBjoern A. Zeeb }
27da8fa4e3SBjoern A. Zeeb 
ath10k_rx_stats_update_ampdu_subfrm(struct ath10k * ar,struct ath10k_sta_tid_stats * stats,u32 mpdu_count)28da8fa4e3SBjoern A. Zeeb static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
29da8fa4e3SBjoern A. Zeeb 						struct ath10k_sta_tid_stats *stats,
30da8fa4e3SBjoern A. Zeeb 						u32 mpdu_count)
31da8fa4e3SBjoern A. Zeeb {
32da8fa4e3SBjoern A. Zeeb 	if (mpdu_count <= 10)
33da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
34da8fa4e3SBjoern A. Zeeb 	else if (mpdu_count <= 20)
35da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
36da8fa4e3SBjoern A. Zeeb 	else if (mpdu_count <= 30)
37da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
38da8fa4e3SBjoern A. Zeeb 	else if (mpdu_count <= 40)
39da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
40da8fa4e3SBjoern A. Zeeb 	else if (mpdu_count <= 50)
41da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
42da8fa4e3SBjoern A. Zeeb 	else if (mpdu_count <= 60)
43da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
44da8fa4e3SBjoern A. Zeeb 	else if (mpdu_count > 60)
45da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
46da8fa4e3SBjoern A. Zeeb }
47da8fa4e3SBjoern A. Zeeb 
ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k * ar,u16 peer_id,u8 tid,struct htt_rx_indication_mpdu_range * ranges,int num_ranges)48da8fa4e3SBjoern A. Zeeb void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
49da8fa4e3SBjoern A. Zeeb 					  struct htt_rx_indication_mpdu_range *ranges,
50da8fa4e3SBjoern A. Zeeb 					  int num_ranges)
51da8fa4e3SBjoern A. Zeeb {
52da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta;
53da8fa4e3SBjoern A. Zeeb 	struct ath10k_peer *peer;
54da8fa4e3SBjoern A. Zeeb 	int i;
55da8fa4e3SBjoern A. Zeeb 
56da8fa4e3SBjoern A. Zeeb 	if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
57da8fa4e3SBjoern A. Zeeb 		return;
58da8fa4e3SBjoern A. Zeeb 
59da8fa4e3SBjoern A. Zeeb 	rcu_read_lock();
60da8fa4e3SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
61da8fa4e3SBjoern A. Zeeb 
62da8fa4e3SBjoern A. Zeeb 	peer = ath10k_peer_find_by_id(ar, peer_id);
63da8fa4e3SBjoern A. Zeeb 	if (!peer || !peer->sta)
64da8fa4e3SBjoern A. Zeeb 		goto out;
65da8fa4e3SBjoern A. Zeeb 
66da8fa4e3SBjoern A. Zeeb 	arsta = (struct ath10k_sta *)peer->sta->drv_priv;
67da8fa4e3SBjoern A. Zeeb 
68da8fa4e3SBjoern A. Zeeb 	for (i = 0; i < num_ranges; i++)
69da8fa4e3SBjoern A. Zeeb 		ath10k_rx_stats_update_ampdu_subfrm(ar,
70da8fa4e3SBjoern A. Zeeb 						    &arsta->tid_stats[tid],
71da8fa4e3SBjoern A. Zeeb 						    ranges[i].mpdu_count);
72da8fa4e3SBjoern A. Zeeb 
73da8fa4e3SBjoern A. Zeeb out:
74da8fa4e3SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
75da8fa4e3SBjoern A. Zeeb 	rcu_read_unlock();
76da8fa4e3SBjoern A. Zeeb }
77da8fa4e3SBjoern A. Zeeb 
ath10k_sta_update_rx_tid_stats(struct ath10k * ar,u8 * first_hdr,unsigned long num_msdus,enum ath10k_pkt_rx_err err,unsigned long unchain_cnt,unsigned long drop_cnt,unsigned long drop_cnt_filter,unsigned long queued_msdus)78da8fa4e3SBjoern A. Zeeb void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
79da8fa4e3SBjoern A. Zeeb 				    unsigned long num_msdus,
80da8fa4e3SBjoern A. Zeeb 				    enum ath10k_pkt_rx_err err,
81da8fa4e3SBjoern A. Zeeb 				    unsigned long unchain_cnt,
82da8fa4e3SBjoern A. Zeeb 				    unsigned long drop_cnt,
83da8fa4e3SBjoern A. Zeeb 				    unsigned long drop_cnt_filter,
84da8fa4e3SBjoern A. Zeeb 				    unsigned long queued_msdus)
85da8fa4e3SBjoern A. Zeeb {
86da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta;
87da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta;
88da8fa4e3SBjoern A. Zeeb 	struct ieee80211_hdr *hdr;
89da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta_tid_stats *stats;
90da8fa4e3SBjoern A. Zeeb 	u8 tid = IEEE80211_NUM_TIDS;
91da8fa4e3SBjoern A. Zeeb 	bool non_data_frm = false;
92da8fa4e3SBjoern A. Zeeb 
93da8fa4e3SBjoern A. Zeeb 	hdr = (struct ieee80211_hdr *)first_hdr;
94da8fa4e3SBjoern A. Zeeb 	if (!ieee80211_is_data(hdr->frame_control))
95da8fa4e3SBjoern A. Zeeb 		non_data_frm = true;
96da8fa4e3SBjoern A. Zeeb 
97da8fa4e3SBjoern A. Zeeb 	if (ieee80211_is_data_qos(hdr->frame_control))
98da8fa4e3SBjoern A. Zeeb 		tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
99da8fa4e3SBjoern A. Zeeb 
100da8fa4e3SBjoern A. Zeeb 	if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
101da8fa4e3SBjoern A. Zeeb 		return;
102da8fa4e3SBjoern A. Zeeb 
103da8fa4e3SBjoern A. Zeeb 	rcu_read_lock();
104da8fa4e3SBjoern A. Zeeb 
105da8fa4e3SBjoern A. Zeeb 	sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
106da8fa4e3SBjoern A. Zeeb 	if (!sta)
107da8fa4e3SBjoern A. Zeeb 		goto exit;
108da8fa4e3SBjoern A. Zeeb 
109da8fa4e3SBjoern A. Zeeb 	arsta = (struct ath10k_sta *)sta->drv_priv;
110da8fa4e3SBjoern A. Zeeb 
111da8fa4e3SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
112da8fa4e3SBjoern A. Zeeb 	stats = &arsta->tid_stats[tid];
113da8fa4e3SBjoern A. Zeeb 	stats->rx_pkt_from_fw += num_msdus;
114da8fa4e3SBjoern A. Zeeb 	stats->rx_pkt_unchained += unchain_cnt;
115da8fa4e3SBjoern A. Zeeb 	stats->rx_pkt_drop_chained += drop_cnt;
116da8fa4e3SBjoern A. Zeeb 	stats->rx_pkt_drop_filter += drop_cnt_filter;
117da8fa4e3SBjoern A. Zeeb 	if (err != ATH10K_PKT_RX_ERR_MAX)
118da8fa4e3SBjoern A. Zeeb 		stats->rx_pkt_err[err] += queued_msdus;
119da8fa4e3SBjoern A. Zeeb 	stats->rx_pkt_queued_for_mac += queued_msdus;
120da8fa4e3SBjoern A. Zeeb 	ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
121da8fa4e3SBjoern A. Zeeb 					    num_msdus);
122da8fa4e3SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
123da8fa4e3SBjoern A. Zeeb 
124da8fa4e3SBjoern A. Zeeb exit:
125da8fa4e3SBjoern A. Zeeb 	rcu_read_unlock();
126da8fa4e3SBjoern A. Zeeb }
127da8fa4e3SBjoern A. Zeeb 
ath10k_sta_update_extd_stats_rx_duration(struct ath10k * ar,struct ath10k_fw_stats * stats)128da8fa4e3SBjoern A. Zeeb static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
129da8fa4e3SBjoern A. Zeeb 						     struct ath10k_fw_stats *stats)
130da8fa4e3SBjoern A. Zeeb {
131da8fa4e3SBjoern A. Zeeb 	struct ath10k_fw_extd_stats_peer *peer;
132da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta;
133da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta;
134da8fa4e3SBjoern A. Zeeb 
135da8fa4e3SBjoern A. Zeeb 	rcu_read_lock();
136da8fa4e3SBjoern A. Zeeb 	list_for_each_entry(peer, &stats->peers_extd, list) {
137da8fa4e3SBjoern A. Zeeb 		sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
138da8fa4e3SBjoern A. Zeeb 						   NULL);
139da8fa4e3SBjoern A. Zeeb 		if (!sta)
140da8fa4e3SBjoern A. Zeeb 			continue;
141da8fa4e3SBjoern A. Zeeb 		arsta = (struct ath10k_sta *)sta->drv_priv;
142da8fa4e3SBjoern A. Zeeb 		arsta->rx_duration += (u64)peer->rx_duration;
143da8fa4e3SBjoern A. Zeeb 	}
144da8fa4e3SBjoern A. Zeeb 	rcu_read_unlock();
145da8fa4e3SBjoern A. Zeeb }
146da8fa4e3SBjoern A. Zeeb 
ath10k_sta_update_stats_rx_duration(struct ath10k * ar,struct ath10k_fw_stats * stats)147da8fa4e3SBjoern A. Zeeb static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
148da8fa4e3SBjoern A. Zeeb 						struct ath10k_fw_stats *stats)
149da8fa4e3SBjoern A. Zeeb {
150da8fa4e3SBjoern A. Zeeb 	struct ath10k_fw_stats_peer *peer;
151da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta;
152da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta;
153da8fa4e3SBjoern A. Zeeb 
154da8fa4e3SBjoern A. Zeeb 	rcu_read_lock();
155da8fa4e3SBjoern A. Zeeb 	list_for_each_entry(peer, &stats->peers, list) {
156da8fa4e3SBjoern A. Zeeb 		sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
157da8fa4e3SBjoern A. Zeeb 						   NULL);
158da8fa4e3SBjoern A. Zeeb 		if (!sta)
159da8fa4e3SBjoern A. Zeeb 			continue;
160da8fa4e3SBjoern A. Zeeb 		arsta = (struct ath10k_sta *)sta->drv_priv;
161da8fa4e3SBjoern A. Zeeb 		arsta->rx_duration += (u64)peer->rx_duration;
162da8fa4e3SBjoern A. Zeeb 	}
163da8fa4e3SBjoern A. Zeeb 	rcu_read_unlock();
164da8fa4e3SBjoern A. Zeeb }
165da8fa4e3SBjoern A. Zeeb 
ath10k_sta_update_rx_duration(struct ath10k * ar,struct ath10k_fw_stats * stats)166da8fa4e3SBjoern A. Zeeb void ath10k_sta_update_rx_duration(struct ath10k *ar,
167da8fa4e3SBjoern A. Zeeb 				   struct ath10k_fw_stats *stats)
168da8fa4e3SBjoern A. Zeeb {
169da8fa4e3SBjoern A. Zeeb 	if (stats->extended)
170da8fa4e3SBjoern A. Zeeb 		ath10k_sta_update_extd_stats_rx_duration(ar, stats);
171da8fa4e3SBjoern A. Zeeb 	else
172da8fa4e3SBjoern A. Zeeb 		ath10k_sta_update_stats_rx_duration(ar, stats);
173da8fa4e3SBjoern A. Zeeb }
174da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_read_aggr_mode(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)175da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
176da8fa4e3SBjoern A. Zeeb 					     char __user *user_buf,
177da8fa4e3SBjoern A. Zeeb 					     size_t count, loff_t *ppos)
178da8fa4e3SBjoern A. Zeeb {
179da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
180da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
181da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
182da8fa4e3SBjoern A. Zeeb 	char buf[32];
183da8fa4e3SBjoern A. Zeeb 	int len = 0;
184da8fa4e3SBjoern A. Zeeb 
185da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
186da8fa4e3SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
187da8fa4e3SBjoern A. Zeeb 			(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
188da8fa4e3SBjoern A. Zeeb 			"auto" : "manual");
189da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
190da8fa4e3SBjoern A. Zeeb 
191da8fa4e3SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
192da8fa4e3SBjoern A. Zeeb }
193da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_write_aggr_mode(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)194da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
195da8fa4e3SBjoern A. Zeeb 					      const char __user *user_buf,
196da8fa4e3SBjoern A. Zeeb 					      size_t count, loff_t *ppos)
197da8fa4e3SBjoern A. Zeeb {
198da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
199da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
200da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
201da8fa4e3SBjoern A. Zeeb 	u32 aggr_mode;
202da8fa4e3SBjoern A. Zeeb 	int ret;
203da8fa4e3SBjoern A. Zeeb 
204da8fa4e3SBjoern A. Zeeb 	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
205da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
206da8fa4e3SBjoern A. Zeeb 
207da8fa4e3SBjoern A. Zeeb 	if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
208da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
209da8fa4e3SBjoern A. Zeeb 
210da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
211da8fa4e3SBjoern A. Zeeb 	if ((ar->state != ATH10K_STATE_ON) ||
212da8fa4e3SBjoern A. Zeeb 	    (aggr_mode == arsta->aggr_mode)) {
213da8fa4e3SBjoern A. Zeeb 		ret = count;
214da8fa4e3SBjoern A. Zeeb 		goto out;
215da8fa4e3SBjoern A. Zeeb 	}
216da8fa4e3SBjoern A. Zeeb 
217da8fa4e3SBjoern A. Zeeb 	ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
218da8fa4e3SBjoern A. Zeeb 	if (ret) {
219da8fa4e3SBjoern A. Zeeb 		ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
220da8fa4e3SBjoern A. Zeeb 		goto out;
221da8fa4e3SBjoern A. Zeeb 	}
222da8fa4e3SBjoern A. Zeeb 
223da8fa4e3SBjoern A. Zeeb 	arsta->aggr_mode = aggr_mode;
224da8fa4e3SBjoern A. Zeeb out:
225da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
226da8fa4e3SBjoern A. Zeeb 	return ret;
227da8fa4e3SBjoern A. Zeeb }
228da8fa4e3SBjoern A. Zeeb 
229da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_aggr_mode = {
230da8fa4e3SBjoern A. Zeeb 	.read = ath10k_dbg_sta_read_aggr_mode,
231da8fa4e3SBjoern A. Zeeb 	.write = ath10k_dbg_sta_write_aggr_mode,
232da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
233da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
234da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
235da8fa4e3SBjoern A. Zeeb };
236da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_write_addba(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)237da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
238da8fa4e3SBjoern A. Zeeb 					  const char __user *user_buf,
239da8fa4e3SBjoern A. Zeeb 					  size_t count, loff_t *ppos)
240da8fa4e3SBjoern A. Zeeb {
241da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
242da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
243da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
244da8fa4e3SBjoern A. Zeeb 	u32 tid, buf_size;
245da8fa4e3SBjoern A. Zeeb 	int ret;
246da8fa4e3SBjoern A. Zeeb 	char buf[64] = {0};
247da8fa4e3SBjoern A. Zeeb 
248da8fa4e3SBjoern A. Zeeb 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
249da8fa4e3SBjoern A. Zeeb 				     user_buf, count);
250da8fa4e3SBjoern A. Zeeb 	if (ret <= 0)
251da8fa4e3SBjoern A. Zeeb 		return ret;
252da8fa4e3SBjoern A. Zeeb 
253da8fa4e3SBjoern A. Zeeb 	ret = sscanf(buf, "%u %u", &tid, &buf_size);
254da8fa4e3SBjoern A. Zeeb 	if (ret != 2)
255da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
256da8fa4e3SBjoern A. Zeeb 
257da8fa4e3SBjoern A. Zeeb 	/* Valid TID values are 0 through 15 */
258da8fa4e3SBjoern A. Zeeb 	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
259da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
260da8fa4e3SBjoern A. Zeeb 
261da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
262da8fa4e3SBjoern A. Zeeb 	if ((ar->state != ATH10K_STATE_ON) ||
263da8fa4e3SBjoern A. Zeeb 	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
264da8fa4e3SBjoern A. Zeeb 		ret = count;
265da8fa4e3SBjoern A. Zeeb 		goto out;
266da8fa4e3SBjoern A. Zeeb 	}
267da8fa4e3SBjoern A. Zeeb 
268da8fa4e3SBjoern A. Zeeb 	ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
269da8fa4e3SBjoern A. Zeeb 				    tid, buf_size);
270da8fa4e3SBjoern A. Zeeb 	if (ret) {
271da8fa4e3SBjoern A. Zeeb 		ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
272da8fa4e3SBjoern A. Zeeb 			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
273da8fa4e3SBjoern A. Zeeb 	}
274da8fa4e3SBjoern A. Zeeb 
275da8fa4e3SBjoern A. Zeeb 	ret = count;
276da8fa4e3SBjoern A. Zeeb out:
277da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
278da8fa4e3SBjoern A. Zeeb 	return ret;
279da8fa4e3SBjoern A. Zeeb }
280da8fa4e3SBjoern A. Zeeb 
281da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_addba = {
282da8fa4e3SBjoern A. Zeeb 	.write = ath10k_dbg_sta_write_addba,
283da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
284da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
285da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
286da8fa4e3SBjoern A. Zeeb };
287da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_write_addba_resp(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)288da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
289da8fa4e3SBjoern A. Zeeb 					       const char __user *user_buf,
290da8fa4e3SBjoern A. Zeeb 					       size_t count, loff_t *ppos)
291da8fa4e3SBjoern A. Zeeb {
292da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
293da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
294da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
295da8fa4e3SBjoern A. Zeeb 	u32 tid, status;
296da8fa4e3SBjoern A. Zeeb 	int ret;
297da8fa4e3SBjoern A. Zeeb 	char buf[64] = {0};
298da8fa4e3SBjoern A. Zeeb 
299da8fa4e3SBjoern A. Zeeb 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
300da8fa4e3SBjoern A. Zeeb 				     user_buf, count);
301da8fa4e3SBjoern A. Zeeb 	if (ret <= 0)
302da8fa4e3SBjoern A. Zeeb 		return ret;
303da8fa4e3SBjoern A. Zeeb 
304da8fa4e3SBjoern A. Zeeb 	ret = sscanf(buf, "%u %u", &tid, &status);
305da8fa4e3SBjoern A. Zeeb 	if (ret != 2)
306da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
307da8fa4e3SBjoern A. Zeeb 
308da8fa4e3SBjoern A. Zeeb 	/* Valid TID values are 0 through 15 */
309da8fa4e3SBjoern A. Zeeb 	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
310da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
311da8fa4e3SBjoern A. Zeeb 
312da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
313da8fa4e3SBjoern A. Zeeb 	if ((ar->state != ATH10K_STATE_ON) ||
314da8fa4e3SBjoern A. Zeeb 	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
315da8fa4e3SBjoern A. Zeeb 		ret = count;
316da8fa4e3SBjoern A. Zeeb 		goto out;
317da8fa4e3SBjoern A. Zeeb 	}
318da8fa4e3SBjoern A. Zeeb 
319da8fa4e3SBjoern A. Zeeb 	ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
320da8fa4e3SBjoern A. Zeeb 					tid, status);
321da8fa4e3SBjoern A. Zeeb 	if (ret) {
322da8fa4e3SBjoern A. Zeeb 		ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
323da8fa4e3SBjoern A. Zeeb 			    arsta->arvif->vdev_id, sta->addr, tid, status);
324da8fa4e3SBjoern A. Zeeb 	}
325da8fa4e3SBjoern A. Zeeb 	ret = count;
326da8fa4e3SBjoern A. Zeeb out:
327da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
328da8fa4e3SBjoern A. Zeeb 	return ret;
329da8fa4e3SBjoern A. Zeeb }
330da8fa4e3SBjoern A. Zeeb 
331da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_addba_resp = {
332da8fa4e3SBjoern A. Zeeb 	.write = ath10k_dbg_sta_write_addba_resp,
333da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
334da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
335da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
336da8fa4e3SBjoern A. Zeeb };
337da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_write_delba(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)338da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
339da8fa4e3SBjoern A. Zeeb 					  const char __user *user_buf,
340da8fa4e3SBjoern A. Zeeb 					  size_t count, loff_t *ppos)
341da8fa4e3SBjoern A. Zeeb {
342da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
343da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
344da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
345da8fa4e3SBjoern A. Zeeb 	u32 tid, initiator, reason;
346da8fa4e3SBjoern A. Zeeb 	int ret;
347da8fa4e3SBjoern A. Zeeb 	char buf[64] = {0};
348da8fa4e3SBjoern A. Zeeb 
349da8fa4e3SBjoern A. Zeeb 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
350da8fa4e3SBjoern A. Zeeb 				     user_buf, count);
351da8fa4e3SBjoern A. Zeeb 	if (ret <= 0)
352da8fa4e3SBjoern A. Zeeb 		return ret;
353da8fa4e3SBjoern A. Zeeb 
354da8fa4e3SBjoern A. Zeeb 	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
355da8fa4e3SBjoern A. Zeeb 	if (ret != 3)
356da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
357da8fa4e3SBjoern A. Zeeb 
358da8fa4e3SBjoern A. Zeeb 	/* Valid TID values are 0 through 15 */
359da8fa4e3SBjoern A. Zeeb 	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
360da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
361da8fa4e3SBjoern A. Zeeb 
362da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
363da8fa4e3SBjoern A. Zeeb 	if ((ar->state != ATH10K_STATE_ON) ||
364da8fa4e3SBjoern A. Zeeb 	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
365da8fa4e3SBjoern A. Zeeb 		ret = count;
366da8fa4e3SBjoern A. Zeeb 		goto out;
367da8fa4e3SBjoern A. Zeeb 	}
368da8fa4e3SBjoern A. Zeeb 
369da8fa4e3SBjoern A. Zeeb 	ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
370da8fa4e3SBjoern A. Zeeb 				    tid, initiator, reason);
371da8fa4e3SBjoern A. Zeeb 	if (ret) {
372da8fa4e3SBjoern A. Zeeb 		ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
373da8fa4e3SBjoern A. Zeeb 			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
374da8fa4e3SBjoern A. Zeeb 			    reason);
375da8fa4e3SBjoern A. Zeeb 	}
376da8fa4e3SBjoern A. Zeeb 	ret = count;
377da8fa4e3SBjoern A. Zeeb out:
378da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
379da8fa4e3SBjoern A. Zeeb 	return ret;
380da8fa4e3SBjoern A. Zeeb }
381da8fa4e3SBjoern A. Zeeb 
382da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_delba = {
383da8fa4e3SBjoern A. Zeeb 	.write = ath10k_dbg_sta_write_delba,
384da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
385da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
386da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
387da8fa4e3SBjoern A. Zeeb };
388da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_read_peer_debug_trigger(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)389da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file,
390da8fa4e3SBjoern A. Zeeb 						      char __user *user_buf,
391da8fa4e3SBjoern A. Zeeb 						      size_t count,
392da8fa4e3SBjoern A. Zeeb 						      loff_t *ppos)
393da8fa4e3SBjoern A. Zeeb {
394da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
395da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
396da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
397da8fa4e3SBjoern A. Zeeb 	char buf[8];
398da8fa4e3SBjoern A. Zeeb 	int len = 0;
399da8fa4e3SBjoern A. Zeeb 
400da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
401da8fa4e3SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf) - len,
402da8fa4e3SBjoern A. Zeeb 			"Write 1 to once trigger the debug logs\n");
403da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
404da8fa4e3SBjoern A. Zeeb 
405da8fa4e3SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
406da8fa4e3SBjoern A. Zeeb }
407da8fa4e3SBjoern A. Zeeb 
408da8fa4e3SBjoern A. Zeeb static ssize_t
ath10k_dbg_sta_write_peer_debug_trigger(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)409da8fa4e3SBjoern A. Zeeb ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,
410da8fa4e3SBjoern A. Zeeb 					const char __user *user_buf,
411da8fa4e3SBjoern A. Zeeb 					size_t count, loff_t *ppos)
412da8fa4e3SBjoern A. Zeeb {
413da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
414da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
415da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
416da8fa4e3SBjoern A. Zeeb 	u8 peer_debug_trigger;
417da8fa4e3SBjoern A. Zeeb 	int ret;
418da8fa4e3SBjoern A. Zeeb 
419da8fa4e3SBjoern A. Zeeb 	if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger))
420da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
421da8fa4e3SBjoern A. Zeeb 
422da8fa4e3SBjoern A. Zeeb 	if (peer_debug_trigger != 1)
423da8fa4e3SBjoern A. Zeeb 		return -EINVAL;
424da8fa4e3SBjoern A. Zeeb 
425da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
426da8fa4e3SBjoern A. Zeeb 
427da8fa4e3SBjoern A. Zeeb 	if (ar->state != ATH10K_STATE_ON) {
428da8fa4e3SBjoern A. Zeeb 		ret = -ENETDOWN;
429da8fa4e3SBjoern A. Zeeb 		goto out;
430da8fa4e3SBjoern A. Zeeb 	}
431da8fa4e3SBjoern A. Zeeb 
432da8fa4e3SBjoern A. Zeeb 	ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr,
433da8fa4e3SBjoern A. Zeeb 					ar->wmi.peer_param->debug, peer_debug_trigger);
434da8fa4e3SBjoern A. Zeeb 	if (ret) {
435da8fa4e3SBjoern A. Zeeb 		ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n",
436da8fa4e3SBjoern A. Zeeb 			    ret);
437da8fa4e3SBjoern A. Zeeb 		goto out;
438da8fa4e3SBjoern A. Zeeb 	}
439da8fa4e3SBjoern A. Zeeb out:
440da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
441da8fa4e3SBjoern A. Zeeb 	return count;
442da8fa4e3SBjoern A. Zeeb }
443da8fa4e3SBjoern A. Zeeb 
444da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_peer_debug_trigger = {
445da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
446da8fa4e3SBjoern A. Zeeb 	.read = ath10k_dbg_sta_read_peer_debug_trigger,
447da8fa4e3SBjoern A. Zeeb 	.write = ath10k_dbg_sta_write_peer_debug_trigger,
448da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
449da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
450da8fa4e3SBjoern A. Zeeb };
451da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_read_peer_ps_state(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)452da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,
453da8fa4e3SBjoern A. Zeeb 						 char __user *user_buf,
454da8fa4e3SBjoern A. Zeeb 						 size_t count, loff_t *ppos)
455da8fa4e3SBjoern A. Zeeb {
456da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
457da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
458da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
459da8fa4e3SBjoern A. Zeeb 	char buf[20];
460da8fa4e3SBjoern A. Zeeb 	int len = 0;
461da8fa4e3SBjoern A. Zeeb 
462da8fa4e3SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
463da8fa4e3SBjoern A. Zeeb 
464da8fa4e3SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
465da8fa4e3SBjoern A. Zeeb 			arsta->peer_ps_state);
466da8fa4e3SBjoern A. Zeeb 
467da8fa4e3SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
468da8fa4e3SBjoern A. Zeeb 
469da8fa4e3SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
470da8fa4e3SBjoern A. Zeeb }
471da8fa4e3SBjoern A. Zeeb 
472da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_peer_ps_state = {
473da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
474da8fa4e3SBjoern A. Zeeb 	.read = ath10k_dbg_sta_read_peer_ps_state,
475da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
476da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
477da8fa4e3SBjoern A. Zeeb };
478da8fa4e3SBjoern A. Zeeb 
get_err_str(enum ath10k_pkt_rx_err i)479da8fa4e3SBjoern A. Zeeb static char *get_err_str(enum ath10k_pkt_rx_err i)
480da8fa4e3SBjoern A. Zeeb {
481da8fa4e3SBjoern A. Zeeb 	switch (i) {
482da8fa4e3SBjoern A. Zeeb 	case ATH10K_PKT_RX_ERR_FCS:
483da8fa4e3SBjoern A. Zeeb 		return "fcs_err";
484da8fa4e3SBjoern A. Zeeb 	case ATH10K_PKT_RX_ERR_TKIP:
485da8fa4e3SBjoern A. Zeeb 		return "tkip_err";
486da8fa4e3SBjoern A. Zeeb 	case ATH10K_PKT_RX_ERR_CRYPT:
487da8fa4e3SBjoern A. Zeeb 		return "crypt_err";
488da8fa4e3SBjoern A. Zeeb 	case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
489da8fa4e3SBjoern A. Zeeb 		return "peer_idx_inval";
490da8fa4e3SBjoern A. Zeeb 	case ATH10K_PKT_RX_ERR_MAX:
491da8fa4e3SBjoern A. Zeeb 		return "unknown";
492da8fa4e3SBjoern A. Zeeb 	}
493da8fa4e3SBjoern A. Zeeb 
494da8fa4e3SBjoern A. Zeeb 	return "unknown";
495da8fa4e3SBjoern A. Zeeb }
496da8fa4e3SBjoern A. Zeeb 
get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)497da8fa4e3SBjoern A. Zeeb static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
498da8fa4e3SBjoern A. Zeeb {
499da8fa4e3SBjoern A. Zeeb 	switch (i) {
500da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_10:
501da8fa4e3SBjoern A. Zeeb 		return "up to 10";
502da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_20:
503da8fa4e3SBjoern A. Zeeb 		return "11-20";
504da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_30:
505da8fa4e3SBjoern A. Zeeb 		return "21-30";
506da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_40:
507da8fa4e3SBjoern A. Zeeb 		return "31-40";
508da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_50:
509da8fa4e3SBjoern A. Zeeb 		return "41-50";
510da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_60:
511da8fa4e3SBjoern A. Zeeb 		return "51-60";
512da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_MORE:
513da8fa4e3SBjoern A. Zeeb 		return ">60";
514da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMPDU_SUBFRM_NUM_MAX:
515da8fa4e3SBjoern A. Zeeb 		return "0";
516da8fa4e3SBjoern A. Zeeb 	}
517da8fa4e3SBjoern A. Zeeb 
518da8fa4e3SBjoern A. Zeeb 	return "0";
519da8fa4e3SBjoern A. Zeeb }
520da8fa4e3SBjoern A. Zeeb 
get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)521da8fa4e3SBjoern A. Zeeb static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
522da8fa4e3SBjoern A. Zeeb {
523da8fa4e3SBjoern A. Zeeb 	switch (i) {
524da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMSDU_SUBFRM_NUM_1:
525da8fa4e3SBjoern A. Zeeb 		return "1";
526da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMSDU_SUBFRM_NUM_2:
527da8fa4e3SBjoern A. Zeeb 		return "2";
528da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMSDU_SUBFRM_NUM_3:
529da8fa4e3SBjoern A. Zeeb 		return "3";
530da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMSDU_SUBFRM_NUM_4:
531da8fa4e3SBjoern A. Zeeb 		return "4";
532da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMSDU_SUBFRM_NUM_MORE:
533da8fa4e3SBjoern A. Zeeb 		return ">4";
534da8fa4e3SBjoern A. Zeeb 	case ATH10K_AMSDU_SUBFRM_NUM_MAX:
535da8fa4e3SBjoern A. Zeeb 		return "0";
536da8fa4e3SBjoern A. Zeeb 	}
537da8fa4e3SBjoern A. Zeeb 
538da8fa4e3SBjoern A. Zeeb 	return "0";
539da8fa4e3SBjoern A. Zeeb }
540da8fa4e3SBjoern A. Zeeb 
541da8fa4e3SBjoern A. Zeeb #define PRINT_TID_STATS(_field, _tabs) \
542da8fa4e3SBjoern A. Zeeb 	do { \
543da8fa4e3SBjoern A. Zeeb 		int k = 0; \
544da8fa4e3SBjoern A. Zeeb 		for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
545da8fa4e3SBjoern A. Zeeb 			if (ar->sta_tid_stats_mask & BIT(j))  { \
546da8fa4e3SBjoern A. Zeeb 				len += scnprintf(buf + len, buf_len - len, \
547da8fa4e3SBjoern A. Zeeb 						 "[%02d] %-10lu  ", \
548da8fa4e3SBjoern A. Zeeb 						 j, stats[j]._field); \
549da8fa4e3SBjoern A. Zeeb 				k++; \
550da8fa4e3SBjoern A. Zeeb 				if (k % 8 == 0)  { \
551da8fa4e3SBjoern A. Zeeb 					len += scnprintf(buf + len, \
552da8fa4e3SBjoern A. Zeeb 							 buf_len - len, "\n"); \
553da8fa4e3SBjoern A. Zeeb 					len += scnprintf(buf + len, \
554da8fa4e3SBjoern A. Zeeb 							 buf_len - len, \
555da8fa4e3SBjoern A. Zeeb 							 _tabs); \
556da8fa4e3SBjoern A. Zeeb 				} \
557da8fa4e3SBjoern A. Zeeb 			} \
558da8fa4e3SBjoern A. Zeeb 		} \
559da8fa4e3SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len, "\n"); \
560da8fa4e3SBjoern A. Zeeb 	} while (0)
561da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_read_tid_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)562da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
563da8fa4e3SBjoern A. Zeeb 					     char __user *user_buf,
564da8fa4e3SBjoern A. Zeeb 					     size_t count, loff_t *ppos)
565da8fa4e3SBjoern A. Zeeb {
566da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
567da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
568da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
569da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
570da8fa4e3SBjoern A. Zeeb 	size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
571da8fa4e3SBjoern A. Zeeb 	char *buf;
572da8fa4e3SBjoern A. Zeeb 	int i, j;
573da8fa4e3SBjoern A. Zeeb 	ssize_t ret;
574da8fa4e3SBjoern A. Zeeb 
575da8fa4e3SBjoern A. Zeeb 	buf = kzalloc(buf_len, GFP_KERNEL);
576da8fa4e3SBjoern A. Zeeb 	if (!buf)
577da8fa4e3SBjoern A. Zeeb 		return -ENOMEM;
578da8fa4e3SBjoern A. Zeeb 
579da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
580da8fa4e3SBjoern A. Zeeb 
581da8fa4e3SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
582da8fa4e3SBjoern A. Zeeb 
583da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
584da8fa4e3SBjoern A. Zeeb 			 "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
585da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
586da8fa4e3SBjoern A. Zeeb 			 "\t\t------------------------------------------\n");
587da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
588da8fa4e3SBjoern A. Zeeb 	PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
589da8fa4e3SBjoern A. Zeeb 
590da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
591da8fa4e3SBjoern A. Zeeb 	PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
592da8fa4e3SBjoern A. Zeeb 
593da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
594da8fa4e3SBjoern A. Zeeb 			 "MSDUs locally dropped:chained\t");
595da8fa4e3SBjoern A. Zeeb 	PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
596da8fa4e3SBjoern A. Zeeb 
597da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
598da8fa4e3SBjoern A. Zeeb 			 "MSDUs locally dropped:filtered\t");
599da8fa4e3SBjoern A. Zeeb 	PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
600da8fa4e3SBjoern A. Zeeb 
601da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len,
602da8fa4e3SBjoern A. Zeeb 			 "MSDUs queued for mac80211\t");
603da8fa4e3SBjoern A. Zeeb 	PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
604da8fa4e3SBjoern A. Zeeb 
605da8fa4e3SBjoern A. Zeeb 	for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
606da8fa4e3SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
607da8fa4e3SBjoern A. Zeeb 				 "MSDUs with error:%s\t", get_err_str(i));
608da8fa4e3SBjoern A. Zeeb 		PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
609da8fa4e3SBjoern A. Zeeb 	}
610da8fa4e3SBjoern A. Zeeb 
611da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "\n");
612da8fa4e3SBjoern A. Zeeb 	for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
613da8fa4e3SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
614da8fa4e3SBjoern A. Zeeb 				 "A-MPDU num subframes %s\t",
615da8fa4e3SBjoern A. Zeeb 				 get_num_ampdu_subfrm_str(i));
616da8fa4e3SBjoern A. Zeeb 		PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
617da8fa4e3SBjoern A. Zeeb 	}
618da8fa4e3SBjoern A. Zeeb 
619da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, buf_len - len, "\n");
620da8fa4e3SBjoern A. Zeeb 	for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
621da8fa4e3SBjoern A. Zeeb 		len += scnprintf(buf + len, buf_len - len,
622da8fa4e3SBjoern A. Zeeb 				 "A-MSDU num subframes %s\t\t",
623da8fa4e3SBjoern A. Zeeb 				 get_num_amsdu_subfrm_str(i));
624da8fa4e3SBjoern A. Zeeb 		PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
625da8fa4e3SBjoern A. Zeeb 	}
626da8fa4e3SBjoern A. Zeeb 
627da8fa4e3SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
628da8fa4e3SBjoern A. Zeeb 
629da8fa4e3SBjoern A. Zeeb 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
630da8fa4e3SBjoern A. Zeeb 
631da8fa4e3SBjoern A. Zeeb 	kfree(buf);
632da8fa4e3SBjoern A. Zeeb 
633da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
634da8fa4e3SBjoern A. Zeeb 
635da8fa4e3SBjoern A. Zeeb 	return ret;
636da8fa4e3SBjoern A. Zeeb }
637da8fa4e3SBjoern A. Zeeb 
638da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_tid_stats_dump = {
639da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
640da8fa4e3SBjoern A. Zeeb 	.read = ath10k_dbg_sta_read_tid_stats,
641da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
642da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
643da8fa4e3SBjoern A. Zeeb };
644da8fa4e3SBjoern A. Zeeb 
ath10k_dbg_sta_dump_tx_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)645da8fa4e3SBjoern A. Zeeb static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
646da8fa4e3SBjoern A. Zeeb 					    char __user *user_buf,
647da8fa4e3SBjoern A. Zeeb 					    size_t count, loff_t *ppos)
648da8fa4e3SBjoern A. Zeeb {
649da8fa4e3SBjoern A. Zeeb 	struct ieee80211_sta *sta = file->private_data;
650da8fa4e3SBjoern A. Zeeb 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
651da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = arsta->arvif->ar;
652da8fa4e3SBjoern A. Zeeb 	struct ath10k_htt_data_stats *stats;
653da8fa4e3SBjoern A. Zeeb 	const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail",
654da8fa4e3SBjoern A. Zeeb 						       "retry", "ampdu"};
655da8fa4e3SBjoern A. Zeeb 	const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
656da8fa4e3SBjoern A. Zeeb 	int len = 0, i, j, k, retval = 0;
657da8fa4e3SBjoern A. Zeeb 	const int size = 16 * 4096;
658da8fa4e3SBjoern A. Zeeb 	char *buf;
659da8fa4e3SBjoern A. Zeeb 
660da8fa4e3SBjoern A. Zeeb 	buf = kzalloc(size, GFP_KERNEL);
661da8fa4e3SBjoern A. Zeeb 	if (!buf)
662da8fa4e3SBjoern A. Zeeb 		return -ENOMEM;
663da8fa4e3SBjoern A. Zeeb 
664da8fa4e3SBjoern A. Zeeb 	mutex_lock(&ar->conf_mutex);
665da8fa4e3SBjoern A. Zeeb 
666da8fa4e3SBjoern A. Zeeb 	if (!arsta->tx_stats) {
667da8fa4e3SBjoern A. Zeeb 		ath10k_warn(ar, "failed to get tx stats");
668da8fa4e3SBjoern A. Zeeb 		mutex_unlock(&ar->conf_mutex);
669da8fa4e3SBjoern A. Zeeb 		kfree(buf);
670da8fa4e3SBjoern A. Zeeb 		return 0;
671da8fa4e3SBjoern A. Zeeb 	}
672da8fa4e3SBjoern A. Zeeb 
673da8fa4e3SBjoern A. Zeeb 	spin_lock_bh(&ar->data_lock);
674da8fa4e3SBjoern A. Zeeb 	for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {
675da8fa4e3SBjoern A. Zeeb 		for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {
676da8fa4e3SBjoern A. Zeeb 			stats = &arsta->tx_stats->stats[k];
677da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len, "%s_%s\n",
678da8fa4e3SBjoern A. Zeeb 					 str_name[k],
679da8fa4e3SBjoern A. Zeeb 					 str[j]);
680da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
681da8fa4e3SBjoern A. Zeeb 					 " VHT MCS %s\n",
682da8fa4e3SBjoern A. Zeeb 					 str[j]);
683da8fa4e3SBjoern A. Zeeb 			for (i = 0; i < ATH10K_VHT_MCS_NUM; i++)
684da8fa4e3SBjoern A. Zeeb 				len += scnprintf(buf + len, size - len,
685da8fa4e3SBjoern A. Zeeb 						 "  %llu ",
686da8fa4e3SBjoern A. Zeeb 						 stats->vht[j][i]);
687da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len, "\n");
688da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len, " HT MCS %s\n",
689da8fa4e3SBjoern A. Zeeb 					 str[j]);
690da8fa4e3SBjoern A. Zeeb 			for (i = 0; i < ATH10K_HT_MCS_NUM; i++)
691da8fa4e3SBjoern A. Zeeb 				len += scnprintf(buf + len, size - len,
692da8fa4e3SBjoern A. Zeeb 						 "  %llu ", stats->ht[j][i]);
693da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len, "\n");
694da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
695da8fa4e3SBjoern A. Zeeb 					" BW %s (20,5,10,40,80,160 MHz)\n", str[j]);
696da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
697da8fa4e3SBjoern A. Zeeb 					 "  %llu %llu %llu %llu %llu %llu\n",
698da8fa4e3SBjoern A. Zeeb 					 stats->bw[j][0], stats->bw[j][1],
699da8fa4e3SBjoern A. Zeeb 					 stats->bw[j][2], stats->bw[j][3],
700da8fa4e3SBjoern A. Zeeb 					 stats->bw[j][4], stats->bw[j][5]);
701da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
702da8fa4e3SBjoern A. Zeeb 					 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
703da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
704da8fa4e3SBjoern A. Zeeb 					 "  %llu %llu %llu %llu\n",
705da8fa4e3SBjoern A. Zeeb 					 stats->nss[j][0], stats->nss[j][1],
706da8fa4e3SBjoern A. Zeeb 					 stats->nss[j][2], stats->nss[j][3]);
707da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
708da8fa4e3SBjoern A. Zeeb 					 " GI %s (LGI,SGI)\n",
709da8fa4e3SBjoern A. Zeeb 					 str[j]);
710da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len, "  %llu %llu\n",
711da8fa4e3SBjoern A. Zeeb 					 stats->gi[j][0], stats->gi[j][1]);
712da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
713da8fa4e3SBjoern A. Zeeb 					 " legacy rate %s (1,2 ... Mbps)\n  ",
714da8fa4e3SBjoern A. Zeeb 					 str[j]);
715da8fa4e3SBjoern A. Zeeb 			for (i = 0; i < ATH10K_LEGACY_NUM; i++)
716da8fa4e3SBjoern A. Zeeb 				len += scnprintf(buf + len, size - len, "%llu ",
717da8fa4e3SBjoern A. Zeeb 						 stats->legacy[j][i]);
718da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len, "\n");
719da8fa4e3SBjoern A. Zeeb 			len += scnprintf(buf + len, size - len,
720da8fa4e3SBjoern A. Zeeb 					 " Rate table %s (1,2 ... Mbps)\n  ",
721da8fa4e3SBjoern A. Zeeb 					 str[j]);
722da8fa4e3SBjoern A. Zeeb 			for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) {
723da8fa4e3SBjoern A. Zeeb 				len += scnprintf(buf + len, size - len, "%llu ",
724da8fa4e3SBjoern A. Zeeb 						 stats->rate_table[j][i]);
725da8fa4e3SBjoern A. Zeeb 				if (!((i + 1) % 8))
726da8fa4e3SBjoern A. Zeeb 					len +=
727da8fa4e3SBjoern A. Zeeb 					scnprintf(buf + len, size - len, "\n  ");
728da8fa4e3SBjoern A. Zeeb 			}
729da8fa4e3SBjoern A. Zeeb 		}
730da8fa4e3SBjoern A. Zeeb 	}
731da8fa4e3SBjoern A. Zeeb 
732da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len,
733da8fa4e3SBjoern A. Zeeb 			 "\nTX duration\n %llu usecs\n",
734da8fa4e3SBjoern A. Zeeb 			 arsta->tx_stats->tx_duration);
735da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len,
736da8fa4e3SBjoern A. Zeeb 			"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
737da8fa4e3SBjoern A. Zeeb 	len += scnprintf(buf + len, size - len,
738da8fa4e3SBjoern A. Zeeb 			"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
739da8fa4e3SBjoern A. Zeeb 	spin_unlock_bh(&ar->data_lock);
740da8fa4e3SBjoern A. Zeeb 
741da8fa4e3SBjoern A. Zeeb 	if (len > size)
742da8fa4e3SBjoern A. Zeeb 		len = size;
743da8fa4e3SBjoern A. Zeeb 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
744da8fa4e3SBjoern A. Zeeb 	kfree(buf);
745da8fa4e3SBjoern A. Zeeb 
746da8fa4e3SBjoern A. Zeeb 	mutex_unlock(&ar->conf_mutex);
747da8fa4e3SBjoern A. Zeeb 	return retval;
748da8fa4e3SBjoern A. Zeeb }
749da8fa4e3SBjoern A. Zeeb 
750da8fa4e3SBjoern A. Zeeb static const struct file_operations fops_tx_stats = {
751da8fa4e3SBjoern A. Zeeb 	.read = ath10k_dbg_sta_dump_tx_stats,
752da8fa4e3SBjoern A. Zeeb 	.open = simple_open,
753da8fa4e3SBjoern A. Zeeb 	.owner = THIS_MODULE,
754da8fa4e3SBjoern A. Zeeb 	.llseek = default_llseek,
755da8fa4e3SBjoern A. Zeeb };
756da8fa4e3SBjoern A. Zeeb 
ath10k_sta_add_debugfs(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct dentry * dir)757da8fa4e3SBjoern A. Zeeb void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
758da8fa4e3SBjoern A. Zeeb 			    struct ieee80211_sta *sta, struct dentry *dir)
759da8fa4e3SBjoern A. Zeeb {
760da8fa4e3SBjoern A. Zeeb 	struct ath10k *ar = hw->priv;
761da8fa4e3SBjoern A. Zeeb 
762da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
763da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
764da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
765da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
766da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
767da8fa4e3SBjoern A. Zeeb 			    &fops_peer_debug_trigger);
768da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("dump_tid_stats", 0400, dir, sta,
769da8fa4e3SBjoern A. Zeeb 			    &fops_tid_stats_dump);
770da8fa4e3SBjoern A. Zeeb 
771da8fa4e3SBjoern A. Zeeb 	if (ath10k_peer_stats_enabled(ar) &&
772da8fa4e3SBjoern A. Zeeb 	    ath10k_debug_is_extd_tx_stats_enabled(ar))
773da8fa4e3SBjoern A. Zeeb 		debugfs_create_file("tx_stats", 0400, dir, sta,
774da8fa4e3SBjoern A. Zeeb 				    &fops_tx_stats);
775da8fa4e3SBjoern A. Zeeb 	debugfs_create_file("peer_ps_state", 0400, dir, sta,
776da8fa4e3SBjoern A. Zeeb 			    &fops_peer_ps_state);
777da8fa4e3SBjoern A. Zeeb }
778