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
  12void
  13ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
  14                                    struct ath11k_per_peer_tx_stats *peer_stats,
  15                                    u8 legacy_rate_idx)
  16{
  17        struct rate_info *txrate = &arsta->txrate;
  18        struct ath11k_htt_tx_stats *tx_stats;
  19        int gi, mcs, bw, nss;
  20
  21        if (!arsta->tx_stats)
  22                return;
  23
  24        tx_stats = arsta->tx_stats;
  25        gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
  26        mcs = txrate->mcs;
  27        bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
  28        nss = txrate->nss - 1;
  29
  30#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
  31
  32        if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
  33                STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
  34                STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
  35                STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
  36                STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
  37                STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
  38                STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
  39        } else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
  40                STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
  41                STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
  42                STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
  43                STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
  44                STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
  45                STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
  46        } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
  47                STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
  48                STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
  49                STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
  50                STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
  51                STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
  52                STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
  53        } else {
  54                mcs = legacy_rate_idx;
  55
  56                STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
  57                STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
  58                STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
  59                STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
  60                STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
  61                STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
  62        }
  63
  64        if (peer_stats->is_ampdu) {
  65                tx_stats->ba_fails += peer_stats->ba_fails;
  66
  67                if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
  68                        STATS_OP_FMT(AMPDU).he[0][mcs] +=
  69                        peer_stats->succ_bytes + peer_stats->retry_bytes;
  70                        STATS_OP_FMT(AMPDU).he[1][mcs] +=
  71                        peer_stats->succ_pkts + peer_stats->retry_pkts;
  72                } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
  73                        STATS_OP_FMT(AMPDU).ht[0][mcs] +=
  74                        peer_stats->succ_bytes + peer_stats->retry_bytes;
  75                        STATS_OP_FMT(AMPDU).ht[1][mcs] +=
  76                        peer_stats->succ_pkts + peer_stats->retry_pkts;
  77                } else {
  78                        STATS_OP_FMT(AMPDU).vht[0][mcs] +=
  79                        peer_stats->succ_bytes + peer_stats->retry_bytes;
  80                        STATS_OP_FMT(AMPDU).vht[1][mcs] +=
  81                        peer_stats->succ_pkts + peer_stats->retry_pkts;
  82                }
  83                STATS_OP_FMT(AMPDU).bw[0][bw] +=
  84                        peer_stats->succ_bytes + peer_stats->retry_bytes;
  85                STATS_OP_FMT(AMPDU).nss[0][nss] +=
  86                        peer_stats->succ_bytes + peer_stats->retry_bytes;
  87                STATS_OP_FMT(AMPDU).gi[0][gi] +=
  88                        peer_stats->succ_bytes + peer_stats->retry_bytes;
  89                STATS_OP_FMT(AMPDU).bw[1][bw] +=
  90                        peer_stats->succ_pkts + peer_stats->retry_pkts;
  91                STATS_OP_FMT(AMPDU).nss[1][nss] +=
  92                        peer_stats->succ_pkts + peer_stats->retry_pkts;
  93                STATS_OP_FMT(AMPDU).gi[1][gi] +=
  94                        peer_stats->succ_pkts + peer_stats->retry_pkts;
  95        } else {
  96                tx_stats->ack_fails += peer_stats->ba_fails;
  97        }
  98
  99        STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
 100        STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
 101        STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
 102
 103        STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
 104        STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
 105        STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
 106
 107        STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
 108        STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
 109        STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
 110
 111        STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
 112        STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
 113        STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
 114
 115        STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
 116        STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
 117        STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
 118
 119        STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
 120        STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
 121        STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
 122
 123        tx_stats->tx_duration += peer_stats->duration;
 124}
 125
 126void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
 127                                               struct sk_buff *msdu,
 128                                               struct hal_tx_status *ts)
 129{
 130        struct ath11k_base *ab = ar->ab;
 131        struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
 132        enum hal_tx_rate_stats_pkt_type pkt_type;
 133        enum hal_tx_rate_stats_sgi sgi;
 134        enum hal_tx_rate_stats_bw bw;
 135        struct ath11k_peer *peer;
 136        struct ath11k_sta *arsta;
 137        struct ieee80211_sta *sta;
 138        u16 rate;
 139        u8 rate_idx = 0;
 140        int ret;
 141        u8 mcs;
 142
 143        rcu_read_lock();
 144        spin_lock_bh(&ab->base_lock);
 145        peer = ath11k_peer_find_by_id(ab, ts->peer_id);
 146        if (!peer || !peer->sta) {
 147                ath11k_warn(ab, "failed to find the peer\n");
 148                spin_unlock_bh(&ab->base_lock);
 149                rcu_read_unlock();
 150                return;
 151        }
 152
 153        sta = peer->sta;
 154        arsta = (struct ath11k_sta *)sta->drv_priv;
 155
 156        memset(&arsta->txrate, 0, sizeof(arsta->txrate));
 157        pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
 158                             ts->rate_stats);
 159        mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
 160                        ts->rate_stats);
 161        sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
 162                        ts->rate_stats);
 163        bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);
 164
 165        if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
 166            pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
 167                ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
 168                                                            pkt_type,
 169                                                            &rate_idx,
 170                                                            &rate);
 171                if (ret < 0)
 172                        goto err_out;
 173                arsta->txrate.legacy = rate;
 174        } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
 175                if (mcs > 7) {
 176                        ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);
 177                        goto err_out;
 178                }
 179
 180                arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1);
 181                arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
 182                if (sgi)
 183                        arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
 184        } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
 185                if (mcs > 9) {
 186                        ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);
 187                        goto err_out;
 188                }
 189
 190                arsta->txrate.mcs = mcs;
 191                arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
 192                if (sgi)
 193                        arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
 194        } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
 195                /* TODO */
 196        }
 197
 198        arsta->txrate.nss = arsta->last_txrate.nss;
 199        arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
 200
 201        ath11k_accumulate_per_peer_tx_stats(arsta, peer_stats, rate_idx);
 202err_out:
 203        spin_unlock_bh(&ab->base_lock);
 204        rcu_read_unlock();
 205}
 206
 207static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
 208                                            char __user *user_buf,
 209                                            size_t count, loff_t *ppos)
 210{
 211        struct ieee80211_sta *sta = file->private_data;
 212        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 213        struct ath11k *ar = arsta->arvif->ar;
 214        struct ath11k_htt_data_stats *stats;
 215        static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
 216                                                              "retry", "ampdu"};
 217        static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
 218        int len = 0, i, j, k, retval = 0;
 219        const int size = 2 * 4096;
 220        char *buf;
 221
 222        if (!arsta->tx_stats)
 223                return -ENOENT;
 224
 225        buf = kzalloc(size, GFP_KERNEL);
 226        if (!buf)
 227                return -ENOMEM;
 228
 229        mutex_lock(&ar->conf_mutex);
 230
 231        spin_lock_bh(&ar->data_lock);
 232        for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
 233                for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
 234                        stats = &arsta->tx_stats->stats[k];
 235                        len += scnprintf(buf + len, size - len, "%s_%s\n",
 236                                         str_name[k],
 237                                         str[j]);
 238                        len += scnprintf(buf + len, size - len,
 239                                         " HE MCS %s\n",
 240                                         str[j]);
 241                        for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
 242                                len += scnprintf(buf + len, size - len,
 243                                                 "  %llu ",
 244                                                 stats->he[j][i]);
 245                        len += scnprintf(buf + len, size - len, "\n");
 246                        len += scnprintf(buf + len, size - len,
 247                                         " VHT MCS %s\n",
 248                                         str[j]);
 249                        for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
 250                                len += scnprintf(buf + len, size - len,
 251                                                 "  %llu ",
 252                                                 stats->vht[j][i]);
 253                        len += scnprintf(buf + len, size - len, "\n");
 254                        len += scnprintf(buf + len, size - len, " HT MCS %s\n",
 255                                         str[j]);
 256                        for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
 257                                len += scnprintf(buf + len, size - len,
 258                                                 "  %llu ", stats->ht[j][i]);
 259                        len += scnprintf(buf + len, size - len, "\n");
 260                        len += scnprintf(buf + len, size - len,
 261                                        " BW %s (20,40,80,160 MHz)\n", str[j]);
 262                        len += scnprintf(buf + len, size - len,
 263                                         "  %llu %llu %llu %llu\n",
 264                                         stats->bw[j][0], stats->bw[j][1],
 265                                         stats->bw[j][2], stats->bw[j][3]);
 266                        len += scnprintf(buf + len, size - len,
 267                                         " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
 268                        len += scnprintf(buf + len, size - len,
 269                                         "  %llu %llu %llu %llu\n",
 270                                         stats->nss[j][0], stats->nss[j][1],
 271                                         stats->nss[j][2], stats->nss[j][3]);
 272                        len += scnprintf(buf + len, size - len,
 273                                         " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
 274                                         str[j]);
 275                        len += scnprintf(buf + len, size - len,
 276                                         "  %llu %llu %llu %llu\n",
 277                                         stats->gi[j][0], stats->gi[j][1],
 278                                         stats->gi[j][2], stats->gi[j][3]);
 279                        len += scnprintf(buf + len, size - len,
 280                                         " legacy rate %s (1,2 ... Mbps)\n  ",
 281                                         str[j]);
 282                        for (i = 0; i < ATH11K_LEGACY_NUM; i++)
 283                                len += scnprintf(buf + len, size - len, "%llu ",
 284                                                 stats->legacy[j][i]);
 285                        len += scnprintf(buf + len, size - len, "\n");
 286                }
 287        }
 288
 289        len += scnprintf(buf + len, size - len,
 290                         "\nTX duration\n %llu usecs\n",
 291                         arsta->tx_stats->tx_duration);
 292        len += scnprintf(buf + len, size - len,
 293                        "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
 294        len += scnprintf(buf + len, size - len,
 295                        "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
 296        spin_unlock_bh(&ar->data_lock);
 297
 298        if (len > size)
 299                len = size;
 300        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 301        kfree(buf);
 302
 303        mutex_unlock(&ar->conf_mutex);
 304        return retval;
 305}
 306
 307static const struct file_operations fops_tx_stats = {
 308        .read = ath11k_dbg_sta_dump_tx_stats,
 309        .open = simple_open,
 310        .owner = THIS_MODULE,
 311        .llseek = default_llseek,
 312};
 313
 314static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
 315                                            char __user *user_buf,
 316                                            size_t count, loff_t *ppos)
 317{
 318        struct ieee80211_sta *sta = file->private_data;
 319        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 320        struct ath11k *ar = arsta->arvif->ar;
 321        struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
 322        int len = 0, i, retval = 0;
 323        const int size = 4096;
 324        char *buf;
 325
 326        if (!rx_stats)
 327                return -ENOENT;
 328
 329        buf = kzalloc(size, GFP_KERNEL);
 330        if (!buf)
 331                return -ENOMEM;
 332
 333        mutex_lock(&ar->conf_mutex);
 334        spin_lock_bh(&ar->ab->base_lock);
 335
 336        len += scnprintf(buf + len, size - len, "RX peer stats:\n");
 337        len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
 338                         rx_stats->num_msdu);
 339        len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
 340                         rx_stats->tcp_msdu_count);
 341        len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
 342                         rx_stats->udp_msdu_count);
 343        len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
 344                         rx_stats->ampdu_msdu_count);
 345        len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
 346                         rx_stats->non_ampdu_msdu_count);
 347        len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
 348                         rx_stats->stbc_count);
 349        len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
 350                         rx_stats->beamformed_count);
 351        len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
 352                         rx_stats->num_mpdu_fcs_ok);
 353        len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
 354                         rx_stats->num_mpdu_fcs_err);
 355        len += scnprintf(buf + len, size - len,
 356                         "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
 357                         rx_stats->gi_count[0], rx_stats->gi_count[1],
 358                         rx_stats->gi_count[2], rx_stats->gi_count[3]);
 359        len += scnprintf(buf + len, size - len,
 360                         "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
 361                         rx_stats->bw_count[0], rx_stats->bw_count[1],
 362                         rx_stats->bw_count[2], rx_stats->bw_count[3]);
 363        len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
 364                         rx_stats->coding_count[0], rx_stats->coding_count[1]);
 365        len += scnprintf(buf + len, size - len,
 366                         "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
 367                         rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
 368                         rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
 369                         rx_stats->pream_cnt[4]);
 370        len += scnprintf(buf + len, size - len,
 371                         "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
 372                         rx_stats->reception_type[0], rx_stats->reception_type[1],
 373                         rx_stats->reception_type[2], rx_stats->reception_type[3]);
 374        len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
 375        for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
 376                len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
 377        len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
 378        for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
 379                len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
 380        len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
 381        for (i = 0; i < HAL_RX_MAX_NSS; i++)
 382                len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
 383        len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
 384                         rx_stats->rx_duration);
 385        len += scnprintf(buf + len, size - len,
 386                         "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
 387                         rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
 388                         rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
 389                         rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
 390                         rx_stats->ru_alloc_cnt[5]);
 391
 392        len += scnprintf(buf + len, size - len, "\n");
 393
 394        spin_unlock_bh(&ar->ab->base_lock);
 395
 396        if (len > size)
 397                len = size;
 398        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 399        kfree(buf);
 400
 401        mutex_unlock(&ar->conf_mutex);
 402        return retval;
 403}
 404
 405static const struct file_operations fops_rx_stats = {
 406        .read = ath11k_dbg_sta_dump_rx_stats,
 407        .open = simple_open,
 408        .owner = THIS_MODULE,
 409        .llseek = default_llseek,
 410};
 411
 412static int
 413ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
 414{
 415        struct ieee80211_sta *sta = inode->i_private;
 416        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 417        struct ath11k *ar = arsta->arvif->ar;
 418        struct debug_htt_stats_req *stats_req;
 419        int ret;
 420
 421        stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
 422        if (!stats_req)
 423                return -ENOMEM;
 424
 425        mutex_lock(&ar->conf_mutex);
 426        ar->debug.htt_stats.stats_req = stats_req;
 427        stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
 428        memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
 429        ret = ath11k_dbg_htt_stats_req(ar);
 430        mutex_unlock(&ar->conf_mutex);
 431        if (ret < 0)
 432                goto out;
 433
 434        file->private_data = stats_req;
 435        return 0;
 436out:
 437        vfree(stats_req);
 438        return ret;
 439}
 440
 441static int
 442ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
 443{
 444        vfree(file->private_data);
 445        return 0;
 446}
 447
 448static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
 449                                                  char __user *user_buf,
 450                                                  size_t count, loff_t *ppos)
 451{
 452        struct debug_htt_stats_req *stats_req = file->private_data;
 453        char *buf;
 454        u32 length = 0;
 455
 456        buf = stats_req->buf;
 457        length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
 458        return simple_read_from_buffer(user_buf, count, ppos, buf, length);
 459}
 460
 461static const struct file_operations fops_htt_peer_stats = {
 462        .open = ath11k_dbg_sta_open_htt_peer_stats,
 463        .release = ath11k_dbg_sta_release_htt_peer_stats,
 464        .read = ath11k_dbg_sta_read_htt_peer_stats,
 465        .owner = THIS_MODULE,
 466        .llseek = default_llseek,
 467};
 468
 469static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
 470                                                const char __user *buf,
 471                                                size_t count, loff_t *ppos)
 472{
 473        struct ieee80211_sta *sta = file->private_data;
 474        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 475        struct ath11k *ar = arsta->arvif->ar;
 476        int ret, enable;
 477
 478        mutex_lock(&ar->conf_mutex);
 479
 480        if (ar->state != ATH11K_STATE_ON) {
 481                ret = -ENETDOWN;
 482                goto out;
 483        }
 484
 485        ret = kstrtoint_from_user(buf, count, 0, &enable);
 486        if (ret)
 487                goto out;
 488
 489        ar->debug.pktlog_peer_valid = enable;
 490        memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
 491
 492        /* Send peer based pktlog enable/disable */
 493        ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
 494        if (ret) {
 495                ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
 496                            sta->addr, ret);
 497                goto out;
 498        }
 499
 500        ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
 501                   enable);
 502        ret = count;
 503
 504out:
 505        mutex_unlock(&ar->conf_mutex);
 506        return ret;
 507}
 508
 509static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
 510                                               char __user *ubuf,
 511                                               size_t count, loff_t *ppos)
 512{
 513        struct ieee80211_sta *sta = file->private_data;
 514        struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
 515        struct ath11k *ar = arsta->arvif->ar;
 516        char buf[32] = {0};
 517        int len;
 518
 519        mutex_lock(&ar->conf_mutex);
 520        len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
 521                        ar->debug.pktlog_peer_valid,
 522                        ar->debug.pktlog_peer_addr);
 523        mutex_unlock(&ar->conf_mutex);
 524
 525        return simple_read_from_buffer(ubuf, count, ppos, buf, len);
 526}
 527
 528static const struct file_operations fops_peer_pktlog = {
 529        .write = ath11k_dbg_sta_write_peer_pktlog,
 530        .read = ath11k_dbg_sta_read_peer_pktlog,
 531        .open = simple_open,
 532        .owner = THIS_MODULE,
 533        .llseek = default_llseek,
 534};
 535
 536void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 537                            struct ieee80211_sta *sta, struct dentry *dir)
 538{
 539        struct ath11k *ar = hw->priv;
 540
 541        if (ath11k_debug_is_extd_tx_stats_enabled(ar))
 542                debugfs_create_file("tx_stats", 0400, dir, sta,
 543                                    &fops_tx_stats);
 544        if (ath11k_debug_is_extd_rx_stats_enabled(ar))
 545                debugfs_create_file("rx_stats", 0400, dir, sta,
 546                                    &fops_rx_stats);
 547
 548        debugfs_create_file("htt_peer_stats", 0400, dir, sta,
 549                            &fops_htt_peer_stats);
 550
 551        debugfs_create_file("peer_pktlog", 0644, dir, sta,
 552                            &fops_peer_pktlog);
 553}
 554