Path: blob/main/sys/contrib/dev/athk/ath10k/debugfs_sta.c
104863 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.3* Copyright (c) 2018, The Linux Foundation. All rights reserved.4* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.5* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.6*/78#include "core.h"9#include "wmi-ops.h"10#include "txrx.h"11#include "debug.h"1213static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,14struct ath10k_sta_tid_stats *stats,15u32 msdu_count)16{17if (msdu_count == 1)18stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;19else if (msdu_count == 2)20stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;21else if (msdu_count == 3)22stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;23else if (msdu_count == 4)24stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;25else if (msdu_count > 4)26stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;27}2829static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,30struct ath10k_sta_tid_stats *stats,31u32 mpdu_count)32{33if (mpdu_count <= 10)34stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;35else if (mpdu_count <= 20)36stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;37else if (mpdu_count <= 30)38stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;39else if (mpdu_count <= 40)40stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;41else if (mpdu_count <= 50)42stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;43else if (mpdu_count <= 60)44stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;45else if (mpdu_count > 60)46stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;47}4849void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,50struct htt_rx_indication_mpdu_range *ranges,51int num_ranges)52{53struct ath10k_sta *arsta;54struct ath10k_peer *peer;55int i;5657if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))58return;5960rcu_read_lock();61spin_lock_bh(&ar->data_lock);6263peer = ath10k_peer_find_by_id(ar, peer_id);64if (!peer || !peer->sta)65goto out;6667arsta = (struct ath10k_sta *)peer->sta->drv_priv;6869for (i = 0; i < num_ranges; i++)70ath10k_rx_stats_update_ampdu_subfrm(ar,71&arsta->tid_stats[tid],72ranges[i].mpdu_count);7374out:75spin_unlock_bh(&ar->data_lock);76rcu_read_unlock();77}7879void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,80unsigned long num_msdus,81enum ath10k_pkt_rx_err err,82unsigned long unchain_cnt,83unsigned long drop_cnt,84unsigned long drop_cnt_filter,85unsigned long queued_msdus)86{87struct ieee80211_sta *sta;88struct ath10k_sta *arsta;89struct ieee80211_hdr *hdr;90struct ath10k_sta_tid_stats *stats;91u8 tid = IEEE80211_NUM_TIDS;92bool non_data_frm = false;9394hdr = (struct ieee80211_hdr *)first_hdr;95if (!ieee80211_is_data(hdr->frame_control))96non_data_frm = true;9798if (ieee80211_is_data_qos(hdr->frame_control))99tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;100101if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)102return;103104rcu_read_lock();105106sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);107if (!sta)108goto exit;109110arsta = (struct ath10k_sta *)sta->drv_priv;111112spin_lock_bh(&ar->data_lock);113stats = &arsta->tid_stats[tid];114stats->rx_pkt_from_fw += num_msdus;115stats->rx_pkt_unchained += unchain_cnt;116stats->rx_pkt_drop_chained += drop_cnt;117stats->rx_pkt_drop_filter += drop_cnt_filter;118if (err != ATH10K_PKT_RX_ERR_MAX)119stats->rx_pkt_err[err] += queued_msdus;120stats->rx_pkt_queued_for_mac += queued_msdus;121ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],122num_msdus);123spin_unlock_bh(&ar->data_lock);124125exit:126rcu_read_unlock();127}128129static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,130struct ath10k_fw_stats *stats)131{132struct ath10k_fw_extd_stats_peer *peer;133struct ieee80211_sta *sta;134struct ath10k_sta *arsta;135136rcu_read_lock();137list_for_each_entry(peer, &stats->peers_extd, list) {138sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,139NULL);140if (!sta)141continue;142arsta = (struct ath10k_sta *)sta->drv_priv;143arsta->rx_duration += (u64)peer->rx_duration;144}145rcu_read_unlock();146}147148static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,149struct ath10k_fw_stats *stats)150{151struct ath10k_fw_stats_peer *peer;152struct ieee80211_sta *sta;153struct ath10k_sta *arsta;154155rcu_read_lock();156list_for_each_entry(peer, &stats->peers, list) {157sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,158NULL);159if (!sta)160continue;161arsta = (struct ath10k_sta *)sta->drv_priv;162arsta->rx_duration += (u64)peer->rx_duration;163}164rcu_read_unlock();165}166167void ath10k_sta_update_rx_duration(struct ath10k *ar,168struct ath10k_fw_stats *stats)169{170if (stats->extended)171ath10k_sta_update_extd_stats_rx_duration(ar, stats);172else173ath10k_sta_update_stats_rx_duration(ar, stats);174}175176static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,177char __user *user_buf,178size_t count, loff_t *ppos)179{180struct ieee80211_sta *sta = file->private_data;181struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;182struct ath10k *ar = arsta->arvif->ar;183char buf[32];184int len = 0;185186mutex_lock(&ar->conf_mutex);187len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",188(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?189"auto" : "manual");190mutex_unlock(&ar->conf_mutex);191192return simple_read_from_buffer(user_buf, count, ppos, buf, len);193}194195static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,196const char __user *user_buf,197size_t count, loff_t *ppos)198{199struct ieee80211_sta *sta = file->private_data;200struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;201struct ath10k *ar = arsta->arvif->ar;202u32 aggr_mode;203int ret;204205if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))206return -EINVAL;207208if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)209return -EINVAL;210211mutex_lock(&ar->conf_mutex);212if ((ar->state != ATH10K_STATE_ON) ||213(aggr_mode == arsta->aggr_mode)) {214ret = count;215goto out;216}217218ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);219if (ret) {220ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);221goto out;222}223224arsta->aggr_mode = aggr_mode;225out:226mutex_unlock(&ar->conf_mutex);227return ret;228}229230static const struct file_operations fops_aggr_mode = {231.read = ath10k_dbg_sta_read_aggr_mode,232.write = ath10k_dbg_sta_write_aggr_mode,233.open = simple_open,234.owner = THIS_MODULE,235.llseek = default_llseek,236};237238static ssize_t ath10k_dbg_sta_write_addba(struct file *file,239const char __user *user_buf,240size_t count, loff_t *ppos)241{242struct ieee80211_sta *sta = file->private_data;243struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;244struct ath10k *ar = arsta->arvif->ar;245u32 tid, buf_size;246int ret;247char buf[64] = {};248249ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,250user_buf, count);251if (ret <= 0)252return ret;253254ret = sscanf(buf, "%u %u", &tid, &buf_size);255if (ret != 2)256return -EINVAL;257258/* Valid TID values are 0 through 15 */259if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)260return -EINVAL;261262mutex_lock(&ar->conf_mutex);263if ((ar->state != ATH10K_STATE_ON) ||264(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {265ret = count;266goto out;267}268269ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,270tid, buf_size);271if (ret) {272ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",273arsta->arvif->vdev_id, sta->addr, tid, buf_size);274}275276ret = count;277out:278mutex_unlock(&ar->conf_mutex);279return ret;280}281282static const struct file_operations fops_addba = {283.write = ath10k_dbg_sta_write_addba,284.open = simple_open,285.owner = THIS_MODULE,286.llseek = default_llseek,287};288289static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,290const char __user *user_buf,291size_t count, loff_t *ppos)292{293struct ieee80211_sta *sta = file->private_data;294struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;295struct ath10k *ar = arsta->arvif->ar;296u32 tid, status;297int ret;298char buf[64] = {};299300ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,301user_buf, count);302if (ret <= 0)303return ret;304305ret = sscanf(buf, "%u %u", &tid, &status);306if (ret != 2)307return -EINVAL;308309/* Valid TID values are 0 through 15 */310if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)311return -EINVAL;312313mutex_lock(&ar->conf_mutex);314if ((ar->state != ATH10K_STATE_ON) ||315(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {316ret = count;317goto out;318}319320ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,321tid, status);322if (ret) {323ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",324arsta->arvif->vdev_id, sta->addr, tid, status);325}326ret = count;327out:328mutex_unlock(&ar->conf_mutex);329return ret;330}331332static const struct file_operations fops_addba_resp = {333.write = ath10k_dbg_sta_write_addba_resp,334.open = simple_open,335.owner = THIS_MODULE,336.llseek = default_llseek,337};338339static ssize_t ath10k_dbg_sta_write_delba(struct file *file,340const char __user *user_buf,341size_t count, loff_t *ppos)342{343struct ieee80211_sta *sta = file->private_data;344struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;345struct ath10k *ar = arsta->arvif->ar;346u32 tid, initiator, reason;347int ret;348char buf[64] = {};349350ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,351user_buf, count);352if (ret <= 0)353return ret;354355ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);356if (ret != 3)357return -EINVAL;358359/* Valid TID values are 0 through 15 */360if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)361return -EINVAL;362363mutex_lock(&ar->conf_mutex);364if ((ar->state != ATH10K_STATE_ON) ||365(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {366ret = count;367goto out;368}369370ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,371tid, initiator, reason);372if (ret) {373ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",374arsta->arvif->vdev_id, sta->addr, tid, initiator,375reason);376}377ret = count;378out:379mutex_unlock(&ar->conf_mutex);380return ret;381}382383static const struct file_operations fops_delba = {384.write = ath10k_dbg_sta_write_delba,385.open = simple_open,386.owner = THIS_MODULE,387.llseek = default_llseek,388};389390static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file,391char __user *user_buf,392size_t count,393loff_t *ppos)394{395struct ieee80211_sta *sta = file->private_data;396struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;397struct ath10k *ar = arsta->arvif->ar;398char buf[8];399int len = 0;400401mutex_lock(&ar->conf_mutex);402len = scnprintf(buf, sizeof(buf) - len,403"Write 1 to once trigger the debug logs\n");404mutex_unlock(&ar->conf_mutex);405406return simple_read_from_buffer(user_buf, count, ppos, buf, len);407}408409static ssize_t410ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,411const char __user *user_buf,412size_t count, loff_t *ppos)413{414struct ieee80211_sta *sta = file->private_data;415struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;416struct ath10k *ar = arsta->arvif->ar;417u8 peer_debug_trigger;418int ret;419420if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger))421return -EINVAL;422423if (peer_debug_trigger != 1)424return -EINVAL;425426mutex_lock(&ar->conf_mutex);427428if (ar->state != ATH10K_STATE_ON) {429ret = -ENETDOWN;430goto out;431}432433ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr,434ar->wmi.peer_param->debug, peer_debug_trigger);435if (ret) {436ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n",437ret);438goto out;439}440out:441mutex_unlock(&ar->conf_mutex);442return ret ?: count;443}444445static const struct file_operations fops_peer_debug_trigger = {446.open = simple_open,447.read = ath10k_dbg_sta_read_peer_debug_trigger,448.write = ath10k_dbg_sta_write_peer_debug_trigger,449.owner = THIS_MODULE,450.llseek = default_llseek,451};452453static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,454char __user *user_buf,455size_t count, loff_t *ppos)456{457struct ieee80211_sta *sta = file->private_data;458struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;459struct ath10k *ar = arsta->arvif->ar;460char buf[20];461int len = 0;462463spin_lock_bh(&ar->data_lock);464465len = scnprintf(buf, sizeof(buf) - len, "%d\n",466arsta->peer_ps_state);467468spin_unlock_bh(&ar->data_lock);469470return simple_read_from_buffer(user_buf, count, ppos, buf, len);471}472473static const struct file_operations fops_peer_ps_state = {474.open = simple_open,475.read = ath10k_dbg_sta_read_peer_ps_state,476.owner = THIS_MODULE,477.llseek = default_llseek,478};479480static char *get_err_str(enum ath10k_pkt_rx_err i)481{482switch (i) {483case ATH10K_PKT_RX_ERR_FCS:484return "fcs_err";485case ATH10K_PKT_RX_ERR_TKIP:486return "tkip_err";487case ATH10K_PKT_RX_ERR_CRYPT:488return "crypt_err";489case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:490return "peer_idx_inval";491case ATH10K_PKT_RX_ERR_MAX:492return "unknown";493}494495return "unknown";496}497498static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)499{500switch (i) {501case ATH10K_AMPDU_SUBFRM_NUM_10:502return "up to 10";503case ATH10K_AMPDU_SUBFRM_NUM_20:504return "11-20";505case ATH10K_AMPDU_SUBFRM_NUM_30:506return "21-30";507case ATH10K_AMPDU_SUBFRM_NUM_40:508return "31-40";509case ATH10K_AMPDU_SUBFRM_NUM_50:510return "41-50";511case ATH10K_AMPDU_SUBFRM_NUM_60:512return "51-60";513case ATH10K_AMPDU_SUBFRM_NUM_MORE:514return ">60";515case ATH10K_AMPDU_SUBFRM_NUM_MAX:516return "0";517}518519return "0";520}521522static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)523{524switch (i) {525case ATH10K_AMSDU_SUBFRM_NUM_1:526return "1";527case ATH10K_AMSDU_SUBFRM_NUM_2:528return "2";529case ATH10K_AMSDU_SUBFRM_NUM_3:530return "3";531case ATH10K_AMSDU_SUBFRM_NUM_4:532return "4";533case ATH10K_AMSDU_SUBFRM_NUM_MORE:534return ">4";535case ATH10K_AMSDU_SUBFRM_NUM_MAX:536return "0";537}538539return "0";540}541542#define PRINT_TID_STATS(_field, _tabs) \543do { \544int k = 0; \545for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \546if (ar->sta_tid_stats_mask & BIT(j)) { \547len += scnprintf(buf + len, buf_len - len, \548"[%02d] %-10lu ", \549j, stats[j]._field); \550k++; \551if (k % 8 == 0) { \552len += scnprintf(buf + len, \553buf_len - len, "\n"); \554len += scnprintf(buf + len, \555buf_len - len, \556_tabs); \557} \558} \559} \560len += scnprintf(buf + len, buf_len - len, "\n"); \561} while (0)562563static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,564char __user *user_buf,565size_t count, loff_t *ppos)566{567struct ieee80211_sta *sta = file->private_data;568struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;569struct ath10k *ar = arsta->arvif->ar;570struct ath10k_sta_tid_stats *stats = arsta->tid_stats;571size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;572char *buf;573int i, j;574ssize_t ret;575576buf = kzalloc(buf_len, GFP_KERNEL);577if (!buf)578return -ENOMEM;579580mutex_lock(&ar->conf_mutex);581582spin_lock_bh(&ar->data_lock);583584len += scnprintf(buf + len, buf_len - len,585"\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");586len += scnprintf(buf + len, buf_len - len,587"\t\t------------------------------------------\n");588len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");589PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");590591len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");592PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");593594len += scnprintf(buf + len, buf_len - len,595"MSDUs locally dropped:chained\t");596PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");597598len += scnprintf(buf + len, buf_len - len,599"MSDUs locally dropped:filtered\t");600PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");601602len += scnprintf(buf + len, buf_len - len,603"MSDUs queued for mac80211\t");604PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");605606for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {607len += scnprintf(buf + len, buf_len - len,608"MSDUs with error:%s\t", get_err_str(i));609PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");610}611612len += scnprintf(buf + len, buf_len - len, "\n");613for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {614len += scnprintf(buf + len, buf_len - len,615"A-MPDU num subframes %s\t",616get_num_ampdu_subfrm_str(i));617PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");618}619620len += scnprintf(buf + len, buf_len - len, "\n");621for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {622len += scnprintf(buf + len, buf_len - len,623"A-MSDU num subframes %s\t\t",624get_num_amsdu_subfrm_str(i));625PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");626}627628spin_unlock_bh(&ar->data_lock);629630ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);631632kfree(buf);633634mutex_unlock(&ar->conf_mutex);635636return ret;637}638639static const struct file_operations fops_tid_stats_dump = {640.open = simple_open,641.read = ath10k_dbg_sta_read_tid_stats,642.owner = THIS_MODULE,643.llseek = default_llseek,644};645646static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,647char __user *user_buf,648size_t count, loff_t *ppos)649{650struct ieee80211_sta *sta = file->private_data;651struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;652struct ath10k *ar = arsta->arvif->ar;653struct ath10k_htt_data_stats *stats;654const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail",655"retry", "ampdu"};656const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};657int len = 0, i, j, k, retval = 0;658const int size = 16 * 4096;659char *buf;660661buf = kzalloc(size, GFP_KERNEL);662if (!buf)663return -ENOMEM;664665mutex_lock(&ar->conf_mutex);666667if (!arsta->tx_stats) {668ath10k_warn(ar, "failed to get tx stats");669mutex_unlock(&ar->conf_mutex);670kfree(buf);671return 0;672}673674spin_lock_bh(&ar->data_lock);675for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {676for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {677stats = &arsta->tx_stats->stats[k];678len += scnprintf(buf + len, size - len, "%s_%s\n",679str_name[k],680str[j]);681len += scnprintf(buf + len, size - len,682" VHT MCS %s\n",683str[j]);684for (i = 0; i < ATH10K_VHT_MCS_NUM; i++)685len += scnprintf(buf + len, size - len,686" %llu ",687stats->vht[j][i]);688len += scnprintf(buf + len, size - len, "\n");689len += scnprintf(buf + len, size - len, " HT MCS %s\n",690str[j]);691for (i = 0; i < ATH10K_HT_MCS_NUM; i++)692len += scnprintf(buf + len, size - len,693" %llu ", stats->ht[j][i]);694len += scnprintf(buf + len, size - len, "\n");695len += scnprintf(buf + len, size - len,696" BW %s (20,5,10,40,80,160 MHz)\n", str[j]);697len += scnprintf(buf + len, size - len,698" %llu %llu %llu %llu %llu %llu\n",699stats->bw[j][0], stats->bw[j][1],700stats->bw[j][2], stats->bw[j][3],701stats->bw[j][4], stats->bw[j][5]);702len += scnprintf(buf + len, size - len,703" NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);704len += scnprintf(buf + len, size - len,705" %llu %llu %llu %llu\n",706stats->nss[j][0], stats->nss[j][1],707stats->nss[j][2], stats->nss[j][3]);708len += scnprintf(buf + len, size - len,709" GI %s (LGI,SGI)\n",710str[j]);711len += scnprintf(buf + len, size - len, " %llu %llu\n",712stats->gi[j][0], stats->gi[j][1]);713len += scnprintf(buf + len, size - len,714" legacy rate %s (1,2 ... Mbps)\n ",715str[j]);716for (i = 0; i < ATH10K_LEGACY_NUM; i++)717len += scnprintf(buf + len, size - len, "%llu ",718stats->legacy[j][i]);719len += scnprintf(buf + len, size - len, "\n");720len += scnprintf(buf + len, size - len,721" Rate table %s (1,2 ... Mbps)\n ",722str[j]);723for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) {724len += scnprintf(buf + len, size - len, "%llu ",725stats->rate_table[j][i]);726if (!((i + 1) % 8))727len +=728scnprintf(buf + len, size - len, "\n ");729}730}731}732733len += scnprintf(buf + len, size - len,734"\nTX duration\n %llu usecs\n",735arsta->tx_stats->tx_duration);736len += scnprintf(buf + len, size - len,737"BA fails\n %llu\n", arsta->tx_stats->ba_fails);738len += scnprintf(buf + len, size - len,739"ack fails\n %llu\n", arsta->tx_stats->ack_fails);740spin_unlock_bh(&ar->data_lock);741742if (len > size)743len = size;744retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);745kfree(buf);746747mutex_unlock(&ar->conf_mutex);748return retval;749}750751static const struct file_operations fops_tx_stats = {752.read = ath10k_dbg_sta_dump_tx_stats,753.open = simple_open,754.owner = THIS_MODULE,755.llseek = default_llseek,756};757758void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,759struct ieee80211_sta *sta, struct dentry *dir)760{761struct ath10k *ar = hw->priv;762763debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);764debugfs_create_file("addba", 0200, dir, sta, &fops_addba);765debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);766debugfs_create_file("delba", 0200, dir, sta, &fops_delba);767debugfs_create_file("peer_debug_trigger", 0600, dir, sta,768&fops_peer_debug_trigger);769debugfs_create_file("dump_tid_stats", 0400, dir, sta,770&fops_tid_stats_dump);771772if (ath10k_peer_stats_enabled(ar) &&773ath10k_debug_is_extd_tx_stats_enabled(ar))774debugfs_create_file("tx_stats", 0400, dir, sta,775&fops_tx_stats);776debugfs_create_file("peer_ps_state", 0400, dir, sta,777&fops_peer_ps_state);778}779780781