Path: blob/main/sys/contrib/dev/athk/ath11k/debugfs_sta.c
48378 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.3*/45#include <linux/vmalloc.h>67#include "debugfs_sta.h"8#include "core.h"9#include "peer.h"10#include "debug.h"11#include "dp_tx.h"12#include "debugfs_htt_stats.h"1314void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,15struct ath11k_per_peer_tx_stats *peer_stats,16u8 legacy_rate_idx)17{18struct rate_info *txrate = &arsta->txrate;19struct ath11k_htt_tx_stats *tx_stats;20int gi, mcs, bw, nss;2122if (!arsta->tx_stats)23return;2425tx_stats = arsta->tx_stats;26gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);27mcs = txrate->mcs;28bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);29nss = txrate->nss - 1;3031#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]3233if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {34STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;35STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;36STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;37STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;38STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;39STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;40} else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {41STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;42STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;43STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;44STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;45STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;46STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;47} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {48STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;49STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;50STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;51STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;52STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;53STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;54} else {55mcs = legacy_rate_idx;5657STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;58STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;59STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;60STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;61STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;62STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;63}6465if (peer_stats->is_ampdu) {66tx_stats->ba_fails += peer_stats->ba_fails;6768if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {69STATS_OP_FMT(AMPDU).he[0][mcs] +=70peer_stats->succ_bytes + peer_stats->retry_bytes;71STATS_OP_FMT(AMPDU).he[1][mcs] +=72peer_stats->succ_pkts + peer_stats->retry_pkts;73} else if (txrate->flags & RATE_INFO_FLAGS_MCS) {74STATS_OP_FMT(AMPDU).ht[0][mcs] +=75peer_stats->succ_bytes + peer_stats->retry_bytes;76STATS_OP_FMT(AMPDU).ht[1][mcs] +=77peer_stats->succ_pkts + peer_stats->retry_pkts;78} else {79STATS_OP_FMT(AMPDU).vht[0][mcs] +=80peer_stats->succ_bytes + peer_stats->retry_bytes;81STATS_OP_FMT(AMPDU).vht[1][mcs] +=82peer_stats->succ_pkts + peer_stats->retry_pkts;83}84STATS_OP_FMT(AMPDU).bw[0][bw] +=85peer_stats->succ_bytes + peer_stats->retry_bytes;86STATS_OP_FMT(AMPDU).nss[0][nss] +=87peer_stats->succ_bytes + peer_stats->retry_bytes;88STATS_OP_FMT(AMPDU).gi[0][gi] +=89peer_stats->succ_bytes + peer_stats->retry_bytes;90STATS_OP_FMT(AMPDU).bw[1][bw] +=91peer_stats->succ_pkts + peer_stats->retry_pkts;92STATS_OP_FMT(AMPDU).nss[1][nss] +=93peer_stats->succ_pkts + peer_stats->retry_pkts;94STATS_OP_FMT(AMPDU).gi[1][gi] +=95peer_stats->succ_pkts + peer_stats->retry_pkts;96} else {97tx_stats->ack_fails += peer_stats->ba_fails;98}99100STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;101STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;102STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;103104STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;105STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;106STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;107108STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;109STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;110STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;111112STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;113STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;114STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;115116STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;117STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;118STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;119120STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;121STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;122STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;123124tx_stats->tx_duration += peer_stats->duration;125}126127void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,128struct hal_tx_status *ts)129{130ath11k_dp_tx_update_txcompl(ar, ts);131}132133static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,134char __user *user_buf,135size_t count, loff_t *ppos)136{137struct ieee80211_sta *sta = file->private_data;138struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;139struct ath11k *ar = arsta->arvif->ar;140struct ath11k_htt_data_stats *stats;141static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",142"retry", "ampdu"};143static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};144int len = 0, i, j, k, retval = 0;145const int size = 2 * 4096;146char *buf;147148if (!arsta->tx_stats)149return -ENOENT;150151buf = kzalloc(size, GFP_KERNEL);152if (!buf)153return -ENOMEM;154155mutex_lock(&ar->conf_mutex);156157spin_lock_bh(&ar->data_lock);158for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {159for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {160stats = &arsta->tx_stats->stats[k];161len += scnprintf(buf + len, size - len, "%s_%s\n",162str_name[k],163str[j]);164len += scnprintf(buf + len, size - len,165" HE MCS %s\n",166str[j]);167for (i = 0; i < ATH11K_HE_MCS_NUM; i++)168len += scnprintf(buf + len, size - len,169" %llu ",170stats->he[j][i]);171len += scnprintf(buf + len, size - len, "\n");172len += scnprintf(buf + len, size - len,173" VHT MCS %s\n",174str[j]);175for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)176len += scnprintf(buf + len, size - len,177" %llu ",178stats->vht[j][i]);179len += scnprintf(buf + len, size - len, "\n");180len += scnprintf(buf + len, size - len, " HT MCS %s\n",181str[j]);182for (i = 0; i < ATH11K_HT_MCS_NUM; i++)183len += scnprintf(buf + len, size - len,184" %llu ", stats->ht[j][i]);185len += scnprintf(buf + len, size - len, "\n");186len += scnprintf(buf + len, size - len,187" BW %s (20,40,80,160 MHz)\n", str[j]);188len += scnprintf(buf + len, size - len,189" %llu %llu %llu %llu\n",190stats->bw[j][0], stats->bw[j][1],191stats->bw[j][2], stats->bw[j][3]);192len += scnprintf(buf + len, size - len,193" NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);194len += scnprintf(buf + len, size - len,195" %llu %llu %llu %llu\n",196stats->nss[j][0], stats->nss[j][1],197stats->nss[j][2], stats->nss[j][3]);198len += scnprintf(buf + len, size - len,199" GI %s (0.4us,0.8us,1.6us,3.2us)\n",200str[j]);201len += scnprintf(buf + len, size - len,202" %llu %llu %llu %llu\n",203stats->gi[j][0], stats->gi[j][1],204stats->gi[j][2], stats->gi[j][3]);205len += scnprintf(buf + len, size - len,206" legacy rate %s (1,2 ... Mbps)\n ",207str[j]);208for (i = 0; i < ATH11K_LEGACY_NUM; i++)209len += scnprintf(buf + len, size - len, "%llu ",210stats->legacy[j][i]);211len += scnprintf(buf + len, size - len, "\n");212}213}214215len += scnprintf(buf + len, size - len,216"\nTX duration\n %llu usecs\n",217arsta->tx_stats->tx_duration);218len += scnprintf(buf + len, size - len,219"BA fails\n %llu\n", arsta->tx_stats->ba_fails);220len += scnprintf(buf + len, size - len,221"ack fails\n %llu\n", arsta->tx_stats->ack_fails);222spin_unlock_bh(&ar->data_lock);223224if (len > size)225len = size;226retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);227kfree(buf);228229mutex_unlock(&ar->conf_mutex);230return retval;231}232233static const struct file_operations fops_tx_stats = {234.read = ath11k_dbg_sta_dump_tx_stats,235.open = simple_open,236.owner = THIS_MODULE,237.llseek = default_llseek,238};239240static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,241char __user *user_buf,242size_t count, loff_t *ppos)243{244struct ieee80211_sta *sta = file->private_data;245struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;246struct ath11k *ar = arsta->arvif->ar;247struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;248int len = 0, i, retval = 0;249const int size = 4096;250char *buf;251252if (!rx_stats)253return -ENOENT;254255buf = kzalloc(size, GFP_KERNEL);256if (!buf)257return -ENOMEM;258259mutex_lock(&ar->conf_mutex);260spin_lock_bh(&ar->ab->base_lock);261262len += scnprintf(buf + len, size - len, "RX peer stats:\n");263len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",264rx_stats->num_msdu);265len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",266rx_stats->tcp_msdu_count);267len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",268rx_stats->udp_msdu_count);269len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",270rx_stats->ampdu_msdu_count);271len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",272rx_stats->non_ampdu_msdu_count);273len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",274rx_stats->stbc_count);275len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",276rx_stats->beamformed_count);277len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",278rx_stats->num_mpdu_fcs_ok);279len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",280rx_stats->num_mpdu_fcs_err);281len += scnprintf(buf + len, size - len,282"GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",283rx_stats->gi_count[0], rx_stats->gi_count[1],284rx_stats->gi_count[2], rx_stats->gi_count[3]);285len += scnprintf(buf + len, size - len,286"BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",287rx_stats->bw_count[0], rx_stats->bw_count[1],288rx_stats->bw_count[2], rx_stats->bw_count[3]);289len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",290rx_stats->coding_count[0], rx_stats->coding_count[1]);291len += scnprintf(buf + len, size - len,292"preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",293rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],294rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],295rx_stats->pream_cnt[4]);296len += scnprintf(buf + len, size - len,297"reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",298rx_stats->reception_type[0], rx_stats->reception_type[1],299rx_stats->reception_type[2], rx_stats->reception_type[3]);300len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");301for (i = 0; i <= IEEE80211_NUM_TIDS; i++)302len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);303len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");304for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)305len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);306len += scnprintf(buf + len, size - len, "\nNSS(1-8):");307for (i = 0; i < HAL_RX_MAX_NSS; i++)308len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);309len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",310rx_stats->rx_duration);311len += scnprintf(buf + len, size - len,312"\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",313rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],314rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],315rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],316rx_stats->ru_alloc_cnt[5]);317318len += scnprintf(buf + len, size - len, "\n");319320spin_unlock_bh(&ar->ab->base_lock);321322if (len > size)323len = size;324retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);325kfree(buf);326327mutex_unlock(&ar->conf_mutex);328return retval;329}330331static const struct file_operations fops_rx_stats = {332.read = ath11k_dbg_sta_dump_rx_stats,333.open = simple_open,334.owner = THIS_MODULE,335.llseek = default_llseek,336};337338static int339ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)340{341struct ieee80211_sta *sta = inode->i_private;342struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;343struct ath11k *ar = arsta->arvif->ar;344struct debug_htt_stats_req *stats_req;345int type = ar->debug.htt_stats.type;346int ret;347348if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO &&349type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) ||350type == ATH11K_DBG_HTT_EXT_STATS_RESET)351return -EPERM;352353stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);354if (!stats_req)355return -ENOMEM;356357mutex_lock(&ar->conf_mutex);358ar->debug.htt_stats.stats_req = stats_req;359stats_req->type = type;360memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);361ret = ath11k_debugfs_htt_stats_req(ar);362mutex_unlock(&ar->conf_mutex);363if (ret < 0)364goto out;365366file->private_data = stats_req;367return 0;368out:369vfree(stats_req);370ar->debug.htt_stats.stats_req = NULL;371return ret;372}373374static int375ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)376{377struct ieee80211_sta *sta = inode->i_private;378struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;379struct ath11k *ar = arsta->arvif->ar;380381mutex_lock(&ar->conf_mutex);382vfree(file->private_data);383ar->debug.htt_stats.stats_req = NULL;384mutex_unlock(&ar->conf_mutex);385386return 0;387}388389static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,390char __user *user_buf,391size_t count, loff_t *ppos)392{393struct debug_htt_stats_req *stats_req = file->private_data;394char *buf;395u32 length = 0;396397buf = stats_req->buf;398length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);399return simple_read_from_buffer(user_buf, count, ppos, buf, length);400}401402static const struct file_operations fops_htt_peer_stats = {403.open = ath11k_dbg_sta_open_htt_peer_stats,404.release = ath11k_dbg_sta_release_htt_peer_stats,405.read = ath11k_dbg_sta_read_htt_peer_stats,406.owner = THIS_MODULE,407.llseek = default_llseek,408};409410static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,411const char __user *buf,412size_t count, loff_t *ppos)413{414struct ieee80211_sta *sta = file->private_data;415struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;416struct ath11k *ar = arsta->arvif->ar;417int ret, enable;418419mutex_lock(&ar->conf_mutex);420421if (ar->state != ATH11K_STATE_ON) {422ret = -ENETDOWN;423goto out;424}425426ret = kstrtoint_from_user(buf, count, 0, &enable);427if (ret)428goto out;429430ar->debug.pktlog_peer_valid = enable;431memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);432433/* Send peer based pktlog enable/disable */434ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);435if (ret) {436ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",437sta->addr, ret);438goto out;439}440441ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",442enable);443ret = count;444445out:446mutex_unlock(&ar->conf_mutex);447return ret;448}449450static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,451char __user *ubuf,452size_t count, loff_t *ppos)453{454struct ieee80211_sta *sta = file->private_data;455struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;456struct ath11k *ar = arsta->arvif->ar;457char buf[32] = {0};458int len;459460mutex_lock(&ar->conf_mutex);461len = scnprintf(buf, sizeof(buf), "%08x %pM\n",462ar->debug.pktlog_peer_valid,463ar->debug.pktlog_peer_addr);464mutex_unlock(&ar->conf_mutex);465466return simple_read_from_buffer(ubuf, count, ppos, buf, len);467}468469static const struct file_operations fops_peer_pktlog = {470.write = ath11k_dbg_sta_write_peer_pktlog,471.read = ath11k_dbg_sta_read_peer_pktlog,472.open = simple_open,473.owner = THIS_MODULE,474.llseek = default_llseek,475};476477static ssize_t ath11k_dbg_sta_write_delba(struct file *file,478const char __user *user_buf,479size_t count, loff_t *ppos)480{481struct ieee80211_sta *sta = file->private_data;482struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;483struct ath11k *ar = arsta->arvif->ar;484u32 tid, initiator, reason;485int ret;486char buf[64] = {0};487488ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,489user_buf, count);490if (ret <= 0)491return ret;492493ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);494if (ret != 3)495return -EINVAL;496497/* Valid TID values are 0 through 15 */498if (tid > HAL_DESC_REO_NON_QOS_TID - 1)499return -EINVAL;500501mutex_lock(&ar->conf_mutex);502if (ar->state != ATH11K_STATE_ON ||503arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {504ret = count;505goto out;506}507508ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,509tid, initiator, reason);510if (ret) {511ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",512arsta->arvif->vdev_id, sta->addr, tid, initiator,513reason);514}515ret = count;516out:517mutex_unlock(&ar->conf_mutex);518return ret;519}520521static const struct file_operations fops_delba = {522.write = ath11k_dbg_sta_write_delba,523.open = simple_open,524.owner = THIS_MODULE,525.llseek = default_llseek,526};527528static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,529const char __user *user_buf,530size_t count, loff_t *ppos)531{532struct ieee80211_sta *sta = file->private_data;533struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;534struct ath11k *ar = arsta->arvif->ar;535u32 tid, status;536int ret;537char buf[64] = {0};538539ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,540user_buf, count);541if (ret <= 0)542return ret;543544ret = sscanf(buf, "%u %u", &tid, &status);545if (ret != 2)546return -EINVAL;547548/* Valid TID values are 0 through 15 */549if (tid > HAL_DESC_REO_NON_QOS_TID - 1)550return -EINVAL;551552mutex_lock(&ar->conf_mutex);553if (ar->state != ATH11K_STATE_ON ||554arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {555ret = count;556goto out;557}558559ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,560tid, status);561if (ret) {562ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",563arsta->arvif->vdev_id, sta->addr, tid, status);564}565ret = count;566out:567mutex_unlock(&ar->conf_mutex);568return ret;569}570571static const struct file_operations fops_addba_resp = {572.write = ath11k_dbg_sta_write_addba_resp,573.open = simple_open,574.owner = THIS_MODULE,575.llseek = default_llseek,576};577578static ssize_t ath11k_dbg_sta_write_addba(struct file *file,579const char __user *user_buf,580size_t count, loff_t *ppos)581{582struct ieee80211_sta *sta = file->private_data;583struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;584struct ath11k *ar = arsta->arvif->ar;585u32 tid, buf_size;586int ret;587char buf[64] = {0};588589ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,590user_buf, count);591if (ret <= 0)592return ret;593594ret = sscanf(buf, "%u %u", &tid, &buf_size);595if (ret != 2)596return -EINVAL;597598/* Valid TID values are 0 through 15 */599if (tid > HAL_DESC_REO_NON_QOS_TID - 1)600return -EINVAL;601602mutex_lock(&ar->conf_mutex);603if (ar->state != ATH11K_STATE_ON ||604arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {605ret = count;606goto out;607}608609ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,610tid, buf_size);611if (ret) {612ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",613arsta->arvif->vdev_id, sta->addr, tid, buf_size);614}615616ret = count;617out:618mutex_unlock(&ar->conf_mutex);619return ret;620}621622static const struct file_operations fops_addba = {623.write = ath11k_dbg_sta_write_addba,624.open = simple_open,625.owner = THIS_MODULE,626.llseek = default_llseek,627};628629static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,630char __user *user_buf,631size_t count, loff_t *ppos)632{633struct ieee80211_sta *sta = file->private_data;634struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;635struct ath11k *ar = arsta->arvif->ar;636char buf[64];637int len = 0;638639mutex_lock(&ar->conf_mutex);640len = scnprintf(buf, sizeof(buf) - len,641"aggregation mode: %s\n\n%s\n%s\n",642(arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?643"auto" : "manual", "auto = 0", "manual = 1");644mutex_unlock(&ar->conf_mutex);645646return simple_read_from_buffer(user_buf, count, ppos, buf, len);647}648649static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,650const char __user *user_buf,651size_t count, loff_t *ppos)652{653struct ieee80211_sta *sta = file->private_data;654struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;655struct ath11k *ar = arsta->arvif->ar;656u32 aggr_mode;657int ret;658659if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))660return -EINVAL;661662if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)663return -EINVAL;664665mutex_lock(&ar->conf_mutex);666if (ar->state != ATH11K_STATE_ON ||667aggr_mode == arsta->aggr_mode) {668ret = count;669goto out;670}671672ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);673if (ret) {674ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",675ret);676goto out;677}678679arsta->aggr_mode = aggr_mode;680out:681mutex_unlock(&ar->conf_mutex);682return ret;683}684685static const struct file_operations fops_aggr_mode = {686.read = ath11k_dbg_sta_read_aggr_mode,687.write = ath11k_dbg_sta_write_aggr_mode,688.open = simple_open,689.owner = THIS_MODULE,690.llseek = default_llseek,691};692693static ssize_t694ath11k_write_htt_peer_stats_reset(struct file *file,695const char __user *user_buf,696size_t count, loff_t *ppos)697{698struct ieee80211_sta *sta = file->private_data;699struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;700struct ath11k *ar = arsta->arvif->ar;701struct htt_ext_stats_cfg_params cfg_params = { 0 };702int ret;703u8 type;704705ret = kstrtou8_from_user(user_buf, count, 0, &type);706if (ret)707return ret;708709if (!type)710return ret;711712mutex_lock(&ar->conf_mutex);713cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;714cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),715HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);716717cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;718719cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);720cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);721cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);722cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);723724cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);725cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);726727cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;728729ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,730ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,731&cfg_params,7320ULL);733if (ret) {734ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);735mutex_unlock(&ar->conf_mutex);736return ret;737}738739mutex_unlock(&ar->conf_mutex);740741ret = count;742743return ret;744}745746static const struct file_operations fops_htt_peer_stats_reset = {747.write = ath11k_write_htt_peer_stats_reset,748.open = simple_open,749.owner = THIS_MODULE,750.llseek = default_llseek,751};752753static ssize_t ath11k_dbg_sta_read_peer_ps_state(struct file *file,754char __user *user_buf,755size_t count, loff_t *ppos)756{757struct ieee80211_sta *sta = file->private_data;758struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;759struct ath11k *ar = arsta->arvif->ar;760char buf[20];761int len;762763spin_lock_bh(&ar->data_lock);764765len = scnprintf(buf, sizeof(buf), "%d\n", arsta->peer_ps_state);766767spin_unlock_bh(&ar->data_lock);768769return simple_read_from_buffer(user_buf, count, ppos, buf, len);770}771772static const struct file_operations fops_peer_ps_state = {773.open = simple_open,774.read = ath11k_dbg_sta_read_peer_ps_state,775.owner = THIS_MODULE,776.llseek = default_llseek,777};778779static ssize_t ath11k_dbg_sta_read_current_ps_duration(struct file *file,780char __user *user_buf,781size_t count,782loff_t *ppos)783{784struct ieee80211_sta *sta = file->private_data;785struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;786struct ath11k *ar = arsta->arvif->ar;787u64 time_since_station_in_power_save;788char buf[20];789int len;790791spin_lock_bh(&ar->data_lock);792793if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&794arsta->peer_current_ps_valid)795time_since_station_in_power_save = jiffies_to_msecs(jiffies796- arsta->ps_start_jiffies);797else798time_since_station_in_power_save = 0;799800len = scnprintf(buf, sizeof(buf), "%llu\n",801time_since_station_in_power_save);802spin_unlock_bh(&ar->data_lock);803804return simple_read_from_buffer(user_buf, count, ppos, buf, len);805}806807static const struct file_operations fops_current_ps_duration = {808.open = simple_open,809.read = ath11k_dbg_sta_read_current_ps_duration,810.owner = THIS_MODULE,811.llseek = default_llseek,812};813814static ssize_t ath11k_dbg_sta_read_total_ps_duration(struct file *file,815char __user *user_buf,816size_t count, loff_t *ppos)817{818struct ieee80211_sta *sta = file->private_data;819struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;820struct ath11k *ar = arsta->arvif->ar;821char buf[20];822u64 power_save_duration;823int len;824825spin_lock_bh(&ar->data_lock);826827if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&828arsta->peer_current_ps_valid)829power_save_duration = jiffies_to_msecs(jiffies830- arsta->ps_start_jiffies)831+ arsta->ps_total_duration;832else833power_save_duration = arsta->ps_total_duration;834835len = scnprintf(buf, sizeof(buf), "%llu\n", power_save_duration);836837spin_unlock_bh(&ar->data_lock);838839return simple_read_from_buffer(user_buf, count, ppos, buf, len);840}841842static const struct file_operations fops_total_ps_duration = {843.open = simple_open,844.read = ath11k_dbg_sta_read_total_ps_duration,845.owner = THIS_MODULE,846.llseek = default_llseek,847};848849void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,850struct ieee80211_sta *sta, struct dentry *dir)851{852struct ath11k *ar = hw->priv;853854if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))855debugfs_create_file("tx_stats", 0400, dir, sta,856&fops_tx_stats);857if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))858debugfs_create_file("rx_stats", 0400, dir, sta,859&fops_rx_stats);860861debugfs_create_file("htt_peer_stats", 0400, dir, sta,862&fops_htt_peer_stats);863864debugfs_create_file("peer_pktlog", 0644, dir, sta,865&fops_peer_pktlog);866867debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);868debugfs_create_file("addba", 0200, dir, sta, &fops_addba);869debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);870debugfs_create_file("delba", 0200, dir, sta, &fops_delba);871872if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,873ar->ab->wmi_ab.svc_map))874debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,875&fops_htt_peer_stats_reset);876877debugfs_create_file("peer_ps_state", 0400, dir, sta,878&fops_peer_ps_state);879880if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,881ar->ab->wmi_ab.svc_map)) {882debugfs_create_file("current_ps_duration", 0440, dir, sta,883&fops_current_ps_duration);884debugfs_create_file("total_ps_duration", 0440, dir, sta,885&fops_total_ps_duration);886}887}888889890