cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

debugfs_sta.c (24558B)


      1// SPDX-License-Identifier: BSD-3-Clause-Clear
      2/*
      3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/vmalloc.h>
      7
      8#include "debugfs_sta.h"
      9#include "core.h"
     10#include "peer.h"
     11#include "debug.h"
     12#include "dp_tx.h"
     13#include "debugfs_htt_stats.h"
     14
     15void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
     16				     struct ath11k_per_peer_tx_stats *peer_stats,
     17				     u8 legacy_rate_idx)
     18{
     19	struct rate_info *txrate = &arsta->txrate;
     20	struct ath11k_htt_tx_stats *tx_stats;
     21	int gi, mcs, bw, nss;
     22
     23	if (!arsta->tx_stats)
     24		return;
     25
     26	tx_stats = arsta->tx_stats;
     27	gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
     28	mcs = txrate->mcs;
     29	bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
     30	nss = txrate->nss - 1;
     31
     32#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
     33
     34	if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
     35		STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
     36		STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
     37		STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
     38		STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
     39		STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
     40		STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
     41	} else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
     42		STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
     43		STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
     44		STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
     45		STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
     46		STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
     47		STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
     48	} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
     49		STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
     50		STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
     51		STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
     52		STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
     53		STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
     54		STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
     55	} else {
     56		mcs = legacy_rate_idx;
     57
     58		STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
     59		STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
     60		STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
     61		STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
     62		STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
     63		STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
     64	}
     65
     66	if (peer_stats->is_ampdu) {
     67		tx_stats->ba_fails += peer_stats->ba_fails;
     68
     69		if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
     70			STATS_OP_FMT(AMPDU).he[0][mcs] +=
     71			peer_stats->succ_bytes + peer_stats->retry_bytes;
     72			STATS_OP_FMT(AMPDU).he[1][mcs] +=
     73			peer_stats->succ_pkts + peer_stats->retry_pkts;
     74		} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
     75			STATS_OP_FMT(AMPDU).ht[0][mcs] +=
     76			peer_stats->succ_bytes + peer_stats->retry_bytes;
     77			STATS_OP_FMT(AMPDU).ht[1][mcs] +=
     78			peer_stats->succ_pkts + peer_stats->retry_pkts;
     79		} else {
     80			STATS_OP_FMT(AMPDU).vht[0][mcs] +=
     81			peer_stats->succ_bytes + peer_stats->retry_bytes;
     82			STATS_OP_FMT(AMPDU).vht[1][mcs] +=
     83			peer_stats->succ_pkts + peer_stats->retry_pkts;
     84		}
     85		STATS_OP_FMT(AMPDU).bw[0][bw] +=
     86			peer_stats->succ_bytes + peer_stats->retry_bytes;
     87		STATS_OP_FMT(AMPDU).nss[0][nss] +=
     88			peer_stats->succ_bytes + peer_stats->retry_bytes;
     89		STATS_OP_FMT(AMPDU).gi[0][gi] +=
     90			peer_stats->succ_bytes + peer_stats->retry_bytes;
     91		STATS_OP_FMT(AMPDU).bw[1][bw] +=
     92			peer_stats->succ_pkts + peer_stats->retry_pkts;
     93		STATS_OP_FMT(AMPDU).nss[1][nss] +=
     94			peer_stats->succ_pkts + peer_stats->retry_pkts;
     95		STATS_OP_FMT(AMPDU).gi[1][gi] +=
     96			peer_stats->succ_pkts + peer_stats->retry_pkts;
     97	} else {
     98		tx_stats->ack_fails += peer_stats->ba_fails;
     99	}
    100
    101	STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
    102	STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
    103	STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
    104
    105	STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
    106	STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
    107	STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
    108
    109	STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
    110	STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
    111	STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
    112
    113	STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
    114	STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
    115	STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
    116
    117	STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
    118	STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
    119	STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
    120
    121	STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
    122	STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
    123	STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
    124
    125	tx_stats->tx_duration += peer_stats->duration;
    126}
    127
    128void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
    129				       struct hal_tx_status *ts)
    130{
    131	ath11k_dp_tx_update_txcompl(ar, ts);
    132}
    133
    134static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
    135					    char __user *user_buf,
    136					    size_t count, loff_t *ppos)
    137{
    138	struct ieee80211_sta *sta = file->private_data;
    139	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    140	struct ath11k *ar = arsta->arvif->ar;
    141	struct ath11k_htt_data_stats *stats;
    142	static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
    143							      "retry", "ampdu"};
    144	static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
    145	int len = 0, i, j, k, retval = 0;
    146	const int size = 2 * 4096;
    147	char *buf;
    148
    149	if (!arsta->tx_stats)
    150		return -ENOENT;
    151
    152	buf = kzalloc(size, GFP_KERNEL);
    153	if (!buf)
    154		return -ENOMEM;
    155
    156	mutex_lock(&ar->conf_mutex);
    157
    158	spin_lock_bh(&ar->data_lock);
    159	for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
    160		for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
    161			stats = &arsta->tx_stats->stats[k];
    162			len += scnprintf(buf + len, size - len, "%s_%s\n",
    163					 str_name[k],
    164					 str[j]);
    165			len += scnprintf(buf + len, size - len,
    166					 " HE MCS %s\n",
    167					 str[j]);
    168			for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
    169				len += scnprintf(buf + len, size - len,
    170						 "  %llu ",
    171						 stats->he[j][i]);
    172			len += scnprintf(buf + len, size - len, "\n");
    173			len += scnprintf(buf + len, size - len,
    174					 " VHT MCS %s\n",
    175					 str[j]);
    176			for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
    177				len += scnprintf(buf + len, size - len,
    178						 "  %llu ",
    179						 stats->vht[j][i]);
    180			len += scnprintf(buf + len, size - len, "\n");
    181			len += scnprintf(buf + len, size - len, " HT MCS %s\n",
    182					 str[j]);
    183			for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
    184				len += scnprintf(buf + len, size - len,
    185						 "  %llu ", stats->ht[j][i]);
    186			len += scnprintf(buf + len, size - len, "\n");
    187			len += scnprintf(buf + len, size - len,
    188					" BW %s (20,40,80,160 MHz)\n", str[j]);
    189			len += scnprintf(buf + len, size - len,
    190					 "  %llu %llu %llu %llu\n",
    191					 stats->bw[j][0], stats->bw[j][1],
    192					 stats->bw[j][2], stats->bw[j][3]);
    193			len += scnprintf(buf + len, size - len,
    194					 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
    195			len += scnprintf(buf + len, size - len,
    196					 "  %llu %llu %llu %llu\n",
    197					 stats->nss[j][0], stats->nss[j][1],
    198					 stats->nss[j][2], stats->nss[j][3]);
    199			len += scnprintf(buf + len, size - len,
    200					 " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
    201					 str[j]);
    202			len += scnprintf(buf + len, size - len,
    203					 "  %llu %llu %llu %llu\n",
    204					 stats->gi[j][0], stats->gi[j][1],
    205					 stats->gi[j][2], stats->gi[j][3]);
    206			len += scnprintf(buf + len, size - len,
    207					 " legacy rate %s (1,2 ... Mbps)\n  ",
    208					 str[j]);
    209			for (i = 0; i < ATH11K_LEGACY_NUM; i++)
    210				len += scnprintf(buf + len, size - len, "%llu ",
    211						 stats->legacy[j][i]);
    212			len += scnprintf(buf + len, size - len, "\n");
    213		}
    214	}
    215
    216	len += scnprintf(buf + len, size - len,
    217			 "\nTX duration\n %llu usecs\n",
    218			 arsta->tx_stats->tx_duration);
    219	len += scnprintf(buf + len, size - len,
    220			"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
    221	len += scnprintf(buf + len, size - len,
    222			"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
    223	spin_unlock_bh(&ar->data_lock);
    224
    225	if (len > size)
    226		len = size;
    227	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    228	kfree(buf);
    229
    230	mutex_unlock(&ar->conf_mutex);
    231	return retval;
    232}
    233
    234static const struct file_operations fops_tx_stats = {
    235	.read = ath11k_dbg_sta_dump_tx_stats,
    236	.open = simple_open,
    237	.owner = THIS_MODULE,
    238	.llseek = default_llseek,
    239};
    240
    241static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
    242					    char __user *user_buf,
    243					    size_t count, loff_t *ppos)
    244{
    245	struct ieee80211_sta *sta = file->private_data;
    246	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    247	struct ath11k *ar = arsta->arvif->ar;
    248	struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
    249	int len = 0, i, retval = 0;
    250	const int size = 4096;
    251	char *buf;
    252
    253	if (!rx_stats)
    254		return -ENOENT;
    255
    256	buf = kzalloc(size, GFP_KERNEL);
    257	if (!buf)
    258		return -ENOMEM;
    259
    260	mutex_lock(&ar->conf_mutex);
    261	spin_lock_bh(&ar->ab->base_lock);
    262
    263	len += scnprintf(buf + len, size - len, "RX peer stats:\n");
    264	len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
    265			 rx_stats->num_msdu);
    266	len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
    267			 rx_stats->tcp_msdu_count);
    268	len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
    269			 rx_stats->udp_msdu_count);
    270	len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
    271			 rx_stats->ampdu_msdu_count);
    272	len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
    273			 rx_stats->non_ampdu_msdu_count);
    274	len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
    275			 rx_stats->stbc_count);
    276	len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
    277			 rx_stats->beamformed_count);
    278	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
    279			 rx_stats->num_mpdu_fcs_ok);
    280	len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
    281			 rx_stats->num_mpdu_fcs_err);
    282	len += scnprintf(buf + len, size - len,
    283			 "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
    284			 rx_stats->gi_count[0], rx_stats->gi_count[1],
    285			 rx_stats->gi_count[2], rx_stats->gi_count[3]);
    286	len += scnprintf(buf + len, size - len,
    287			 "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
    288			 rx_stats->bw_count[0], rx_stats->bw_count[1],
    289			 rx_stats->bw_count[2], rx_stats->bw_count[3]);
    290	len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
    291			 rx_stats->coding_count[0], rx_stats->coding_count[1]);
    292	len += scnprintf(buf + len, size - len,
    293			 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
    294			 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
    295			 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
    296			 rx_stats->pream_cnt[4]);
    297	len += scnprintf(buf + len, size - len,
    298			 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
    299			 rx_stats->reception_type[0], rx_stats->reception_type[1],
    300			 rx_stats->reception_type[2], rx_stats->reception_type[3]);
    301	len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
    302	for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
    303		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
    304	len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
    305	for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
    306		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
    307	len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
    308	for (i = 0; i < HAL_RX_MAX_NSS; i++)
    309		len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
    310	len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
    311			 rx_stats->rx_duration);
    312	len += scnprintf(buf + len, size - len,
    313			 "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
    314			 rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
    315			 rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
    316			 rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
    317			 rx_stats->ru_alloc_cnt[5]);
    318
    319	len += scnprintf(buf + len, size - len, "\n");
    320
    321	spin_unlock_bh(&ar->ab->base_lock);
    322
    323	if (len > size)
    324		len = size;
    325	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
    326	kfree(buf);
    327
    328	mutex_unlock(&ar->conf_mutex);
    329	return retval;
    330}
    331
    332static const struct file_operations fops_rx_stats = {
    333	.read = ath11k_dbg_sta_dump_rx_stats,
    334	.open = simple_open,
    335	.owner = THIS_MODULE,
    336	.llseek = default_llseek,
    337};
    338
    339static int
    340ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
    341{
    342	struct ieee80211_sta *sta = inode->i_private;
    343	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    344	struct ath11k *ar = arsta->arvif->ar;
    345	struct debug_htt_stats_req *stats_req;
    346	int type = ar->debug.htt_stats.type;
    347	int ret;
    348
    349	if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO &&
    350	     type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) ||
    351	    type == ATH11K_DBG_HTT_EXT_STATS_RESET)
    352		return -EPERM;
    353
    354	stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
    355	if (!stats_req)
    356		return -ENOMEM;
    357
    358	mutex_lock(&ar->conf_mutex);
    359	ar->debug.htt_stats.stats_req = stats_req;
    360	stats_req->type = type;
    361	memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
    362	ret = ath11k_debugfs_htt_stats_req(ar);
    363	mutex_unlock(&ar->conf_mutex);
    364	if (ret < 0)
    365		goto out;
    366
    367	file->private_data = stats_req;
    368	return 0;
    369out:
    370	vfree(stats_req);
    371	ar->debug.htt_stats.stats_req = NULL;
    372	return ret;
    373}
    374
    375static int
    376ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
    377{
    378	struct ieee80211_sta *sta = inode->i_private;
    379	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    380	struct ath11k *ar = arsta->arvif->ar;
    381
    382	mutex_lock(&ar->conf_mutex);
    383	vfree(file->private_data);
    384	ar->debug.htt_stats.stats_req = NULL;
    385	mutex_unlock(&ar->conf_mutex);
    386
    387	return 0;
    388}
    389
    390static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
    391						  char __user *user_buf,
    392						  size_t count, loff_t *ppos)
    393{
    394	struct debug_htt_stats_req *stats_req = file->private_data;
    395	char *buf;
    396	u32 length = 0;
    397
    398	buf = stats_req->buf;
    399	length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
    400	return simple_read_from_buffer(user_buf, count, ppos, buf, length);
    401}
    402
    403static const struct file_operations fops_htt_peer_stats = {
    404	.open = ath11k_dbg_sta_open_htt_peer_stats,
    405	.release = ath11k_dbg_sta_release_htt_peer_stats,
    406	.read = ath11k_dbg_sta_read_htt_peer_stats,
    407	.owner = THIS_MODULE,
    408	.llseek = default_llseek,
    409};
    410
    411static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
    412						const char __user *buf,
    413						size_t count, loff_t *ppos)
    414{
    415	struct ieee80211_sta *sta = file->private_data;
    416	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    417	struct ath11k *ar = arsta->arvif->ar;
    418	int ret, enable;
    419
    420	mutex_lock(&ar->conf_mutex);
    421
    422	if (ar->state != ATH11K_STATE_ON) {
    423		ret = -ENETDOWN;
    424		goto out;
    425	}
    426
    427	ret = kstrtoint_from_user(buf, count, 0, &enable);
    428	if (ret)
    429		goto out;
    430
    431	ar->debug.pktlog_peer_valid = enable;
    432	memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
    433
    434	/* Send peer based pktlog enable/disable */
    435	ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
    436	if (ret) {
    437		ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
    438			    sta->addr, ret);
    439		goto out;
    440	}
    441
    442	ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
    443		   enable);
    444	ret = count;
    445
    446out:
    447	mutex_unlock(&ar->conf_mutex);
    448	return ret;
    449}
    450
    451static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
    452					       char __user *ubuf,
    453					       size_t count, loff_t *ppos)
    454{
    455	struct ieee80211_sta *sta = file->private_data;
    456	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    457	struct ath11k *ar = arsta->arvif->ar;
    458	char buf[32] = {0};
    459	int len;
    460
    461	mutex_lock(&ar->conf_mutex);
    462	len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
    463			ar->debug.pktlog_peer_valid,
    464			ar->debug.pktlog_peer_addr);
    465	mutex_unlock(&ar->conf_mutex);
    466
    467	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
    468}
    469
    470static const struct file_operations fops_peer_pktlog = {
    471	.write = ath11k_dbg_sta_write_peer_pktlog,
    472	.read = ath11k_dbg_sta_read_peer_pktlog,
    473	.open = simple_open,
    474	.owner = THIS_MODULE,
    475	.llseek = default_llseek,
    476};
    477
    478static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
    479					  const char __user *user_buf,
    480					  size_t count, loff_t *ppos)
    481{
    482	struct ieee80211_sta *sta = file->private_data;
    483	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    484	struct ath11k *ar = arsta->arvif->ar;
    485	u32 tid, initiator, reason;
    486	int ret;
    487	char buf[64] = {0};
    488
    489	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
    490				     user_buf, count);
    491	if (ret <= 0)
    492		return ret;
    493
    494	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
    495	if (ret != 3)
    496		return -EINVAL;
    497
    498	/* Valid TID values are 0 through 15 */
    499	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
    500		return -EINVAL;
    501
    502	mutex_lock(&ar->conf_mutex);
    503	if (ar->state != ATH11K_STATE_ON ||
    504	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
    505		ret = count;
    506		goto out;
    507	}
    508
    509	ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
    510				    tid, initiator, reason);
    511	if (ret) {
    512		ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
    513			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
    514			    reason);
    515	}
    516	ret = count;
    517out:
    518	mutex_unlock(&ar->conf_mutex);
    519	return ret;
    520}
    521
    522static const struct file_operations fops_delba = {
    523	.write = ath11k_dbg_sta_write_delba,
    524	.open = simple_open,
    525	.owner = THIS_MODULE,
    526	.llseek = default_llseek,
    527};
    528
    529static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
    530					       const char __user *user_buf,
    531					       size_t count, loff_t *ppos)
    532{
    533	struct ieee80211_sta *sta = file->private_data;
    534	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    535	struct ath11k *ar = arsta->arvif->ar;
    536	u32 tid, status;
    537	int ret;
    538	char buf[64] = {0};
    539
    540	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
    541				     user_buf, count);
    542	if (ret <= 0)
    543		return ret;
    544
    545	ret = sscanf(buf, "%u %u", &tid, &status);
    546	if (ret != 2)
    547		return -EINVAL;
    548
    549	/* Valid TID values are 0 through 15 */
    550	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
    551		return -EINVAL;
    552
    553	mutex_lock(&ar->conf_mutex);
    554	if (ar->state != ATH11K_STATE_ON ||
    555	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
    556		ret = count;
    557		goto out;
    558	}
    559
    560	ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
    561					tid, status);
    562	if (ret) {
    563		ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
    564			    arsta->arvif->vdev_id, sta->addr, tid, status);
    565	}
    566	ret = count;
    567out:
    568	mutex_unlock(&ar->conf_mutex);
    569	return ret;
    570}
    571
    572static const struct file_operations fops_addba_resp = {
    573	.write = ath11k_dbg_sta_write_addba_resp,
    574	.open = simple_open,
    575	.owner = THIS_MODULE,
    576	.llseek = default_llseek,
    577};
    578
    579static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
    580					  const char __user *user_buf,
    581					  size_t count, loff_t *ppos)
    582{
    583	struct ieee80211_sta *sta = file->private_data;
    584	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    585	struct ath11k *ar = arsta->arvif->ar;
    586	u32 tid, buf_size;
    587	int ret;
    588	char buf[64] = {0};
    589
    590	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
    591				     user_buf, count);
    592	if (ret <= 0)
    593		return ret;
    594
    595	ret = sscanf(buf, "%u %u", &tid, &buf_size);
    596	if (ret != 2)
    597		return -EINVAL;
    598
    599	/* Valid TID values are 0 through 15 */
    600	if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
    601		return -EINVAL;
    602
    603	mutex_lock(&ar->conf_mutex);
    604	if (ar->state != ATH11K_STATE_ON ||
    605	    arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
    606		ret = count;
    607		goto out;
    608	}
    609
    610	ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
    611				    tid, buf_size);
    612	if (ret) {
    613		ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
    614			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
    615	}
    616
    617	ret = count;
    618out:
    619	mutex_unlock(&ar->conf_mutex);
    620	return ret;
    621}
    622
    623static const struct file_operations fops_addba = {
    624	.write = ath11k_dbg_sta_write_addba,
    625	.open = simple_open,
    626	.owner = THIS_MODULE,
    627	.llseek = default_llseek,
    628};
    629
    630static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
    631					     char __user *user_buf,
    632					     size_t count, loff_t *ppos)
    633{
    634	struct ieee80211_sta *sta = file->private_data;
    635	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    636	struct ath11k *ar = arsta->arvif->ar;
    637	char buf[64];
    638	int len = 0;
    639
    640	mutex_lock(&ar->conf_mutex);
    641	len = scnprintf(buf, sizeof(buf) - len,
    642			"aggregation mode: %s\n\n%s\n%s\n",
    643			(arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
    644			"auto" : "manual", "auto = 0", "manual = 1");
    645	mutex_unlock(&ar->conf_mutex);
    646
    647	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    648}
    649
    650static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
    651					      const char __user *user_buf,
    652					      size_t count, loff_t *ppos)
    653{
    654	struct ieee80211_sta *sta = file->private_data;
    655	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    656	struct ath11k *ar = arsta->arvif->ar;
    657	u32 aggr_mode;
    658	int ret;
    659
    660	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
    661		return -EINVAL;
    662
    663	if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
    664		return -EINVAL;
    665
    666	mutex_lock(&ar->conf_mutex);
    667	if (ar->state != ATH11K_STATE_ON ||
    668	    aggr_mode == arsta->aggr_mode) {
    669		ret = count;
    670		goto out;
    671	}
    672
    673	ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
    674	if (ret) {
    675		ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
    676			    ret);
    677		goto out;
    678	}
    679
    680	arsta->aggr_mode = aggr_mode;
    681out:
    682	mutex_unlock(&ar->conf_mutex);
    683	return ret;
    684}
    685
    686static const struct file_operations fops_aggr_mode = {
    687	.read = ath11k_dbg_sta_read_aggr_mode,
    688	.write = ath11k_dbg_sta_write_aggr_mode,
    689	.open = simple_open,
    690	.owner = THIS_MODULE,
    691	.llseek = default_llseek,
    692};
    693
    694static ssize_t
    695ath11k_write_htt_peer_stats_reset(struct file *file,
    696				  const char __user *user_buf,
    697				  size_t count, loff_t *ppos)
    698{
    699	struct ieee80211_sta *sta = file->private_data;
    700	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
    701	struct ath11k *ar = arsta->arvif->ar;
    702	struct htt_ext_stats_cfg_params cfg_params = { 0 };
    703	int ret;
    704	u8 type;
    705
    706	ret = kstrtou8_from_user(user_buf, count, 0, &type);
    707	if (ret)
    708		return ret;
    709
    710	if (!type)
    711		return ret;
    712
    713	mutex_lock(&ar->conf_mutex);
    714	cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
    715	cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
    716				HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
    717
    718	cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
    719
    720	cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
    721	cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
    722	cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
    723	cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
    724
    725	cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
    726	cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
    727
    728	cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
    729
    730	ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
    731						 ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
    732						 &cfg_params,
    733						 0ULL);
    734	if (ret) {
    735		ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
    736		mutex_unlock(&ar->conf_mutex);
    737		return ret;
    738	}
    739
    740	mutex_unlock(&ar->conf_mutex);
    741
    742	ret = count;
    743
    744	return ret;
    745}
    746
    747static const struct file_operations fops_htt_peer_stats_reset = {
    748	.write = ath11k_write_htt_peer_stats_reset,
    749	.open = simple_open,
    750	.owner = THIS_MODULE,
    751	.llseek = default_llseek,
    752};
    753
    754void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    755			       struct ieee80211_sta *sta, struct dentry *dir)
    756{
    757	struct ath11k *ar = hw->priv;
    758
    759	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
    760		debugfs_create_file("tx_stats", 0400, dir, sta,
    761				    &fops_tx_stats);
    762	if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
    763		debugfs_create_file("rx_stats", 0400, dir, sta,
    764				    &fops_rx_stats);
    765
    766	debugfs_create_file("htt_peer_stats", 0400, dir, sta,
    767			    &fops_htt_peer_stats);
    768
    769	debugfs_create_file("peer_pktlog", 0644, dir, sta,
    770			    &fops_peer_pktlog);
    771
    772	debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
    773	debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
    774	debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
    775	debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
    776
    777	if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
    778		     ar->ab->wmi_ab.svc_map))
    779		debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
    780				    &fops_htt_peer_stats_reset);
    781}