Path: blob/main/sys/contrib/dev/athk/ath10k/debugfs_sta.c
48378 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.3* Copyright (c) 2018, The Linux Foundation. All rights reserved.4*/56#include "core.h"7#include "wmi-ops.h"8#include "txrx.h"9#include "debug.h"1011static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,12struct ath10k_sta_tid_stats *stats,13u32 msdu_count)14{15if (msdu_count == 1)16stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;17else if (msdu_count == 2)18stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;19else if (msdu_count == 3)20stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;21else if (msdu_count == 4)22stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;23else if (msdu_count > 4)24stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;25}2627static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,28struct ath10k_sta_tid_stats *stats,29u32 mpdu_count)30{31if (mpdu_count <= 10)32stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;33else if (mpdu_count <= 20)34stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;35else if (mpdu_count <= 30)36stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;37else if (mpdu_count <= 40)38stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;39else if (mpdu_count <= 50)40stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;41else if (mpdu_count <= 60)42stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;43else if (mpdu_count > 60)44stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;45}4647void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,48struct htt_rx_indication_mpdu_range *ranges,49int num_ranges)50{51struct ath10k_sta *arsta;52struct ath10k_peer *peer;53int i;5455if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))56return;5758rcu_read_lock();59spin_lock_bh(&ar->data_lock);6061peer = ath10k_peer_find_by_id(ar, peer_id);62if (!peer || !peer->sta)63goto out;6465arsta = (struct ath10k_sta *)peer->sta->drv_priv;6667for (i = 0; i < num_ranges; i++)68ath10k_rx_stats_update_ampdu_subfrm(ar,69&arsta->tid_stats[tid],70ranges[i].mpdu_count);7172out:73spin_unlock_bh(&ar->data_lock);74rcu_read_unlock();75}7677void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,78unsigned long num_msdus,79enum ath10k_pkt_rx_err err,80unsigned long unchain_cnt,81unsigned long drop_cnt,82unsigned long drop_cnt_filter,83unsigned long queued_msdus)84{85struct ieee80211_sta *sta;86struct ath10k_sta *arsta;87struct ieee80211_hdr *hdr;88struct ath10k_sta_tid_stats *stats;89u8 tid = IEEE80211_NUM_TIDS;90bool non_data_frm = false;9192hdr = (struct ieee80211_hdr *)first_hdr;93if (!ieee80211_is_data(hdr->frame_control))94non_data_frm = true;9596if (ieee80211_is_data_qos(hdr->frame_control))97tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;9899if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)100return;101102rcu_read_lock();103104sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);105if (!sta)106goto exit;107108arsta = (struct ath10k_sta *)sta->drv_priv;109110spin_lock_bh(&ar->data_lock);111stats = &arsta->tid_stats[tid];112stats->rx_pkt_from_fw += num_msdus;113stats->rx_pkt_unchained += unchain_cnt;114stats->rx_pkt_drop_chained += drop_cnt;115stats->rx_pkt_drop_filter += drop_cnt_filter;116if (err != ATH10K_PKT_RX_ERR_MAX)117stats->rx_pkt_err[err] += queued_msdus;118stats->rx_pkt_queued_for_mac += queued_msdus;119ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],120num_msdus);121spin_unlock_bh(&ar->data_lock);122123exit:124rcu_read_unlock();125}126127static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,128struct ath10k_fw_stats *stats)129{130struct ath10k_fw_extd_stats_peer *peer;131struct ieee80211_sta *sta;132struct ath10k_sta *arsta;133134rcu_read_lock();135list_for_each_entry(peer, &stats->peers_extd, list) {136sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,137NULL);138if (!sta)139continue;140arsta = (struct ath10k_sta *)sta->drv_priv;141arsta->rx_duration += (u64)peer->rx_duration;142}143rcu_read_unlock();144}145146static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,147struct ath10k_fw_stats *stats)148{149struct ath10k_fw_stats_peer *peer;150struct ieee80211_sta *sta;151struct ath10k_sta *arsta;152153rcu_read_lock();154list_for_each_entry(peer, &stats->peers, list) {155sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,156NULL);157if (!sta)158continue;159arsta = (struct ath10k_sta *)sta->drv_priv;160arsta->rx_duration += (u64)peer->rx_duration;161}162rcu_read_unlock();163}164165void ath10k_sta_update_rx_duration(struct ath10k *ar,166struct ath10k_fw_stats *stats)167{168if (stats->extended)169ath10k_sta_update_extd_stats_rx_duration(ar, stats);170else171ath10k_sta_update_stats_rx_duration(ar, stats);172}173174static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,175char __user *user_buf,176size_t count, loff_t *ppos)177{178struct ieee80211_sta *sta = file->private_data;179struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;180struct ath10k *ar = arsta->arvif->ar;181char buf[32];182int len = 0;183184mutex_lock(&ar->conf_mutex);185len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",186(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?187"auto" : "manual");188mutex_unlock(&ar->conf_mutex);189190return simple_read_from_buffer(user_buf, count, ppos, buf, len);191}192193static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,194const char __user *user_buf,195size_t count, loff_t *ppos)196{197struct ieee80211_sta *sta = file->private_data;198struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;199struct ath10k *ar = arsta->arvif->ar;200u32 aggr_mode;201int ret;202203if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))204return -EINVAL;205206if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)207return -EINVAL;208209mutex_lock(&ar->conf_mutex);210if ((ar->state != ATH10K_STATE_ON) ||211(aggr_mode == arsta->aggr_mode)) {212ret = count;213goto out;214}215216ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);217if (ret) {218ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);219goto out;220}221222arsta->aggr_mode = aggr_mode;223out:224mutex_unlock(&ar->conf_mutex);225return ret;226}227228static const struct file_operations fops_aggr_mode = {229.read = ath10k_dbg_sta_read_aggr_mode,230.write = ath10k_dbg_sta_write_aggr_mode,231.open = simple_open,232.owner = THIS_MODULE,233.llseek = default_llseek,234};235236static ssize_t ath10k_dbg_sta_write_addba(struct file *file,237const char __user *user_buf,238size_t count, loff_t *ppos)239{240struct ieee80211_sta *sta = file->private_data;241struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;242struct ath10k *ar = arsta->arvif->ar;243u32 tid, buf_size;244int ret;245char buf[64] = {0};246247ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,248user_buf, count);249if (ret <= 0)250return ret;251252ret = sscanf(buf, "%u %u", &tid, &buf_size);253if (ret != 2)254return -EINVAL;255256/* Valid TID values are 0 through 15 */257if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)258return -EINVAL;259260mutex_lock(&ar->conf_mutex);261if ((ar->state != ATH10K_STATE_ON) ||262(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {263ret = count;264goto out;265}266267ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,268tid, buf_size);269if (ret) {270ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",271arsta->arvif->vdev_id, sta->addr, tid, buf_size);272}273274ret = count;275out:276mutex_unlock(&ar->conf_mutex);277return ret;278}279280static const struct file_operations fops_addba = {281.write = ath10k_dbg_sta_write_addba,282.open = simple_open,283.owner = THIS_MODULE,284.llseek = default_llseek,285};286287static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,288const char __user *user_buf,289size_t count, loff_t *ppos)290{291struct ieee80211_sta *sta = file->private_data;292struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;293struct ath10k *ar = arsta->arvif->ar;294u32 tid, status;295int ret;296char buf[64] = {0};297298ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,299user_buf, count);300if (ret <= 0)301return ret;302303ret = sscanf(buf, "%u %u", &tid, &status);304if (ret != 2)305return -EINVAL;306307/* Valid TID values are 0 through 15 */308if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)309return -EINVAL;310311mutex_lock(&ar->conf_mutex);312if ((ar->state != ATH10K_STATE_ON) ||313(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {314ret = count;315goto out;316}317318ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,319tid, status);320if (ret) {321ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",322arsta->arvif->vdev_id, sta->addr, tid, status);323}324ret = count;325out:326mutex_unlock(&ar->conf_mutex);327return ret;328}329330static const struct file_operations fops_addba_resp = {331.write = ath10k_dbg_sta_write_addba_resp,332.open = simple_open,333.owner = THIS_MODULE,334.llseek = default_llseek,335};336337static ssize_t ath10k_dbg_sta_write_delba(struct file *file,338const char __user *user_buf,339size_t count, loff_t *ppos)340{341struct ieee80211_sta *sta = file->private_data;342struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;343struct ath10k *ar = arsta->arvif->ar;344u32 tid, initiator, reason;345int ret;346char buf[64] = {0};347348ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,349user_buf, count);350if (ret <= 0)351return ret;352353ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);354if (ret != 3)355return -EINVAL;356357/* Valid TID values are 0 through 15 */358if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)359return -EINVAL;360361mutex_lock(&ar->conf_mutex);362if ((ar->state != ATH10K_STATE_ON) ||363(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {364ret = count;365goto out;366}367368ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,369tid, initiator, reason);370if (ret) {371ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",372arsta->arvif->vdev_id, sta->addr, tid, initiator,373reason);374}375ret = count;376out:377mutex_unlock(&ar->conf_mutex);378return ret;379}380381static const struct file_operations fops_delba = {382.write = ath10k_dbg_sta_write_delba,383.open = simple_open,384.owner = THIS_MODULE,385.llseek = default_llseek,386};387388static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file,389char __user *user_buf,390size_t count,391loff_t *ppos)392{393struct ieee80211_sta *sta = file->private_data;394struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;395struct ath10k *ar = arsta->arvif->ar;396char buf[8];397int len = 0;398399mutex_lock(&ar->conf_mutex);400len = scnprintf(buf, sizeof(buf) - len,401"Write 1 to once trigger the debug logs\n");402mutex_unlock(&ar->conf_mutex);403404return simple_read_from_buffer(user_buf, count, ppos, buf, len);405}406407static ssize_t408ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,409const char __user *user_buf,410size_t count, loff_t *ppos)411{412struct ieee80211_sta *sta = file->private_data;413struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;414struct ath10k *ar = arsta->arvif->ar;415u8 peer_debug_trigger;416int ret;417418if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger))419return -EINVAL;420421if (peer_debug_trigger != 1)422return -EINVAL;423424mutex_lock(&ar->conf_mutex);425426if (ar->state != ATH10K_STATE_ON) {427ret = -ENETDOWN;428goto out;429}430431ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr,432ar->wmi.peer_param->debug, peer_debug_trigger);433if (ret) {434ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n",435ret);436goto out;437}438out:439mutex_unlock(&ar->conf_mutex);440return count;441}442443static const struct file_operations fops_peer_debug_trigger = {444.open = simple_open,445.read = ath10k_dbg_sta_read_peer_debug_trigger,446.write = ath10k_dbg_sta_write_peer_debug_trigger,447.owner = THIS_MODULE,448.llseek = default_llseek,449};450451static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,452char __user *user_buf,453size_t count, loff_t *ppos)454{455struct ieee80211_sta *sta = file->private_data;456struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;457struct ath10k *ar = arsta->arvif->ar;458char buf[20];459int len = 0;460461spin_lock_bh(&ar->data_lock);462463len = scnprintf(buf, sizeof(buf) - len, "%d\n",464arsta->peer_ps_state);465466spin_unlock_bh(&ar->data_lock);467468return simple_read_from_buffer(user_buf, count, ppos, buf, len);469}470471static const struct file_operations fops_peer_ps_state = {472.open = simple_open,473.read = ath10k_dbg_sta_read_peer_ps_state,474.owner = THIS_MODULE,475.llseek = default_llseek,476};477478static char *get_err_str(enum ath10k_pkt_rx_err i)479{480switch (i) {481case ATH10K_PKT_RX_ERR_FCS:482return "fcs_err";483case ATH10K_PKT_RX_ERR_TKIP:484return "tkip_err";485case ATH10K_PKT_RX_ERR_CRYPT:486return "crypt_err";487case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:488return "peer_idx_inval";489case ATH10K_PKT_RX_ERR_MAX:490return "unknown";491}492493return "unknown";494}495496static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)497{498switch (i) {499case ATH10K_AMPDU_SUBFRM_NUM_10:500return "up to 10";501case ATH10K_AMPDU_SUBFRM_NUM_20:502return "11-20";503case ATH10K_AMPDU_SUBFRM_NUM_30:504return "21-30";505case ATH10K_AMPDU_SUBFRM_NUM_40:506return "31-40";507case ATH10K_AMPDU_SUBFRM_NUM_50:508return "41-50";509case ATH10K_AMPDU_SUBFRM_NUM_60:510return "51-60";511case ATH10K_AMPDU_SUBFRM_NUM_MORE:512return ">60";513case ATH10K_AMPDU_SUBFRM_NUM_MAX:514return "0";515}516517return "0";518}519520static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)521{522switch (i) {523case ATH10K_AMSDU_SUBFRM_NUM_1:524return "1";525case ATH10K_AMSDU_SUBFRM_NUM_2:526return "2";527case ATH10K_AMSDU_SUBFRM_NUM_3:528return "3";529case ATH10K_AMSDU_SUBFRM_NUM_4:530return "4";531case ATH10K_AMSDU_SUBFRM_NUM_MORE:532return ">4";533case ATH10K_AMSDU_SUBFRM_NUM_MAX:534return "0";535}536537return "0";538}539540#define PRINT_TID_STATS(_field, _tabs) \541do { \542int k = 0; \543for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \544if (ar->sta_tid_stats_mask & BIT(j)) { \545len += scnprintf(buf + len, buf_len - len, \546"[%02d] %-10lu ", \547j, stats[j]._field); \548k++; \549if (k % 8 == 0) { \550len += scnprintf(buf + len, \551buf_len - len, "\n"); \552len += scnprintf(buf + len, \553buf_len - len, \554_tabs); \555} \556} \557} \558len += scnprintf(buf + len, buf_len - len, "\n"); \559} while (0)560561static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,562char __user *user_buf,563size_t count, loff_t *ppos)564{565struct ieee80211_sta *sta = file->private_data;566struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;567struct ath10k *ar = arsta->arvif->ar;568struct ath10k_sta_tid_stats *stats = arsta->tid_stats;569size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;570char *buf;571int i, j;572ssize_t ret;573574buf = kzalloc(buf_len, GFP_KERNEL);575if (!buf)576return -ENOMEM;577578mutex_lock(&ar->conf_mutex);579580spin_lock_bh(&ar->data_lock);581582len += scnprintf(buf + len, buf_len - len,583"\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");584len += scnprintf(buf + len, buf_len - len,585"\t\t------------------------------------------\n");586len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");587PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");588589len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");590PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");591592len += scnprintf(buf + len, buf_len - len,593"MSDUs locally dropped:chained\t");594PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");595596len += scnprintf(buf + len, buf_len - len,597"MSDUs locally dropped:filtered\t");598PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");599600len += scnprintf(buf + len, buf_len - len,601"MSDUs queued for mac80211\t");602PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");603604for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {605len += scnprintf(buf + len, buf_len - len,606"MSDUs with error:%s\t", get_err_str(i));607PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");608}609610len += scnprintf(buf + len, buf_len - len, "\n");611for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {612len += scnprintf(buf + len, buf_len - len,613"A-MPDU num subframes %s\t",614get_num_ampdu_subfrm_str(i));615PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");616}617618len += scnprintf(buf + len, buf_len - len, "\n");619for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {620len += scnprintf(buf + len, buf_len - len,621"A-MSDU num subframes %s\t\t",622get_num_amsdu_subfrm_str(i));623PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");624}625626spin_unlock_bh(&ar->data_lock);627628ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);629630kfree(buf);631632mutex_unlock(&ar->conf_mutex);633634return ret;635}636637static const struct file_operations fops_tid_stats_dump = {638.open = simple_open,639.read = ath10k_dbg_sta_read_tid_stats,640.owner = THIS_MODULE,641.llseek = default_llseek,642};643644static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,645char __user *user_buf,646size_t count, loff_t *ppos)647{648struct ieee80211_sta *sta = file->private_data;649struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;650struct ath10k *ar = arsta->arvif->ar;651struct ath10k_htt_data_stats *stats;652const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail",653"retry", "ampdu"};654const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};655int len = 0, i, j, k, retval = 0;656const int size = 16 * 4096;657char *buf;658659buf = kzalloc(size, GFP_KERNEL);660if (!buf)661return -ENOMEM;662663mutex_lock(&ar->conf_mutex);664665if (!arsta->tx_stats) {666ath10k_warn(ar, "failed to get tx stats");667mutex_unlock(&ar->conf_mutex);668kfree(buf);669return 0;670}671672spin_lock_bh(&ar->data_lock);673for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {674for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {675stats = &arsta->tx_stats->stats[k];676len += scnprintf(buf + len, size - len, "%s_%s\n",677str_name[k],678str[j]);679len += scnprintf(buf + len, size - len,680" VHT MCS %s\n",681str[j]);682for (i = 0; i < ATH10K_VHT_MCS_NUM; i++)683len += scnprintf(buf + len, size - len,684" %llu ",685stats->vht[j][i]);686len += scnprintf(buf + len, size - len, "\n");687len += scnprintf(buf + len, size - len, " HT MCS %s\n",688str[j]);689for (i = 0; i < ATH10K_HT_MCS_NUM; i++)690len += scnprintf(buf + len, size - len,691" %llu ", stats->ht[j][i]);692len += scnprintf(buf + len, size - len, "\n");693len += scnprintf(buf + len, size - len,694" BW %s (20,5,10,40,80,160 MHz)\n", str[j]);695len += scnprintf(buf + len, size - len,696" %llu %llu %llu %llu %llu %llu\n",697stats->bw[j][0], stats->bw[j][1],698stats->bw[j][2], stats->bw[j][3],699stats->bw[j][4], stats->bw[j][5]);700len += scnprintf(buf + len, size - len,701" NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);702len += scnprintf(buf + len, size - len,703" %llu %llu %llu %llu\n",704stats->nss[j][0], stats->nss[j][1],705stats->nss[j][2], stats->nss[j][3]);706len += scnprintf(buf + len, size - len,707" GI %s (LGI,SGI)\n",708str[j]);709len += scnprintf(buf + len, size - len, " %llu %llu\n",710stats->gi[j][0], stats->gi[j][1]);711len += scnprintf(buf + len, size - len,712" legacy rate %s (1,2 ... Mbps)\n ",713str[j]);714for (i = 0; i < ATH10K_LEGACY_NUM; i++)715len += scnprintf(buf + len, size - len, "%llu ",716stats->legacy[j][i]);717len += scnprintf(buf + len, size - len, "\n");718len += scnprintf(buf + len, size - len,719" Rate table %s (1,2 ... Mbps)\n ",720str[j]);721for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) {722len += scnprintf(buf + len, size - len, "%llu ",723stats->rate_table[j][i]);724if (!((i + 1) % 8))725len +=726scnprintf(buf + len, size - len, "\n ");727}728}729}730731len += scnprintf(buf + len, size - len,732"\nTX duration\n %llu usecs\n",733arsta->tx_stats->tx_duration);734len += scnprintf(buf + len, size - len,735"BA fails\n %llu\n", arsta->tx_stats->ba_fails);736len += scnprintf(buf + len, size - len,737"ack fails\n %llu\n", arsta->tx_stats->ack_fails);738spin_unlock_bh(&ar->data_lock);739740if (len > size)741len = size;742retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);743kfree(buf);744745mutex_unlock(&ar->conf_mutex);746return retval;747}748749static const struct file_operations fops_tx_stats = {750.read = ath10k_dbg_sta_dump_tx_stats,751.open = simple_open,752.owner = THIS_MODULE,753.llseek = default_llseek,754};755756void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,757struct ieee80211_sta *sta, struct dentry *dir)758{759struct ath10k *ar = hw->priv;760761debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);762debugfs_create_file("addba", 0200, dir, sta, &fops_addba);763debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);764debugfs_create_file("delba", 0200, dir, sta, &fops_delba);765debugfs_create_file("peer_debug_trigger", 0600, dir, sta,766&fops_peer_debug_trigger);767debugfs_create_file("dump_tid_stats", 0400, dir, sta,768&fops_tid_stats_dump);769770if (ath10k_peer_stats_enabled(ar) &&771ath10k_debug_is_extd_tx_stats_enabled(ar))772debugfs_create_file("tx_stats", 0400, dir, sta,773&fops_tx_stats);774debugfs_create_file("peer_ps_state", 0400, dir, sta,775&fops_peer_ps_state);776}777778779