18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "debugfs_sta.h" 98c2ecf20Sopenharmony_ci#include "core.h" 108c2ecf20Sopenharmony_ci#include "peer.h" 118c2ecf20Sopenharmony_ci#include "debug.h" 128c2ecf20Sopenharmony_ci#include "dp_tx.h" 138c2ecf20Sopenharmony_ci#include "debugfs_htt_stats.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_civoid ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta, 168c2ecf20Sopenharmony_ci struct ath11k_per_peer_tx_stats *peer_stats, 178c2ecf20Sopenharmony_ci u8 legacy_rate_idx) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct rate_info *txrate = &arsta->txrate; 208c2ecf20Sopenharmony_ci struct ath11k_htt_tx_stats *tx_stats; 218c2ecf20Sopenharmony_ci int gi, mcs, bw, nss; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (!arsta->tx_stats) 248c2ecf20Sopenharmony_ci return; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci tx_stats = arsta->tx_stats; 278c2ecf20Sopenharmony_ci gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags); 288c2ecf20Sopenharmony_ci mcs = txrate->mcs; 298c2ecf20Sopenharmony_ci bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw); 308c2ecf20Sopenharmony_ci nss = txrate->nss - 1; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name] 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) { 358c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes; 368c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts; 378c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes; 388c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts; 398c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes; 408c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts; 418c2ecf20Sopenharmony_ci } else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) { 428c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes; 438c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts; 448c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes; 458c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts; 468c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes; 478c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts; 488c2ecf20Sopenharmony_ci } else if (txrate->flags & RATE_INFO_FLAGS_MCS) { 498c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes; 508c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts; 518c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes; 528c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts; 538c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes; 548c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts; 558c2ecf20Sopenharmony_ci } else { 568c2ecf20Sopenharmony_ci mcs = legacy_rate_idx; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes; 598c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts; 608c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes; 618c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts; 628c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes; 638c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (peer_stats->is_ampdu) { 678c2ecf20Sopenharmony_ci tx_stats->ba_fails += peer_stats->ba_fails; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) { 708c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).he[0][mcs] += 718c2ecf20Sopenharmony_ci peer_stats->succ_bytes + peer_stats->retry_bytes; 728c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).he[1][mcs] += 738c2ecf20Sopenharmony_ci peer_stats->succ_pkts + peer_stats->retry_pkts; 748c2ecf20Sopenharmony_ci } else if (txrate->flags & RATE_INFO_FLAGS_MCS) { 758c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).ht[0][mcs] += 768c2ecf20Sopenharmony_ci peer_stats->succ_bytes + peer_stats->retry_bytes; 778c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).ht[1][mcs] += 788c2ecf20Sopenharmony_ci peer_stats->succ_pkts + peer_stats->retry_pkts; 798c2ecf20Sopenharmony_ci } else { 808c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).vht[0][mcs] += 818c2ecf20Sopenharmony_ci peer_stats->succ_bytes + peer_stats->retry_bytes; 828c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).vht[1][mcs] += 838c2ecf20Sopenharmony_ci peer_stats->succ_pkts + peer_stats->retry_pkts; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).bw[0][bw] += 868c2ecf20Sopenharmony_ci peer_stats->succ_bytes + peer_stats->retry_bytes; 878c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).nss[0][nss] += 888c2ecf20Sopenharmony_ci peer_stats->succ_bytes + peer_stats->retry_bytes; 898c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).gi[0][gi] += 908c2ecf20Sopenharmony_ci peer_stats->succ_bytes + peer_stats->retry_bytes; 918c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).bw[1][bw] += 928c2ecf20Sopenharmony_ci peer_stats->succ_pkts + peer_stats->retry_pkts; 938c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).nss[1][nss] += 948c2ecf20Sopenharmony_ci peer_stats->succ_pkts + peer_stats->retry_pkts; 958c2ecf20Sopenharmony_ci STATS_OP_FMT(AMPDU).gi[1][gi] += 968c2ecf20Sopenharmony_ci peer_stats->succ_pkts + peer_stats->retry_pkts; 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci tx_stats->ack_fails += peer_stats->ba_fails; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes; 1028c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes; 1038c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts; 1068c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts; 1078c2ecf20Sopenharmony_ci STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes; 1108c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes; 1118c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts; 1148c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts; 1158c2ecf20Sopenharmony_ci STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes; 1188c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes; 1198c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts; 1228c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts; 1238c2ecf20Sopenharmony_ci STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci tx_stats->tx_duration += peer_stats->duration; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_civoid ath11k_debugfs_sta_update_txcompl(struct ath11k *ar, 1298c2ecf20Sopenharmony_ci struct sk_buff *msdu, 1308c2ecf20Sopenharmony_ci struct hal_tx_status *ts) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct ath11k_base *ab = ar->ab; 1338c2ecf20Sopenharmony_ci struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; 1348c2ecf20Sopenharmony_ci enum hal_tx_rate_stats_pkt_type pkt_type; 1358c2ecf20Sopenharmony_ci enum hal_tx_rate_stats_sgi sgi; 1368c2ecf20Sopenharmony_ci enum hal_tx_rate_stats_bw bw; 1378c2ecf20Sopenharmony_ci struct ath11k_peer *peer; 1388c2ecf20Sopenharmony_ci struct ath11k_sta *arsta; 1398c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 1408c2ecf20Sopenharmony_ci u16 rate; 1418c2ecf20Sopenharmony_ci u8 rate_idx = 0; 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci u8 mcs; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci rcu_read_lock(); 1468c2ecf20Sopenharmony_ci spin_lock_bh(&ab->base_lock); 1478c2ecf20Sopenharmony_ci peer = ath11k_peer_find_by_id(ab, ts->peer_id); 1488c2ecf20Sopenharmony_ci if (!peer || !peer->sta) { 1498c2ecf20Sopenharmony_ci ath11k_warn(ab, "failed to find the peer\n"); 1508c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 1518c2ecf20Sopenharmony_ci rcu_read_unlock(); 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci sta = peer->sta; 1568c2ecf20Sopenharmony_ci arsta = (struct ath11k_sta *)sta->drv_priv; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci memset(&arsta->txrate, 0, sizeof(arsta->txrate)); 1598c2ecf20Sopenharmony_ci pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, 1608c2ecf20Sopenharmony_ci ts->rate_stats); 1618c2ecf20Sopenharmony_ci mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, 1628c2ecf20Sopenharmony_ci ts->rate_stats); 1638c2ecf20Sopenharmony_ci sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, 1648c2ecf20Sopenharmony_ci ts->rate_stats); 1658c2ecf20Sopenharmony_ci bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || 1688c2ecf20Sopenharmony_ci pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { 1698c2ecf20Sopenharmony_ci ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, 1708c2ecf20Sopenharmony_ci pkt_type, 1718c2ecf20Sopenharmony_ci &rate_idx, 1728c2ecf20Sopenharmony_ci &rate); 1738c2ecf20Sopenharmony_ci if (ret < 0) 1748c2ecf20Sopenharmony_ci goto err_out; 1758c2ecf20Sopenharmony_ci arsta->txrate.legacy = rate; 1768c2ecf20Sopenharmony_ci } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { 1778c2ecf20Sopenharmony_ci if (mcs > 7) { 1788c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs); 1798c2ecf20Sopenharmony_ci goto err_out; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1); 1838c2ecf20Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_MCS; 1848c2ecf20Sopenharmony_ci if (sgi) 1858c2ecf20Sopenharmony_ci arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 1868c2ecf20Sopenharmony_ci } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { 1878c2ecf20Sopenharmony_ci if (mcs > 9) { 1888c2ecf20Sopenharmony_ci ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs); 1898c2ecf20Sopenharmony_ci goto err_out; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci arsta->txrate.mcs = mcs; 1938c2ecf20Sopenharmony_ci arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; 1948c2ecf20Sopenharmony_ci if (sgi) 1958c2ecf20Sopenharmony_ci arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; 1968c2ecf20Sopenharmony_ci } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { 1978c2ecf20Sopenharmony_ci /* TODO */ 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci arsta->txrate.nss = arsta->last_txrate.nss; 2018c2ecf20Sopenharmony_ci arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cierr_out: 2068c2ecf20Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 2078c2ecf20Sopenharmony_ci rcu_read_unlock(); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file, 2118c2ecf20Sopenharmony_ci char __user *user_buf, 2128c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 2158c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 2168c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 2178c2ecf20Sopenharmony_ci struct ath11k_htt_data_stats *stats; 2188c2ecf20Sopenharmony_ci static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail", 2198c2ecf20Sopenharmony_ci "retry", "ampdu"}; 2208c2ecf20Sopenharmony_ci static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"}; 2218c2ecf20Sopenharmony_ci int len = 0, i, j, k, retval = 0; 2228c2ecf20Sopenharmony_ci const int size = 2 * 4096; 2238c2ecf20Sopenharmony_ci char *buf; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!arsta->tx_stats) 2268c2ecf20Sopenharmony_ci return -ENOENT; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci buf = kzalloc(size, GFP_KERNEL); 2298c2ecf20Sopenharmony_ci if (!buf) 2308c2ecf20Sopenharmony_ci return -ENOMEM; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 2358c2ecf20Sopenharmony_ci for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) { 2368c2ecf20Sopenharmony_ci for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) { 2378c2ecf20Sopenharmony_ci stats = &arsta->tx_stats->stats[k]; 2388c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%s_%s\n", 2398c2ecf20Sopenharmony_ci str_name[k], 2408c2ecf20Sopenharmony_ci str[j]); 2418c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2428c2ecf20Sopenharmony_ci " HE MCS %s\n", 2438c2ecf20Sopenharmony_ci str[j]); 2448c2ecf20Sopenharmony_ci for (i = 0; i < ATH11K_HE_MCS_NUM; i++) 2458c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2468c2ecf20Sopenharmony_ci " %llu ", 2478c2ecf20Sopenharmony_ci stats->he[j][i]); 2488c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 2498c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2508c2ecf20Sopenharmony_ci " VHT MCS %s\n", 2518c2ecf20Sopenharmony_ci str[j]); 2528c2ecf20Sopenharmony_ci for (i = 0; i < ATH11K_VHT_MCS_NUM; i++) 2538c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2548c2ecf20Sopenharmony_ci " %llu ", 2558c2ecf20Sopenharmony_ci stats->vht[j][i]); 2568c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 2578c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, " HT MCS %s\n", 2588c2ecf20Sopenharmony_ci str[j]); 2598c2ecf20Sopenharmony_ci for (i = 0; i < ATH11K_HT_MCS_NUM; i++) 2608c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2618c2ecf20Sopenharmony_ci " %llu ", stats->ht[j][i]); 2628c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 2638c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2648c2ecf20Sopenharmony_ci " BW %s (20,40,80,160 MHz)\n", str[j]); 2658c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2668c2ecf20Sopenharmony_ci " %llu %llu %llu %llu\n", 2678c2ecf20Sopenharmony_ci stats->bw[j][0], stats->bw[j][1], 2688c2ecf20Sopenharmony_ci stats->bw[j][2], stats->bw[j][3]); 2698c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2708c2ecf20Sopenharmony_ci " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]); 2718c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2728c2ecf20Sopenharmony_ci " %llu %llu %llu %llu\n", 2738c2ecf20Sopenharmony_ci stats->nss[j][0], stats->nss[j][1], 2748c2ecf20Sopenharmony_ci stats->nss[j][2], stats->nss[j][3]); 2758c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2768c2ecf20Sopenharmony_ci " GI %s (0.4us,0.8us,1.6us,3.2us)\n", 2778c2ecf20Sopenharmony_ci str[j]); 2788c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2798c2ecf20Sopenharmony_ci " %llu %llu %llu %llu\n", 2808c2ecf20Sopenharmony_ci stats->gi[j][0], stats->gi[j][1], 2818c2ecf20Sopenharmony_ci stats->gi[j][2], stats->gi[j][3]); 2828c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2838c2ecf20Sopenharmony_ci " legacy rate %s (1,2 ... Mbps)\n ", 2848c2ecf20Sopenharmony_ci str[j]); 2858c2ecf20Sopenharmony_ci for (i = 0; i < ATH11K_LEGACY_NUM; i++) 2868c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", 2878c2ecf20Sopenharmony_ci stats->legacy[j][i]); 2888c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2938c2ecf20Sopenharmony_ci "\nTX duration\n %llu usecs\n", 2948c2ecf20Sopenharmony_ci arsta->tx_stats->tx_duration); 2958c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2968c2ecf20Sopenharmony_ci "BA fails\n %llu\n", arsta->tx_stats->ba_fails); 2978c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 2988c2ecf20Sopenharmony_ci "ack fails\n %llu\n", arsta->tx_stats->ack_fails); 2998c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (len > size) 3028c2ecf20Sopenharmony_ci len = size; 3038c2ecf20Sopenharmony_ci retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 3048c2ecf20Sopenharmony_ci kfree(buf); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 3078c2ecf20Sopenharmony_ci return retval; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic const struct file_operations fops_tx_stats = { 3118c2ecf20Sopenharmony_ci .read = ath11k_dbg_sta_dump_tx_stats, 3128c2ecf20Sopenharmony_ci .open = simple_open, 3138c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3148c2ecf20Sopenharmony_ci .llseek = default_llseek, 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file, 3188c2ecf20Sopenharmony_ci char __user *user_buf, 3198c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 3228c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 3238c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 3248c2ecf20Sopenharmony_ci struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats; 3258c2ecf20Sopenharmony_ci int len = 0, i, retval = 0; 3268c2ecf20Sopenharmony_ci const int size = 4096; 3278c2ecf20Sopenharmony_ci char *buf; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!rx_stats) 3308c2ecf20Sopenharmony_ci return -ENOENT; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci buf = kzalloc(size, GFP_KERNEL); 3338c2ecf20Sopenharmony_ci if (!buf) 3348c2ecf20Sopenharmony_ci return -ENOMEM; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 3378c2ecf20Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "RX peer stats:\n"); 3408c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n", 3418c2ecf20Sopenharmony_ci rx_stats->num_msdu); 3428c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n", 3438c2ecf20Sopenharmony_ci rx_stats->tcp_msdu_count); 3448c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n", 3458c2ecf20Sopenharmony_ci rx_stats->udp_msdu_count); 3468c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n", 3478c2ecf20Sopenharmony_ci rx_stats->ampdu_msdu_count); 3488c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n", 3498c2ecf20Sopenharmony_ci rx_stats->non_ampdu_msdu_count); 3508c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n", 3518c2ecf20Sopenharmony_ci rx_stats->stbc_count); 3528c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n", 3538c2ecf20Sopenharmony_ci rx_stats->beamformed_count); 3548c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n", 3558c2ecf20Sopenharmony_ci rx_stats->num_mpdu_fcs_ok); 3568c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n", 3578c2ecf20Sopenharmony_ci rx_stats->num_mpdu_fcs_err); 3588c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 3598c2ecf20Sopenharmony_ci "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n", 3608c2ecf20Sopenharmony_ci rx_stats->gi_count[0], rx_stats->gi_count[1], 3618c2ecf20Sopenharmony_ci rx_stats->gi_count[2], rx_stats->gi_count[3]); 3628c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 3638c2ecf20Sopenharmony_ci "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n", 3648c2ecf20Sopenharmony_ci rx_stats->bw_count[0], rx_stats->bw_count[1], 3658c2ecf20Sopenharmony_ci rx_stats->bw_count[2], rx_stats->bw_count[3]); 3668c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n", 3678c2ecf20Sopenharmony_ci rx_stats->coding_count[0], rx_stats->coding_count[1]); 3688c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 3698c2ecf20Sopenharmony_ci "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n", 3708c2ecf20Sopenharmony_ci rx_stats->pream_cnt[0], rx_stats->pream_cnt[1], 3718c2ecf20Sopenharmony_ci rx_stats->pream_cnt[2], rx_stats->pream_cnt[3], 3728c2ecf20Sopenharmony_ci rx_stats->pream_cnt[4]); 3738c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 3748c2ecf20Sopenharmony_ci "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n", 3758c2ecf20Sopenharmony_ci rx_stats->reception_type[0], rx_stats->reception_type[1], 3768c2ecf20Sopenharmony_ci rx_stats->reception_type[2], rx_stats->reception_type[3]); 3778c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):"); 3788c2ecf20Sopenharmony_ci for (i = 0; i <= IEEE80211_NUM_TIDS; i++) 3798c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]); 3808c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):"); 3818c2ecf20Sopenharmony_ci for (i = 0; i < HAL_RX_MAX_MCS + 1; i++) 3828c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]); 3838c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\nNSS(1-8):"); 3848c2ecf20Sopenharmony_ci for (i = 0; i < HAL_RX_MAX_NSS; i++) 3858c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]); 3868c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ", 3878c2ecf20Sopenharmony_ci rx_stats->rx_duration); 3888c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 3898c2ecf20Sopenharmony_ci "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n", 3908c2ecf20Sopenharmony_ci rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0], 3918c2ecf20Sopenharmony_ci rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2], 3928c2ecf20Sopenharmony_ci rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4], 3938c2ecf20Sopenharmony_ci rx_stats->ru_alloc_cnt[5]); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (len > size) 4008c2ecf20Sopenharmony_ci len = size; 4018c2ecf20Sopenharmony_ci retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 4028c2ecf20Sopenharmony_ci kfree(buf); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4058c2ecf20Sopenharmony_ci return retval; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic const struct file_operations fops_rx_stats = { 4098c2ecf20Sopenharmony_ci .read = ath11k_dbg_sta_dump_rx_stats, 4108c2ecf20Sopenharmony_ci .open = simple_open, 4118c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4128c2ecf20Sopenharmony_ci .llseek = default_llseek, 4138c2ecf20Sopenharmony_ci}; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int 4168c2ecf20Sopenharmony_ciath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = inode->i_private; 4198c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 4208c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 4218c2ecf20Sopenharmony_ci struct debug_htt_stats_req *stats_req; 4228c2ecf20Sopenharmony_ci int ret; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE); 4258c2ecf20Sopenharmony_ci if (!stats_req) 4268c2ecf20Sopenharmony_ci return -ENOMEM; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 4298c2ecf20Sopenharmony_ci ar->debug.htt_stats.stats_req = stats_req; 4308c2ecf20Sopenharmony_ci stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO; 4318c2ecf20Sopenharmony_ci memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN); 4328c2ecf20Sopenharmony_ci ret = ath11k_debugfs_htt_stats_req(ar); 4338c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4348c2ecf20Sopenharmony_ci if (ret < 0) 4358c2ecf20Sopenharmony_ci goto out; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci file->private_data = stats_req; 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ciout: 4408c2ecf20Sopenharmony_ci vfree(stats_req); 4418c2ecf20Sopenharmony_ci ar->debug.htt_stats.stats_req = NULL; 4428c2ecf20Sopenharmony_ci return ret; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int 4468c2ecf20Sopenharmony_ciath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = inode->i_private; 4498c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 4508c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 4538c2ecf20Sopenharmony_ci vfree(file->private_data); 4548c2ecf20Sopenharmony_ci ar->debug.htt_stats.stats_req = NULL; 4558c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file, 4618c2ecf20Sopenharmony_ci char __user *user_buf, 4628c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct debug_htt_stats_req *stats_req = file->private_data; 4658c2ecf20Sopenharmony_ci char *buf; 4668c2ecf20Sopenharmony_ci u32 length = 0; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci buf = stats_req->buf; 4698c2ecf20Sopenharmony_ci length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE); 4708c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, length); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic const struct file_operations fops_htt_peer_stats = { 4748c2ecf20Sopenharmony_ci .open = ath11k_dbg_sta_open_htt_peer_stats, 4758c2ecf20Sopenharmony_ci .release = ath11k_dbg_sta_release_htt_peer_stats, 4768c2ecf20Sopenharmony_ci .read = ath11k_dbg_sta_read_htt_peer_stats, 4778c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4788c2ecf20Sopenharmony_ci .llseek = default_llseek, 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file, 4828c2ecf20Sopenharmony_ci const char __user *buf, 4838c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 4868c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 4878c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 4888c2ecf20Sopenharmony_ci int ret, enable; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (ar->state != ATH11K_STATE_ON) { 4938c2ecf20Sopenharmony_ci ret = -ENETDOWN; 4948c2ecf20Sopenharmony_ci goto out; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci ret = kstrtoint_from_user(buf, count, 0, &enable); 4988c2ecf20Sopenharmony_ci if (ret) 4998c2ecf20Sopenharmony_ci goto out; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ar->debug.pktlog_peer_valid = enable; 5028c2ecf20Sopenharmony_ci memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Send peer based pktlog enable/disable */ 5058c2ecf20Sopenharmony_ci ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable); 5068c2ecf20Sopenharmony_ci if (ret) { 5078c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n", 5088c2ecf20Sopenharmony_ci sta->addr, ret); 5098c2ecf20Sopenharmony_ci goto out; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n", 5138c2ecf20Sopenharmony_ci enable); 5148c2ecf20Sopenharmony_ci ret = count; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ciout: 5178c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 5188c2ecf20Sopenharmony_ci return ret; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file, 5228c2ecf20Sopenharmony_ci char __user *ubuf, 5238c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 5268c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 5278c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 5288c2ecf20Sopenharmony_ci char buf[32] = {0}; 5298c2ecf20Sopenharmony_ci int len; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 5328c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%08x %pM\n", 5338c2ecf20Sopenharmony_ci ar->debug.pktlog_peer_valid, 5348c2ecf20Sopenharmony_ci ar->debug.pktlog_peer_addr); 5358c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic const struct file_operations fops_peer_pktlog = { 5418c2ecf20Sopenharmony_ci .write = ath11k_dbg_sta_write_peer_pktlog, 5428c2ecf20Sopenharmony_ci .read = ath11k_dbg_sta_read_peer_pktlog, 5438c2ecf20Sopenharmony_ci .open = simple_open, 5448c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5458c2ecf20Sopenharmony_ci .llseek = default_llseek, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_write_delba(struct file *file, 5498c2ecf20Sopenharmony_ci const char __user *user_buf, 5508c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 5538c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 5548c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 5558c2ecf20Sopenharmony_ci u32 tid, initiator, reason; 5568c2ecf20Sopenharmony_ci int ret; 5578c2ecf20Sopenharmony_ci char buf[64] = {0}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 5608c2ecf20Sopenharmony_ci user_buf, count); 5618c2ecf20Sopenharmony_ci if (ret <= 0) 5628c2ecf20Sopenharmony_ci return ret; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); 5658c2ecf20Sopenharmony_ci if (ret != 3) 5668c2ecf20Sopenharmony_ci return -EINVAL; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* Valid TID values are 0 through 15 */ 5698c2ecf20Sopenharmony_ci if (tid > HAL_DESC_REO_NON_QOS_TID - 1) 5708c2ecf20Sopenharmony_ci return -EINVAL; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 5738c2ecf20Sopenharmony_ci if (ar->state != ATH11K_STATE_ON || 5748c2ecf20Sopenharmony_ci arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) { 5758c2ecf20Sopenharmony_ci ret = count; 5768c2ecf20Sopenharmony_ci goto out; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, 5808c2ecf20Sopenharmony_ci tid, initiator, reason); 5818c2ecf20Sopenharmony_ci if (ret) { 5828c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", 5838c2ecf20Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, initiator, 5848c2ecf20Sopenharmony_ci reason); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci ret = count; 5878c2ecf20Sopenharmony_ciout: 5888c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 5898c2ecf20Sopenharmony_ci return ret; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic const struct file_operations fops_delba = { 5938c2ecf20Sopenharmony_ci .write = ath11k_dbg_sta_write_delba, 5948c2ecf20Sopenharmony_ci .open = simple_open, 5958c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5968c2ecf20Sopenharmony_ci .llseek = default_llseek, 5978c2ecf20Sopenharmony_ci}; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file, 6008c2ecf20Sopenharmony_ci const char __user *user_buf, 6018c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 6048c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 6058c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 6068c2ecf20Sopenharmony_ci u32 tid, status; 6078c2ecf20Sopenharmony_ci int ret; 6088c2ecf20Sopenharmony_ci char buf[64] = {0}; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 6118c2ecf20Sopenharmony_ci user_buf, count); 6128c2ecf20Sopenharmony_ci if (ret <= 0) 6138c2ecf20Sopenharmony_ci return ret; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u", &tid, &status); 6168c2ecf20Sopenharmony_ci if (ret != 2) 6178c2ecf20Sopenharmony_ci return -EINVAL; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Valid TID values are 0 through 15 */ 6208c2ecf20Sopenharmony_ci if (tid > HAL_DESC_REO_NON_QOS_TID - 1) 6218c2ecf20Sopenharmony_ci return -EINVAL; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 6248c2ecf20Sopenharmony_ci if (ar->state != ATH11K_STATE_ON || 6258c2ecf20Sopenharmony_ci arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) { 6268c2ecf20Sopenharmony_ci ret = count; 6278c2ecf20Sopenharmony_ci goto out; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, 6318c2ecf20Sopenharmony_ci tid, status); 6328c2ecf20Sopenharmony_ci if (ret) { 6338c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", 6348c2ecf20Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, status); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci ret = count; 6378c2ecf20Sopenharmony_ciout: 6388c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6398c2ecf20Sopenharmony_ci return ret; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic const struct file_operations fops_addba_resp = { 6438c2ecf20Sopenharmony_ci .write = ath11k_dbg_sta_write_addba_resp, 6448c2ecf20Sopenharmony_ci .open = simple_open, 6458c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6468c2ecf20Sopenharmony_ci .llseek = default_llseek, 6478c2ecf20Sopenharmony_ci}; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_write_addba(struct file *file, 6508c2ecf20Sopenharmony_ci const char __user *user_buf, 6518c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 6548c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 6558c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 6568c2ecf20Sopenharmony_ci u32 tid, buf_size; 6578c2ecf20Sopenharmony_ci int ret; 6588c2ecf20Sopenharmony_ci char buf[64] = {0}; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 6618c2ecf20Sopenharmony_ci user_buf, count); 6628c2ecf20Sopenharmony_ci if (ret <= 0) 6638c2ecf20Sopenharmony_ci return ret; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u", &tid, &buf_size); 6668c2ecf20Sopenharmony_ci if (ret != 2) 6678c2ecf20Sopenharmony_ci return -EINVAL; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* Valid TID values are 0 through 15 */ 6708c2ecf20Sopenharmony_ci if (tid > HAL_DESC_REO_NON_QOS_TID - 1) 6718c2ecf20Sopenharmony_ci return -EINVAL; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 6748c2ecf20Sopenharmony_ci if (ar->state != ATH11K_STATE_ON || 6758c2ecf20Sopenharmony_ci arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) { 6768c2ecf20Sopenharmony_ci ret = count; 6778c2ecf20Sopenharmony_ci goto out; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, 6818c2ecf20Sopenharmony_ci tid, buf_size); 6828c2ecf20Sopenharmony_ci if (ret) { 6838c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", 6848c2ecf20Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, buf_size); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci ret = count; 6888c2ecf20Sopenharmony_ciout: 6898c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6908c2ecf20Sopenharmony_ci return ret; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic const struct file_operations fops_addba = { 6948c2ecf20Sopenharmony_ci .write = ath11k_dbg_sta_write_addba, 6958c2ecf20Sopenharmony_ci .open = simple_open, 6968c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6978c2ecf20Sopenharmony_ci .llseek = default_llseek, 6988c2ecf20Sopenharmony_ci}; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file, 7018c2ecf20Sopenharmony_ci char __user *user_buf, 7028c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 7058c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 7068c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 7078c2ecf20Sopenharmony_ci char buf[64]; 7088c2ecf20Sopenharmony_ci int len = 0; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 7118c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, 7128c2ecf20Sopenharmony_ci "aggregation mode: %s\n\n%s\n%s\n", 7138c2ecf20Sopenharmony_ci (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ? 7148c2ecf20Sopenharmony_ci "auto" : "manual", "auto = 0", "manual = 1"); 7158c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file, 7218c2ecf20Sopenharmony_ci const char __user *user_buf, 7228c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 7258c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 7268c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 7278c2ecf20Sopenharmony_ci u32 aggr_mode; 7288c2ecf20Sopenharmony_ci int ret; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) 7318c2ecf20Sopenharmony_ci return -EINVAL; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX) 7348c2ecf20Sopenharmony_ci return -EINVAL; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 7378c2ecf20Sopenharmony_ci if (ar->state != ATH11K_STATE_ON || 7388c2ecf20Sopenharmony_ci aggr_mode == arsta->aggr_mode) { 7398c2ecf20Sopenharmony_ci ret = count; 7408c2ecf20Sopenharmony_ci goto out; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); 7448c2ecf20Sopenharmony_ci if (ret) { 7458c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n", 7468c2ecf20Sopenharmony_ci ret); 7478c2ecf20Sopenharmony_ci goto out; 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci arsta->aggr_mode = aggr_mode; 7518c2ecf20Sopenharmony_ciout: 7528c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 7538c2ecf20Sopenharmony_ci return ret; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic const struct file_operations fops_aggr_mode = { 7578c2ecf20Sopenharmony_ci .read = ath11k_dbg_sta_read_aggr_mode, 7588c2ecf20Sopenharmony_ci .write = ath11k_dbg_sta_write_aggr_mode, 7598c2ecf20Sopenharmony_ci .open = simple_open, 7608c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7618c2ecf20Sopenharmony_ci .llseek = default_llseek, 7628c2ecf20Sopenharmony_ci}; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic ssize_t 7658c2ecf20Sopenharmony_ciath11k_write_htt_peer_stats_reset(struct file *file, 7668c2ecf20Sopenharmony_ci const char __user *user_buf, 7678c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 7708c2ecf20Sopenharmony_ci struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; 7718c2ecf20Sopenharmony_ci struct ath11k *ar = arsta->arvif->ar; 7728c2ecf20Sopenharmony_ci struct htt_ext_stats_cfg_params cfg_params = { 0 }; 7738c2ecf20Sopenharmony_ci int ret; 7748c2ecf20Sopenharmony_ci u8 type; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci ret = kstrtou8_from_user(user_buf, count, 0, &type); 7778c2ecf20Sopenharmony_ci if (ret) 7788c2ecf20Sopenharmony_ci return ret; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!type) 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 7848c2ecf20Sopenharmony_ci cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR; 7858c2ecf20Sopenharmony_ci cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1), 7868c2ecf20Sopenharmony_ci HTT_PEER_STATS_REQ_MODE_FLUSH_TQM); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]); 7918c2ecf20Sopenharmony_ci cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]); 7928c2ecf20Sopenharmony_ci cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]); 7938c2ecf20Sopenharmony_ci cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]); 7968c2ecf20Sopenharmony_ci cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar, 8018c2ecf20Sopenharmony_ci ATH11K_DBG_HTT_EXT_STATS_PEER_INFO, 8028c2ecf20Sopenharmony_ci &cfg_params, 8038c2ecf20Sopenharmony_ci 0ULL); 8048c2ecf20Sopenharmony_ci if (ret) { 8058c2ecf20Sopenharmony_ci ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret); 8068c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 8078c2ecf20Sopenharmony_ci return ret; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci ret = count; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return ret; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic const struct file_operations fops_htt_peer_stats_reset = { 8188c2ecf20Sopenharmony_ci .write = ath11k_write_htt_peer_stats_reset, 8198c2ecf20Sopenharmony_ci .open = simple_open, 8208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8218c2ecf20Sopenharmony_ci .llseek = default_llseek, 8228c2ecf20Sopenharmony_ci}; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_civoid ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 8258c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, struct dentry *dir) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci struct ath11k *ar = hw->priv; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) 8308c2ecf20Sopenharmony_ci debugfs_create_file("tx_stats", 0400, dir, sta, 8318c2ecf20Sopenharmony_ci &fops_tx_stats); 8328c2ecf20Sopenharmony_ci if (ath11k_debugfs_is_extd_rx_stats_enabled(ar)) 8338c2ecf20Sopenharmony_ci debugfs_create_file("rx_stats", 0400, dir, sta, 8348c2ecf20Sopenharmony_ci &fops_rx_stats); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci debugfs_create_file("htt_peer_stats", 0400, dir, sta, 8378c2ecf20Sopenharmony_ci &fops_htt_peer_stats); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci debugfs_create_file("peer_pktlog", 0644, dir, sta, 8408c2ecf20Sopenharmony_ci &fops_peer_pktlog); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode); 8438c2ecf20Sopenharmony_ci debugfs_create_file("addba", 0200, dir, sta, &fops_addba); 8448c2ecf20Sopenharmony_ci debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp); 8458c2ecf20Sopenharmony_ci debugfs_create_file("delba", 0200, dir, sta, &fops_delba); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET, 8488c2ecf20Sopenharmony_ci ar->ab->wmi_ab.svc_map)) 8498c2ecf20Sopenharmony_ci debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta, 8508c2ecf20Sopenharmony_ci &fops_htt_peer_stats_reset); 8518c2ecf20Sopenharmony_ci} 852