0001
0002
0003
0004
0005
0006 #include <linux/vmalloc.h>
0007
0008 #include "debugfs_sta.h"
0009 #include "core.h"
0010 #include "peer.h"
0011 #include "debug.h"
0012 #include "dp_tx.h"
0013 #include "debugfs_htt_stats.h"
0014
0015 void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
0016 struct ath11k_per_peer_tx_stats *peer_stats,
0017 u8 legacy_rate_idx)
0018 {
0019 struct rate_info *txrate = &arsta->txrate;
0020 struct ath11k_htt_tx_stats *tx_stats;
0021 int gi, mcs, bw, nss;
0022
0023 if (!arsta->tx_stats)
0024 return;
0025
0026 tx_stats = arsta->tx_stats;
0027 gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
0028 mcs = txrate->mcs;
0029 bw = ath11k_mac_mac80211_bw_to_ath11k_bw(txrate->bw);
0030 nss = txrate->nss - 1;
0031
0032 #define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
0033
0034 if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
0035 STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
0036 STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
0037 STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
0038 STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
0039 STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
0040 STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
0041 } else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
0042 STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
0043 STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
0044 STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
0045 STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
0046 STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
0047 STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
0048 } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
0049 STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
0050 STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
0051 STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
0052 STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
0053 STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
0054 STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
0055 } else {
0056 mcs = legacy_rate_idx;
0057
0058 STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
0059 STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
0060 STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
0061 STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
0062 STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
0063 STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
0064 }
0065
0066 if (peer_stats->is_ampdu) {
0067 tx_stats->ba_fails += peer_stats->ba_fails;
0068
0069 if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
0070 STATS_OP_FMT(AMPDU).he[0][mcs] +=
0071 peer_stats->succ_bytes + peer_stats->retry_bytes;
0072 STATS_OP_FMT(AMPDU).he[1][mcs] +=
0073 peer_stats->succ_pkts + peer_stats->retry_pkts;
0074 } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
0075 STATS_OP_FMT(AMPDU).ht[0][mcs] +=
0076 peer_stats->succ_bytes + peer_stats->retry_bytes;
0077 STATS_OP_FMT(AMPDU).ht[1][mcs] +=
0078 peer_stats->succ_pkts + peer_stats->retry_pkts;
0079 } else {
0080 STATS_OP_FMT(AMPDU).vht[0][mcs] +=
0081 peer_stats->succ_bytes + peer_stats->retry_bytes;
0082 STATS_OP_FMT(AMPDU).vht[1][mcs] +=
0083 peer_stats->succ_pkts + peer_stats->retry_pkts;
0084 }
0085 STATS_OP_FMT(AMPDU).bw[0][bw] +=
0086 peer_stats->succ_bytes + peer_stats->retry_bytes;
0087 STATS_OP_FMT(AMPDU).nss[0][nss] +=
0088 peer_stats->succ_bytes + peer_stats->retry_bytes;
0089 STATS_OP_FMT(AMPDU).gi[0][gi] +=
0090 peer_stats->succ_bytes + peer_stats->retry_bytes;
0091 STATS_OP_FMT(AMPDU).bw[1][bw] +=
0092 peer_stats->succ_pkts + peer_stats->retry_pkts;
0093 STATS_OP_FMT(AMPDU).nss[1][nss] +=
0094 peer_stats->succ_pkts + peer_stats->retry_pkts;
0095 STATS_OP_FMT(AMPDU).gi[1][gi] +=
0096 peer_stats->succ_pkts + peer_stats->retry_pkts;
0097 } else {
0098 tx_stats->ack_fails += peer_stats->ba_fails;
0099 }
0100
0101 STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
0102 STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
0103 STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
0104
0105 STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
0106 STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
0107 STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
0108
0109 STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
0110 STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
0111 STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
0112
0113 STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
0114 STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
0115 STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
0116
0117 STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
0118 STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
0119 STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
0120
0121 STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
0122 STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
0123 STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
0124
0125 tx_stats->tx_duration += peer_stats->duration;
0126 }
0127
0128 void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
0129 struct hal_tx_status *ts)
0130 {
0131 ath11k_dp_tx_update_txcompl(ar, ts);
0132 }
0133
0134 static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
0135 char __user *user_buf,
0136 size_t count, loff_t *ppos)
0137 {
0138 struct ieee80211_sta *sta = file->private_data;
0139 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0140 struct ath11k *ar = arsta->arvif->ar;
0141 struct ath11k_htt_data_stats *stats;
0142 static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
0143 "retry", "ampdu"};
0144 static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
0145 int len = 0, i, j, k, retval = 0;
0146 const int size = 2 * 4096;
0147 char *buf;
0148
0149 if (!arsta->tx_stats)
0150 return -ENOENT;
0151
0152 buf = kzalloc(size, GFP_KERNEL);
0153 if (!buf)
0154 return -ENOMEM;
0155
0156 mutex_lock(&ar->conf_mutex);
0157
0158 spin_lock_bh(&ar->data_lock);
0159 for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
0160 for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
0161 stats = &arsta->tx_stats->stats[k];
0162 len += scnprintf(buf + len, size - len, "%s_%s\n",
0163 str_name[k],
0164 str[j]);
0165 len += scnprintf(buf + len, size - len,
0166 " HE MCS %s\n",
0167 str[j]);
0168 for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
0169 len += scnprintf(buf + len, size - len,
0170 " %llu ",
0171 stats->he[j][i]);
0172 len += scnprintf(buf + len, size - len, "\n");
0173 len += scnprintf(buf + len, size - len,
0174 " VHT MCS %s\n",
0175 str[j]);
0176 for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
0177 len += scnprintf(buf + len, size - len,
0178 " %llu ",
0179 stats->vht[j][i]);
0180 len += scnprintf(buf + len, size - len, "\n");
0181 len += scnprintf(buf + len, size - len, " HT MCS %s\n",
0182 str[j]);
0183 for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
0184 len += scnprintf(buf + len, size - len,
0185 " %llu ", stats->ht[j][i]);
0186 len += scnprintf(buf + len, size - len, "\n");
0187 len += scnprintf(buf + len, size - len,
0188 " BW %s (20,40,80,160 MHz)\n", str[j]);
0189 len += scnprintf(buf + len, size - len,
0190 " %llu %llu %llu %llu\n",
0191 stats->bw[j][0], stats->bw[j][1],
0192 stats->bw[j][2], stats->bw[j][3]);
0193 len += scnprintf(buf + len, size - len,
0194 " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
0195 len += scnprintf(buf + len, size - len,
0196 " %llu %llu %llu %llu\n",
0197 stats->nss[j][0], stats->nss[j][1],
0198 stats->nss[j][2], stats->nss[j][3]);
0199 len += scnprintf(buf + len, size - len,
0200 " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
0201 str[j]);
0202 len += scnprintf(buf + len, size - len,
0203 " %llu %llu %llu %llu\n",
0204 stats->gi[j][0], stats->gi[j][1],
0205 stats->gi[j][2], stats->gi[j][3]);
0206 len += scnprintf(buf + len, size - len,
0207 " legacy rate %s (1,2 ... Mbps)\n ",
0208 str[j]);
0209 for (i = 0; i < ATH11K_LEGACY_NUM; i++)
0210 len += scnprintf(buf + len, size - len, "%llu ",
0211 stats->legacy[j][i]);
0212 len += scnprintf(buf + len, size - len, "\n");
0213 }
0214 }
0215
0216 len += scnprintf(buf + len, size - len,
0217 "\nTX duration\n %llu usecs\n",
0218 arsta->tx_stats->tx_duration);
0219 len += scnprintf(buf + len, size - len,
0220 "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
0221 len += scnprintf(buf + len, size - len,
0222 "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
0223 spin_unlock_bh(&ar->data_lock);
0224
0225 if (len > size)
0226 len = size;
0227 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0228 kfree(buf);
0229
0230 mutex_unlock(&ar->conf_mutex);
0231 return retval;
0232 }
0233
0234 static const struct file_operations fops_tx_stats = {
0235 .read = ath11k_dbg_sta_dump_tx_stats,
0236 .open = simple_open,
0237 .owner = THIS_MODULE,
0238 .llseek = default_llseek,
0239 };
0240
0241 static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
0242 char __user *user_buf,
0243 size_t count, loff_t *ppos)
0244 {
0245 struct ieee80211_sta *sta = file->private_data;
0246 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0247 struct ath11k *ar = arsta->arvif->ar;
0248 struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
0249 int len = 0, i, retval = 0;
0250 const int size = 4096;
0251 char *buf;
0252
0253 if (!rx_stats)
0254 return -ENOENT;
0255
0256 buf = kzalloc(size, GFP_KERNEL);
0257 if (!buf)
0258 return -ENOMEM;
0259
0260 mutex_lock(&ar->conf_mutex);
0261 spin_lock_bh(&ar->ab->base_lock);
0262
0263 len += scnprintf(buf + len, size - len, "RX peer stats:\n");
0264 len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
0265 rx_stats->num_msdu);
0266 len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
0267 rx_stats->tcp_msdu_count);
0268 len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
0269 rx_stats->udp_msdu_count);
0270 len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
0271 rx_stats->ampdu_msdu_count);
0272 len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
0273 rx_stats->non_ampdu_msdu_count);
0274 len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
0275 rx_stats->stbc_count);
0276 len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
0277 rx_stats->beamformed_count);
0278 len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
0279 rx_stats->num_mpdu_fcs_ok);
0280 len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
0281 rx_stats->num_mpdu_fcs_err);
0282 len += scnprintf(buf + len, size - len,
0283 "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
0284 rx_stats->gi_count[0], rx_stats->gi_count[1],
0285 rx_stats->gi_count[2], rx_stats->gi_count[3]);
0286 len += scnprintf(buf + len, size - len,
0287 "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
0288 rx_stats->bw_count[0], rx_stats->bw_count[1],
0289 rx_stats->bw_count[2], rx_stats->bw_count[3]);
0290 len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
0291 rx_stats->coding_count[0], rx_stats->coding_count[1]);
0292 len += scnprintf(buf + len, size - len,
0293 "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
0294 rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
0295 rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
0296 rx_stats->pream_cnt[4]);
0297 len += scnprintf(buf + len, size - len,
0298 "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
0299 rx_stats->reception_type[0], rx_stats->reception_type[1],
0300 rx_stats->reception_type[2], rx_stats->reception_type[3]);
0301 len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
0302 for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
0303 len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
0304 len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
0305 for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
0306 len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
0307 len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
0308 for (i = 0; i < HAL_RX_MAX_NSS; i++)
0309 len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
0310 len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
0311 rx_stats->rx_duration);
0312 len += scnprintf(buf + len, size - len,
0313 "\nDCM: %llu\nRU: 26 %llu 52: %llu 106: %llu 242: %llu 484: %llu 996: %llu\n",
0314 rx_stats->dcm_count, rx_stats->ru_alloc_cnt[0],
0315 rx_stats->ru_alloc_cnt[1], rx_stats->ru_alloc_cnt[2],
0316 rx_stats->ru_alloc_cnt[3], rx_stats->ru_alloc_cnt[4],
0317 rx_stats->ru_alloc_cnt[5]);
0318
0319 len += scnprintf(buf + len, size - len, "\n");
0320
0321 spin_unlock_bh(&ar->ab->base_lock);
0322
0323 if (len > size)
0324 len = size;
0325 retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0326 kfree(buf);
0327
0328 mutex_unlock(&ar->conf_mutex);
0329 return retval;
0330 }
0331
0332 static const struct file_operations fops_rx_stats = {
0333 .read = ath11k_dbg_sta_dump_rx_stats,
0334 .open = simple_open,
0335 .owner = THIS_MODULE,
0336 .llseek = default_llseek,
0337 };
0338
0339 static int
0340 ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
0341 {
0342 struct ieee80211_sta *sta = inode->i_private;
0343 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0344 struct ath11k *ar = arsta->arvif->ar;
0345 struct debug_htt_stats_req *stats_req;
0346 int type = ar->debug.htt_stats.type;
0347 int ret;
0348
0349 if ((type != ATH11K_DBG_HTT_EXT_STATS_PEER_INFO &&
0350 type != ATH11K_DBG_HTT_EXT_STATS_PEER_CTRL_PATH_TXRX_STATS) ||
0351 type == ATH11K_DBG_HTT_EXT_STATS_RESET)
0352 return -EPERM;
0353
0354 stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
0355 if (!stats_req)
0356 return -ENOMEM;
0357
0358 mutex_lock(&ar->conf_mutex);
0359 ar->debug.htt_stats.stats_req = stats_req;
0360 stats_req->type = type;
0361 memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
0362 ret = ath11k_debugfs_htt_stats_req(ar);
0363 mutex_unlock(&ar->conf_mutex);
0364 if (ret < 0)
0365 goto out;
0366
0367 file->private_data = stats_req;
0368 return 0;
0369 out:
0370 vfree(stats_req);
0371 ar->debug.htt_stats.stats_req = NULL;
0372 return ret;
0373 }
0374
0375 static int
0376 ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
0377 {
0378 struct ieee80211_sta *sta = inode->i_private;
0379 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0380 struct ath11k *ar = arsta->arvif->ar;
0381
0382 mutex_lock(&ar->conf_mutex);
0383 vfree(file->private_data);
0384 ar->debug.htt_stats.stats_req = NULL;
0385 mutex_unlock(&ar->conf_mutex);
0386
0387 return 0;
0388 }
0389
0390 static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
0391 char __user *user_buf,
0392 size_t count, loff_t *ppos)
0393 {
0394 struct debug_htt_stats_req *stats_req = file->private_data;
0395 char *buf;
0396 u32 length = 0;
0397
0398 buf = stats_req->buf;
0399 length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
0400 return simple_read_from_buffer(user_buf, count, ppos, buf, length);
0401 }
0402
0403 static const struct file_operations fops_htt_peer_stats = {
0404 .open = ath11k_dbg_sta_open_htt_peer_stats,
0405 .release = ath11k_dbg_sta_release_htt_peer_stats,
0406 .read = ath11k_dbg_sta_read_htt_peer_stats,
0407 .owner = THIS_MODULE,
0408 .llseek = default_llseek,
0409 };
0410
0411 static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
0412 const char __user *buf,
0413 size_t count, loff_t *ppos)
0414 {
0415 struct ieee80211_sta *sta = file->private_data;
0416 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0417 struct ath11k *ar = arsta->arvif->ar;
0418 int ret, enable;
0419
0420 mutex_lock(&ar->conf_mutex);
0421
0422 if (ar->state != ATH11K_STATE_ON) {
0423 ret = -ENETDOWN;
0424 goto out;
0425 }
0426
0427 ret = kstrtoint_from_user(buf, count, 0, &enable);
0428 if (ret)
0429 goto out;
0430
0431 ar->debug.pktlog_peer_valid = enable;
0432 memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
0433
0434
0435 ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
0436 if (ret) {
0437 ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
0438 sta->addr, ret);
0439 goto out;
0440 }
0441
0442 ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
0443 enable);
0444 ret = count;
0445
0446 out:
0447 mutex_unlock(&ar->conf_mutex);
0448 return ret;
0449 }
0450
0451 static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
0452 char __user *ubuf,
0453 size_t count, loff_t *ppos)
0454 {
0455 struct ieee80211_sta *sta = file->private_data;
0456 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0457 struct ath11k *ar = arsta->arvif->ar;
0458 char buf[32] = {0};
0459 int len;
0460
0461 mutex_lock(&ar->conf_mutex);
0462 len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
0463 ar->debug.pktlog_peer_valid,
0464 ar->debug.pktlog_peer_addr);
0465 mutex_unlock(&ar->conf_mutex);
0466
0467 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
0468 }
0469
0470 static const struct file_operations fops_peer_pktlog = {
0471 .write = ath11k_dbg_sta_write_peer_pktlog,
0472 .read = ath11k_dbg_sta_read_peer_pktlog,
0473 .open = simple_open,
0474 .owner = THIS_MODULE,
0475 .llseek = default_llseek,
0476 };
0477
0478 static ssize_t ath11k_dbg_sta_write_delba(struct file *file,
0479 const char __user *user_buf,
0480 size_t count, loff_t *ppos)
0481 {
0482 struct ieee80211_sta *sta = file->private_data;
0483 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0484 struct ath11k *ar = arsta->arvif->ar;
0485 u32 tid, initiator, reason;
0486 int ret;
0487 char buf[64] = {0};
0488
0489 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
0490 user_buf, count);
0491 if (ret <= 0)
0492 return ret;
0493
0494 ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
0495 if (ret != 3)
0496 return -EINVAL;
0497
0498
0499 if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
0500 return -EINVAL;
0501
0502 mutex_lock(&ar->conf_mutex);
0503 if (ar->state != ATH11K_STATE_ON ||
0504 arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
0505 ret = count;
0506 goto out;
0507 }
0508
0509 ret = ath11k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
0510 tid, initiator, reason);
0511 if (ret) {
0512 ath11k_warn(ar->ab, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
0513 arsta->arvif->vdev_id, sta->addr, tid, initiator,
0514 reason);
0515 }
0516 ret = count;
0517 out:
0518 mutex_unlock(&ar->conf_mutex);
0519 return ret;
0520 }
0521
0522 static const struct file_operations fops_delba = {
0523 .write = ath11k_dbg_sta_write_delba,
0524 .open = simple_open,
0525 .owner = THIS_MODULE,
0526 .llseek = default_llseek,
0527 };
0528
0529 static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file,
0530 const char __user *user_buf,
0531 size_t count, loff_t *ppos)
0532 {
0533 struct ieee80211_sta *sta = file->private_data;
0534 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0535 struct ath11k *ar = arsta->arvif->ar;
0536 u32 tid, status;
0537 int ret;
0538 char buf[64] = {0};
0539
0540 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
0541 user_buf, count);
0542 if (ret <= 0)
0543 return ret;
0544
0545 ret = sscanf(buf, "%u %u", &tid, &status);
0546 if (ret != 2)
0547 return -EINVAL;
0548
0549
0550 if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
0551 return -EINVAL;
0552
0553 mutex_lock(&ar->conf_mutex);
0554 if (ar->state != ATH11K_STATE_ON ||
0555 arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
0556 ret = count;
0557 goto out;
0558 }
0559
0560 ret = ath11k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
0561 tid, status);
0562 if (ret) {
0563 ath11k_warn(ar->ab, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
0564 arsta->arvif->vdev_id, sta->addr, tid, status);
0565 }
0566 ret = count;
0567 out:
0568 mutex_unlock(&ar->conf_mutex);
0569 return ret;
0570 }
0571
0572 static const struct file_operations fops_addba_resp = {
0573 .write = ath11k_dbg_sta_write_addba_resp,
0574 .open = simple_open,
0575 .owner = THIS_MODULE,
0576 .llseek = default_llseek,
0577 };
0578
0579 static ssize_t ath11k_dbg_sta_write_addba(struct file *file,
0580 const char __user *user_buf,
0581 size_t count, loff_t *ppos)
0582 {
0583 struct ieee80211_sta *sta = file->private_data;
0584 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0585 struct ath11k *ar = arsta->arvif->ar;
0586 u32 tid, buf_size;
0587 int ret;
0588 char buf[64] = {0};
0589
0590 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
0591 user_buf, count);
0592 if (ret <= 0)
0593 return ret;
0594
0595 ret = sscanf(buf, "%u %u", &tid, &buf_size);
0596 if (ret != 2)
0597 return -EINVAL;
0598
0599
0600 if (tid > HAL_DESC_REO_NON_QOS_TID - 1)
0601 return -EINVAL;
0602
0603 mutex_lock(&ar->conf_mutex);
0604 if (ar->state != ATH11K_STATE_ON ||
0605 arsta->aggr_mode != ATH11K_DBG_AGGR_MODE_MANUAL) {
0606 ret = count;
0607 goto out;
0608 }
0609
0610 ret = ath11k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
0611 tid, buf_size);
0612 if (ret) {
0613 ath11k_warn(ar->ab, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
0614 arsta->arvif->vdev_id, sta->addr, tid, buf_size);
0615 }
0616
0617 ret = count;
0618 out:
0619 mutex_unlock(&ar->conf_mutex);
0620 return ret;
0621 }
0622
0623 static const struct file_operations fops_addba = {
0624 .write = ath11k_dbg_sta_write_addba,
0625 .open = simple_open,
0626 .owner = THIS_MODULE,
0627 .llseek = default_llseek,
0628 };
0629
0630 static ssize_t ath11k_dbg_sta_read_aggr_mode(struct file *file,
0631 char __user *user_buf,
0632 size_t count, loff_t *ppos)
0633 {
0634 struct ieee80211_sta *sta = file->private_data;
0635 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0636 struct ath11k *ar = arsta->arvif->ar;
0637 char buf[64];
0638 int len = 0;
0639
0640 mutex_lock(&ar->conf_mutex);
0641 len = scnprintf(buf, sizeof(buf) - len,
0642 "aggregation mode: %s\n\n%s\n%s\n",
0643 (arsta->aggr_mode == ATH11K_DBG_AGGR_MODE_AUTO) ?
0644 "auto" : "manual", "auto = 0", "manual = 1");
0645 mutex_unlock(&ar->conf_mutex);
0646
0647 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0648 }
0649
0650 static ssize_t ath11k_dbg_sta_write_aggr_mode(struct file *file,
0651 const char __user *user_buf,
0652 size_t count, loff_t *ppos)
0653 {
0654 struct ieee80211_sta *sta = file->private_data;
0655 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0656 struct ath11k *ar = arsta->arvif->ar;
0657 u32 aggr_mode;
0658 int ret;
0659
0660 if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
0661 return -EINVAL;
0662
0663 if (aggr_mode >= ATH11K_DBG_AGGR_MODE_MAX)
0664 return -EINVAL;
0665
0666 mutex_lock(&ar->conf_mutex);
0667 if (ar->state != ATH11K_STATE_ON ||
0668 aggr_mode == arsta->aggr_mode) {
0669 ret = count;
0670 goto out;
0671 }
0672
0673 ret = ath11k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
0674 if (ret) {
0675 ath11k_warn(ar->ab, "failed to clear addba session ret: %d\n",
0676 ret);
0677 goto out;
0678 }
0679
0680 arsta->aggr_mode = aggr_mode;
0681 out:
0682 mutex_unlock(&ar->conf_mutex);
0683 return ret;
0684 }
0685
0686 static const struct file_operations fops_aggr_mode = {
0687 .read = ath11k_dbg_sta_read_aggr_mode,
0688 .write = ath11k_dbg_sta_write_aggr_mode,
0689 .open = simple_open,
0690 .owner = THIS_MODULE,
0691 .llseek = default_llseek,
0692 };
0693
0694 static ssize_t
0695 ath11k_write_htt_peer_stats_reset(struct file *file,
0696 const char __user *user_buf,
0697 size_t count, loff_t *ppos)
0698 {
0699 struct ieee80211_sta *sta = file->private_data;
0700 struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
0701 struct ath11k *ar = arsta->arvif->ar;
0702 struct htt_ext_stats_cfg_params cfg_params = { 0 };
0703 int ret;
0704 u8 type;
0705
0706 ret = kstrtou8_from_user(user_buf, count, 0, &type);
0707 if (ret)
0708 return ret;
0709
0710 if (!type)
0711 return ret;
0712
0713 mutex_lock(&ar->conf_mutex);
0714 cfg_params.cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
0715 cfg_params.cfg0 |= FIELD_PREP(GENMASK(15, 1),
0716 HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
0717
0718 cfg_params.cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
0719
0720 cfg_params.cfg2 |= FIELD_PREP(GENMASK(7, 0), sta->addr[0]);
0721 cfg_params.cfg2 |= FIELD_PREP(GENMASK(15, 8), sta->addr[1]);
0722 cfg_params.cfg2 |= FIELD_PREP(GENMASK(23, 16), sta->addr[2]);
0723 cfg_params.cfg2 |= FIELD_PREP(GENMASK(31, 24), sta->addr[3]);
0724
0725 cfg_params.cfg3 |= FIELD_PREP(GENMASK(7, 0), sta->addr[4]);
0726 cfg_params.cfg3 |= FIELD_PREP(GENMASK(15, 8), sta->addr[5]);
0727
0728 cfg_params.cfg3 |= ATH11K_HTT_PEER_STATS_RESET;
0729
0730 ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
0731 ATH11K_DBG_HTT_EXT_STATS_PEER_INFO,
0732 &cfg_params,
0733 0ULL);
0734 if (ret) {
0735 ath11k_warn(ar->ab, "failed to send htt peer stats request: %d\n", ret);
0736 mutex_unlock(&ar->conf_mutex);
0737 return ret;
0738 }
0739
0740 mutex_unlock(&ar->conf_mutex);
0741
0742 ret = count;
0743
0744 return ret;
0745 }
0746
0747 static const struct file_operations fops_htt_peer_stats_reset = {
0748 .write = ath11k_write_htt_peer_stats_reset,
0749 .open = simple_open,
0750 .owner = THIS_MODULE,
0751 .llseek = default_llseek,
0752 };
0753
0754 void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0755 struct ieee80211_sta *sta, struct dentry *dir)
0756 {
0757 struct ath11k *ar = hw->priv;
0758
0759 if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
0760 debugfs_create_file("tx_stats", 0400, dir, sta,
0761 &fops_tx_stats);
0762 if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
0763 debugfs_create_file("rx_stats", 0400, dir, sta,
0764 &fops_rx_stats);
0765
0766 debugfs_create_file("htt_peer_stats", 0400, dir, sta,
0767 &fops_htt_peer_stats);
0768
0769 debugfs_create_file("peer_pktlog", 0644, dir, sta,
0770 &fops_peer_pktlog);
0771
0772 debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
0773 debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
0774 debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
0775 debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
0776
0777 if (test_bit(WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET,
0778 ar->ab->wmi_ab.svc_map))
0779 debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
0780 &fops_htt_peer_stats_reset);
0781 }