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