linux/drivers/net/wireless/ath/ath11k/debugfs_sta.c
<<
>>
Prefs
   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 "core.h"
   9#include "peer.h"
  10#include "debug.h"
  11#include "dp_tx.h"
  12#include "debug_htt_stats.h"
  13
  14void
  15ath11k_accumulate_per_peer_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_update_per_peer_stats_from_txcompl(struct ath11k *ar,
 129                                               struct sk_buff *msdu,
 130                                               struct hal_tx_status *ts)
 131{
 132        struct ath11k_base *ab = ar->ab;
 133        struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
 134        enum hal_tx_rate_stats_pkt_type pkt_type;
 135        enum hal_tx_rate_stats_sgi sgi;
 136        enum hal_tx_rate_stats_bw bw;
 137        struct ath11k_peer *peer;
 138        struct ath11k_sta *arsta;
 139        struct ieee80211_sta *sta;
 140        u16 rate;
 141        u8 rate_idx = 0;
 142        int ret;
 143        u8 mcs;
 144
 145        rcu_read_lock();
 146        spin_lock_bh(&ab->base_lock);
 147        peer = ath11k_peer_find_by_id(ab, ts->peer_id);
 148        if (!peer || !peer->sta) {
 149                ath11k_warn(ab, "failed to find the peer\n");
 150                spin_unlock_bh(&ab->base_lock);
 151                rcu_read_unlock();
 152                return;
 153        }
 154
 155        sta = peer->sta;
 156        arsta = (struct ath11k_sta *)sta->drv_priv;
 157
 158        memset(&arsta->txrate, 0, sizeof(arsta->txrate));
 159        pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
 160                             ts->rate_stats);
 161        mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
 162                        ts->rate_stats);
 163        sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
 164                        ts->rate_stats);
 165        bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);
 166
 167        if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
 168            pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
 169                ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
 170                                                            pkt_type,
 171                                                            &rate_idx,
 172                                                            &rate);
 173                if (ret < 0)
 174                        goto err_out;
 175                arsta->txrate.legacy = rate;
 176        } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
 177                if (mcs > 7) {
 178                        ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);
 179                        goto err_out;
 180                }
 181
 182                arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1);
 183                arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
 184                if (sgi)
 185                        arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
 186        } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
 187                if (mcs > 9) {
 188                        ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);
 189                        goto err_out;
 190                }
 191
 192                arsta->txrate.mcs = mcs;
 193                arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
 194                if (sgi)
 195                        arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
 196        } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
 197                /* TODO */
 198        }
 199
 200        arsta->txrate.nss = arsta->last_txrate.nss;
 201        arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
 202
 203        ath11k_accumulate_per_peer_tx_stats(arsta, peer_stats, rate_idx);
 204err_out:
 205        spin_unlock_bh(&ab->base_lock);
 206        rcu_read_unlock();
 207}
 208
 209static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
 210                                            char __user *user_buf,
 211                                            size_t count, loff_t *ppos)
 212{
 213        struct ieee80211_sta *sta = file->private_data;
 214        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 215        struct ath11k *ar = arsta->arvif->ar;
 216        struct ath11k_htt_data_stats *stats;
 217        static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
 218                                                              "retry", "ampdu"};
 219        static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
 220        int len = 0, i, j, k, retval = 0;
 221        const int size = 2 * 4096;
 222        char *buf;
 223
 224        if (!arsta->tx_stats)
 225                return -ENOENT;
 226
 227        buf = kzalloc(size, GFP_KERNEL);
 228        if (!buf)
 229                return -ENOMEM;
 230
 231        mutex_lock(&ar->conf_mutex);
 232
 233        spin_lock_bh(&ar->data_lock);
 234        for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
 235                for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
 236                        stats = &arsta->tx_stats->stats[k];
 237                        len += scnprintf(buf + len, size - len, "%s_%s\n",
 238                                         str_name[k],
 239                                         str[j]);
 240                        len += scnprintf(buf + len, size - len,
 241                                         " HE MCS %s\n",
 242                                         str[j]);
 243                        for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
 244                                len += scnprintf(buf + len, size - len,
 245                                                 "  %llu ",
 246                                                 stats->he[j][i]);
 247                        len += scnprintf(buf + len, size - len, "\n");
 248                        len += scnprintf(buf + len, size - len,
 249                                         " VHT MCS %s\n",
 250                                         str[j]);
 251                        for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
 252                                len += scnprintf(buf + len, size - len,
 253                                                 "  %llu ",
 254                                                 stats->vht[j][i]);
 255                        len += scnprintf(buf + len, size - len, "\n");
 256                        len += scnprintf(buf + len, size - len, " HT MCS %s\n",
 257                                         str[j]);
 258                        for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
 259                                len += scnprintf(buf + len, size - len,
 260                                                 "  %llu ", stats->ht[j][i]);
 261                        len += scnprintf(buf + len, size - len, "\n");
 262                        len += scnprintf(buf + len, size - len,
 263                                        " BW %s (20,40,80,160 MHz)\n", str[j]);
 264                        len += scnprintf(buf + len, size - len,
 265                                         "  %llu %llu %llu %llu\n",
 266                                         stats->bw[j][0], stats->bw[j][1],
 267                                         stats->bw[j][2], stats->bw[j][3]);
 268                        len += scnprintf(buf + len, size - len,
 269                                         " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
 270                        len += scnprintf(buf + len, size - len,
 271                                         "  %llu %llu %llu %llu\n",
 272                                         stats->nss[j][0], stats->nss[j][1],
 273                                         stats->nss[j][2], stats->nss[j][3]);
 274                        len += scnprintf(buf + len, size - len,
 275                                         " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
 276                                         str[j]);
 277                        len += scnprintf(buf + len, size - len,
 278                                         "  %llu %llu %llu %llu\n",
 279                                         stats->gi[j][0], stats->gi[j][1],
 280                                         stats->gi[j][2], stats->gi[j][3]);
 281                        len += scnprintf(buf + len, size - len,
 282                                         " legacy rate %s (1,2 ... Mbps)\n  ",
 283                                         str[j]);
 284                        for (i = 0; i < ATH11K_LEGACY_NUM; i++)
 285                                len += scnprintf(buf + len, size - len, "%llu ",
 286                                                 stats->legacy[j][i]);
 287                        len += scnprintf(buf + len, size - len, "\n");
 288                }
 289        }
 290
 291        len += scnprintf(buf + len, size - len,
 292                         "\nTX duration\n %llu usecs\n",
 293                         arsta->tx_stats->tx_duration);
 294        len += scnprintf(buf + len, size - len,
 295                        "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
 296        len += scnprintf(buf + len, size - len,
 297                        "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
 298        spin_unlock_bh(&ar->data_lock);
 299
 300        if (len > size)
 301                len = size;
 302        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 303        kfree(buf);
 304
 305        mutex_unlock(&ar->conf_mutex);
 306        return retval;
 307}
 308
 309static const struct file_operations fops_tx_stats = {
 310        .read = ath11k_dbg_sta_dump_tx_stats,
 311        .open = simple_open,
 312        .owner = THIS_MODULE,
 313        .llseek = default_llseek,
 314};
 315
 316static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
 317                                            char __user *user_buf,
 318                                            size_t count, loff_t *ppos)
 319{
 320        struct ieee80211_sta *sta = file->private_data;
 321        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 322        struct ath11k *ar = arsta->arvif->ar;
 323        struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
 324        int len = 0, i, retval = 0;
 325        const int size = 4096;
 326        char *buf;
 327
 328        if (!rx_stats)
 329                return -ENOENT;
 330
 331        buf = kzalloc(size, GFP_KERNEL);
 332        if (!buf)
 333                return -ENOMEM;
 334
 335        mutex_lock(&ar->conf_mutex);
 336        spin_lock_bh(&ar->ab->base_lock);
 337
 338        len += scnprintf(buf + len, size - len, "RX peer stats:\n");
 339        len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
 340                         rx_stats->num_msdu);
 341        len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
 342                         rx_stats->tcp_msdu_count);
 343        len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
 344                         rx_stats->udp_msdu_count);
 345        len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
 346                         rx_stats->ampdu_msdu_count);
 347        len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
 348                         rx_stats->non_ampdu_msdu_count);
 349        len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
 350                         rx_stats->stbc_count);
 351        len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
 352                         rx_stats->beamformed_count);
 353        len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
 354                         rx_stats->num_mpdu_fcs_ok);
 355        len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
 356                         rx_stats->num_mpdu_fcs_err);
 357        len += scnprintf(buf + len, size - len,
 358                         "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
 359                         rx_stats->gi_count[0], rx_stats->gi_count[1],
 360                         rx_stats->gi_count[2], rx_stats->gi_count[3]);
 361        len += scnprintf(buf + len, size - len,
 362                         "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
 363                         rx_stats->bw_count[0], rx_stats->bw_count[1],
 364                         rx_stats->bw_count[2], rx_stats->bw_count[3]);
 365        len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
 366                         rx_stats->coding_count[0], rx_stats->coding_count[1]);
 367        len += scnprintf(buf + len, size - len,
 368                         "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
 369                         rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
 370                         rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
 371                         rx_stats->pream_cnt[4]);
 372        len += scnprintf(buf + len, size - len,
 373                         "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
 374                         rx_stats->reception_type[0], rx_stats->reception_type[1],
 375                         rx_stats->reception_type[2], rx_stats->reception_type[3]);
 376        len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
 377        for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
 378                len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
 379        len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
 380        for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
 381                len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
 382        len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
 383        for (i = 0; i < HAL_RX_MAX_NSS; i++)
 384                len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
 385        len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
 386                         rx_stats->rx_duration);
 387        len += scnprintf(buf + len, size - len,
 388                         "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
 389                         rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
 390                         rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
 391                         rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
 392                         rx_stats->ru_alloc_cnt[5]);
 393
 394        len += scnprintf(buf + len, size - len, "\n");
 395
 396        spin_unlock_bh(&ar->ab->base_lock);
 397
 398        if (len > size)
 399                len = size;
 400        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 401        kfree(buf);
 402
 403        mutex_unlock(&ar->conf_mutex);
 404        return retval;
 405}
 406
 407static const struct file_operations fops_rx_stats = {
 408        .read = ath11k_dbg_sta_dump_rx_stats,
 409        .open = simple_open,
 410        .owner = THIS_MODULE,
 411        .llseek = default_llseek,
 412};
 413
 414static int
 415ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
 416{
 417        struct ieee80211_sta *sta = inode->i_private;
 418        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 419        struct ath11k *ar = arsta->arvif->ar;
 420        struct debug_htt_stats_req *stats_req;
 421        int ret;
 422
 423        stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
 424        if (!stats_req)
 425                return -ENOMEM;
 426
 427        mutex_lock(&ar->conf_mutex);
 428        ar->debug.htt_stats.stats_req = stats_req;
 429        stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
 430        memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
 431        ret = ath11k_dbg_htt_stats_req(ar);
 432        mutex_unlock(&ar->conf_mutex);
 433        if (ret < 0)
 434                goto out;
 435
 436        file->private_data = stats_req;
 437        return 0;
 438out:
 439        vfree(stats_req);
 440        ar->debug.htt_stats.stats_req = NULL;
 441        return ret;
 442}
 443
 444static int
 445ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
 446{
 447        struct ieee80211_sta *sta = inode->i_private;
 448        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 449        struct ath11k *ar = arsta->arvif->ar;
 450
 451        mutex_lock(&ar->conf_mutex);
 452        vfree(file->private_data);
 453        ar->debug.htt_stats.stats_req = NULL;
 454        mutex_unlock(&ar->conf_mutex);
 455
 456        return 0;
 457}
 458
 459static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
 460                                                  char __user *user_buf,
 461                                                  size_t count, loff_t *ppos)
 462{
 463        struct debug_htt_stats_req *stats_req = file->private_data;
 464        char *buf;
 465        u32 length = 0;
 466
 467        buf = stats_req->buf;
 468        length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
 469        return simple_read_from_buffer(user_buf, count, ppos, buf, length);
 470}
 471
 472static const struct file_operations fops_htt_peer_stats = {
 473        .open = ath11k_dbg_sta_open_htt_peer_stats,
 474        .release = ath11k_dbg_sta_release_htt_peer_stats,
 475        .read = ath11k_dbg_sta_read_htt_peer_stats,
 476        .owner = THIS_MODULE,
 477        .llseek = default_llseek,
 478};
 479
 480static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
 481                                                const char __user *buf,
 482                                                size_t count, loff_t *ppos)
 483{
 484        struct ieee80211_sta *sta = file->private_data;
 485        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 486        struct ath11k *ar = arsta->arvif->ar;
 487        int ret, enable;
 488
 489        mutex_lock(&ar->conf_mutex);
 490
 491        if (ar->state != ATH11K_STATE_ON) {
 492                ret = -ENETDOWN;
 493                goto out;
 494        }
 495
 496        ret = kstrtoint_from_user(buf, count, 0, &enable);
 497        if (ret)
 498                goto out;
 499
 500        ar->debug.pktlog_peer_valid = enable;
 501        memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
 502
 503        /* Send peer based pktlog enable/disable */
 504        ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
 505        if (ret) {
 506                ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
 507                            sta->addr, ret);
 508                goto out;
 509        }
 510
 511        ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
 512                   enable);
 513        ret = count;
 514
 515out:
 516        mutex_unlock(&ar->conf_mutex);
 517        return ret;
 518}
 519
 520static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
 521                                               char __user *ubuf,
 522                                               size_t count, loff_t *ppos)
 523{
 524        struct ieee80211_sta *sta = file->private_data;
 525        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 526        struct ath11k *ar = arsta->arvif->ar;
 527        char buf[32] = {0};
 528        int len;
 529
 530        mutex_lock(&ar->conf_mutex);
 531        len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
 532                        ar->debug.pktlog_peer_valid,
 533                        ar->debug.pktlog_peer_addr);
 534        mutex_unlock(&ar->conf_mutex);
 535
 536        return simple_read_from_buffer(ubuf, count, ppos, buf, len);
 537}
 538
 539static const struct file_operations fops_peer_pktlog = {
 540        .write = ath11k_dbg_sta_write_peer_pktlog,
 541        .read = ath11k_dbg_sta_read_peer_pktlog,
 542        .open = simple_open,
 543        .owner = THIS_MODULE,
 544        .llseek = default_llseek,
 545};
 546
 547static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
 548                                          const char __user *user_buf,
 549                                          size_t count, loff_t *ppos)
 550{
 551        struct ieee80211_sta *sta = file->private_data;
 552        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 553        struct ath11k *ar = arsta->arvif->ar;
 554        u32 tid, initiator, reason;
 555        int ret;
 556        char buf[64] = {0};
 557
 558        ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
 559                                     user_buf, count);
 560        if (ret <= 0)
 561                return ret;
 562
 563        ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
 564        if (ret != 3)
 565                return -EINVAL;
 566
 567        /* Valid TID values are 0 through 15 */
 568        if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
 569                return -EINVAL;
 570
 571        mutex_lock(&ar->conf_mutex);
 572        if (ar->state != ATH11K_STATE_ON ||
 573            arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
 574                ret = count;
 575                goto out;
 576        }
 577
 578        ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
 579                                    tid, initiator, reason);
 580        if (ret) {
 581                ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
 582                            arsta->arvif->vdev_id, sta->addr, tid, initiator,
 583                            reason);
 584        }
 585        ret = count;
 586out:
 587        mutex_unlock(&ar->conf_mutex);
 588        return ret;
 589}
 590
 591static const struct file_operations fops_delba = {
 592        .write = ath11k_dbg_sta_write_delba,
 593        .open = simple_open,
 594        .owner = THIS_MODULE,
 595        .llseek = default_llseek,
 596};
 597
 598static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
 599                                               const char __user *user_buf,
 600                                               size_t count, loff_t *ppos)
 601{
 602        struct ieee80211_sta *sta = file->private_data;
 603        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 604        struct ath11k *ar = arsta->arvif->ar;
 605        u32 tid, status;
 606        int ret;
 607        char buf[64] = {0};
 608
 609        ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
 610                                     user_buf, count);
 611        if (ret <= 0)
 612                return ret;
 613
 614        ret = sscanf(buf, "%u %u", &tid, &status);
 615        if (ret != 2)
 616                return -EINVAL;
 617
 618        /* Valid TID values are 0 through 15 */
 619        if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
 620                return -EINVAL;
 621
 622        mutex_lock(&ar->conf_mutex);
 623        if (ar->state != ATH11K_STATE_ON ||
 624            arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
 625                ret = count;
 626                goto out;
 627        }
 628
 629        ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
 630                                        tid, status);
 631        if (ret) {
 632                ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
 633                            arsta->arvif->vdev_id, sta->addr, tid, status);
 634        }
 635        ret = count;
 636out:
 637        mutex_unlock(&ar->conf_mutex);
 638        return ret;
 639}
 640
 641static const struct file_operations fops_addba_resp = {
 642        .write = ath11k_dbg_sta_write_addba_resp,
 643        .open = simple_open,
 644        .owner = THIS_MODULE,
 645        .llseek = default_llseek,
 646};
 647
 648static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
 649                                          const char __user *user_buf,
 650                                          size_t count, loff_t *ppos)
 651{
 652        struct ieee80211_sta *sta = file->private_data;
 653        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 654        struct ath11k *ar = arsta->arvif->ar;
 655        u32 tid, buf_size;
 656        int ret;
 657        char buf[64] = {0};
 658
 659        ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
 660                                     user_buf, count);
 661        if (ret <= 0)
 662                return ret;
 663
 664        ret = sscanf(buf, "%u %u", &tid, &buf_size);
 665        if (ret != 2)
 666                return -EINVAL;
 667
 668        /* Valid TID values are 0 through 15 */
 669        if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
 670                return -EINVAL;
 671
 672        mutex_lock(&ar->conf_mutex);
 673        if (ar->state != ATH11K_STATE_ON ||
 674            arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
 675                ret = count;
 676                goto out;
 677        }
 678
 679        ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
 680                                    tid, buf_size);
 681        if (ret) {
 682                ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
 683                            arsta->arvif->vdev_id, sta->addr, tid, buf_size);
 684        }
 685
 686        ret = count;
 687out:
 688        mutex_unlock(&ar->conf_mutex);
 689        return ret;
 690}
 691
 692static const struct file_operations fops_addba = {
 693        .write = ath11k_dbg_sta_write_addba,
 694        .open = simple_open,
 695        .owner = THIS_MODULE,
 696        .llseek = default_llseek,
 697};
 698
 699static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
 700                                             char __user *user_buf,
 701                                             size_t count, loff_t *ppos)
 702{
 703        struct ieee80211_sta *sta = file->private_data;
 704        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 705        struct ath11k *ar = arsta->arvif->ar;
 706        char buf[64];
 707        int len = 0;
 708
 709        mutex_lock(&ar->conf_mutex);
 710        len = scnprintf(buf, sizeof(buf) - len,
 711                        "aggregation mode: %s\n\n%s\n%s\n",
 712                        (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
 713                        "auto" : "manual", "auto = 0", "manual = 1");
 714        mutex_unlock(&ar->conf_mutex);
 715
 716        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 717}
 718
 719static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
 720                                              const char __user *user_buf,
 721                                              size_t count, loff_t *ppos)
 722{
 723        struct ieee80211_sta *sta = file->private_data;
 724        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 725        struct ath11k *ar = arsta->arvif->ar;
 726        u32 aggr_mode;
 727        int ret;
 728
 729        if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
 730                return -EINVAL;
 731
 732        if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
 733                return -EINVAL;
 734
 735        mutex_lock(&ar->conf_mutex);
 736        if (ar->state != ATH11K_STATE_ON ||
 737            aggr_mode == arsta->aggr_mode) {
 738                ret = count;
 739                goto out;
 740        }
 741
 742        ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
 743        if (ret) {
 744                ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
 745                            ret);
 746                goto out;
 747        }
 748
 749        arsta->aggr_mode = aggr_mode;
 750out:
 751        mutex_unlock(&ar->conf_mutex);
 752        return ret;
 753}
 754
 755static const struct file_operations fops_aggr_mode = {
 756        .read = ath11k_dbg_sta_read_aggr_mode,
 757        .write = ath11k_dbg_sta_write_aggr_mode,
 758        .open = simple_open,
 759        .owner = THIS_MODULE,
 760        .llseek = default_llseek,
 761};
 762
 763static ssize_t
 764ath11k_write_htt_peer_stats_reset(struct file *file,
 765                                  const char __user *user_buf,
 766                                  size_t count, loff_t *ppos)
 767{
 768        struct ieee80211_sta *sta = file->private_data;
 769        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 770        struct ath11k *ar = arsta->arvif->ar;
 771        struct htt_ext_stats_cfg_params cfg_params = { 0 };
 772        int ret;
 773        u8 type;
 774
 775        ret = kstrtou8_from_user(user_buf, count, 0, &type);
 776        if (ret)
 777                return ret;
 778
 779        if (!type)
 780                return ret;
 781
 782        mutex_lock(&ar->conf_mutex);
 783        cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
 784        cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
 785                                HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
 786
 787        cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
 788
 789        cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
 790        cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
 791        cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
 792        cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
 793
 794        cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
 795        cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
 796
 797        cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
 798
 799        ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
 800                                                 ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
 801                                                 &cfg_params,
 802                                                 0ULL);
 803        if (ret) {
 804                ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
 805                mutex_unlock(&ar->conf_mutex);
 806                return ret;
 807        }
 808
 809        mutex_unlock(&ar->conf_mutex);
 810
 811        ret = count;
 812
 813        return ret;
 814}
 815
 816static const struct file_operations fops_htt_peer_stats_reset = {
 817        .write = ath11k_write_htt_peer_stats_reset,
 818        .open = simple_open,
 819        .owner = THIS_MODULE,
 820        .llseek = default_llseek,
 821};
 822
 823void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 824                            struct ieee80211_sta *sta, struct dentry *dir)
 825{
 826        struct ath11k *ar = hw->priv;
 827
 828        if (ath11k_debug_is_extd_tx_stats_enabled(ar))
 829                debugfs_create_file("tx_stats", 0400, dir, sta,
 830                                    &fops_tx_stats);
 831        if (ath11k_debug_is_extd_rx_stats_enabled(ar))
 832                debugfs_create_file("rx_stats", 0400, dir, sta,
 833                                    &fops_rx_stats);
 834
 835        debugfs_create_file("htt_peer_stats", 0400, dir, sta,
 836                            &fops_htt_peer_stats);
 837
 838        debugfs_create_file("peer_pktlog", 0644, dir, sta,
 839                            &fops_peer_pktlog);
 840
 841        debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
 842        debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
 843        debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
 844        debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
 845
 846        if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
 847                     ar->ab->wmi_ab.svc_map))
 848                debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
 849                                    &fops_htt_peer_stats_reset);
 850}
 851