162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. 462306a36Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "core.h" 862306a36Sopenharmony_ci#include "wmi-ops.h" 962306a36Sopenharmony_ci#include "txrx.h" 1062306a36Sopenharmony_ci#include "debug.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar, 1362306a36Sopenharmony_ci struct ath10k_sta_tid_stats *stats, 1462306a36Sopenharmony_ci u32 msdu_count) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci if (msdu_count == 1) 1762306a36Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++; 1862306a36Sopenharmony_ci else if (msdu_count == 2) 1962306a36Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++; 2062306a36Sopenharmony_ci else if (msdu_count == 3) 2162306a36Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++; 2262306a36Sopenharmony_ci else if (msdu_count == 4) 2362306a36Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++; 2462306a36Sopenharmony_ci else if (msdu_count > 4) 2562306a36Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++; 2662306a36Sopenharmony_ci} 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar, 2962306a36Sopenharmony_ci struct ath10k_sta_tid_stats *stats, 3062306a36Sopenharmony_ci u32 mpdu_count) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci if (mpdu_count <= 10) 3362306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++; 3462306a36Sopenharmony_ci else if (mpdu_count <= 20) 3562306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++; 3662306a36Sopenharmony_ci else if (mpdu_count <= 30) 3762306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++; 3862306a36Sopenharmony_ci else if (mpdu_count <= 40) 3962306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++; 4062306a36Sopenharmony_ci else if (mpdu_count <= 50) 4162306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++; 4262306a36Sopenharmony_ci else if (mpdu_count <= 60) 4362306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++; 4462306a36Sopenharmony_ci else if (mpdu_count > 60) 4562306a36Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_civoid ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid, 4962306a36Sopenharmony_ci struct htt_rx_indication_mpdu_range *ranges, 5062306a36Sopenharmony_ci int num_ranges) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct ath10k_sta *arsta; 5362306a36Sopenharmony_ci struct ath10k_peer *peer; 5462306a36Sopenharmony_ci int i; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid))) 5762306a36Sopenharmony_ci return; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci rcu_read_lock(); 6062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci peer = ath10k_peer_find_by_id(ar, peer_id); 6362306a36Sopenharmony_ci if (!peer || !peer->sta) 6462306a36Sopenharmony_ci goto out; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci arsta = (struct ath10k_sta *)peer->sta->drv_priv; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci for (i = 0; i < num_ranges; i++) 6962306a36Sopenharmony_ci ath10k_rx_stats_update_ampdu_subfrm(ar, 7062306a36Sopenharmony_ci &arsta->tid_stats[tid], 7162306a36Sopenharmony_ci ranges[i].mpdu_count); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciout: 7462306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 7562306a36Sopenharmony_ci rcu_read_unlock(); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr, 7962306a36Sopenharmony_ci unsigned long num_msdus, 8062306a36Sopenharmony_ci enum ath10k_pkt_rx_err err, 8162306a36Sopenharmony_ci unsigned long unchain_cnt, 8262306a36Sopenharmony_ci unsigned long drop_cnt, 8362306a36Sopenharmony_ci unsigned long drop_cnt_filter, 8462306a36Sopenharmony_ci unsigned long queued_msdus) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct ieee80211_sta *sta; 8762306a36Sopenharmony_ci struct ath10k_sta *arsta; 8862306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 8962306a36Sopenharmony_ci struct ath10k_sta_tid_stats *stats; 9062306a36Sopenharmony_ci u8 tid = IEEE80211_NUM_TIDS; 9162306a36Sopenharmony_ci bool non_data_frm = false; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)first_hdr; 9462306a36Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 9562306a36Sopenharmony_ci non_data_frm = true; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 9862306a36Sopenharmony_ci tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm) 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci rcu_read_lock(); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL); 10662306a36Sopenharmony_ci if (!sta) 10762306a36Sopenharmony_ci goto exit; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 11262306a36Sopenharmony_ci stats = &arsta->tid_stats[tid]; 11362306a36Sopenharmony_ci stats->rx_pkt_from_fw += num_msdus; 11462306a36Sopenharmony_ci stats->rx_pkt_unchained += unchain_cnt; 11562306a36Sopenharmony_ci stats->rx_pkt_drop_chained += drop_cnt; 11662306a36Sopenharmony_ci stats->rx_pkt_drop_filter += drop_cnt_filter; 11762306a36Sopenharmony_ci if (err != ATH10K_PKT_RX_ERR_MAX) 11862306a36Sopenharmony_ci stats->rx_pkt_err[err] += queued_msdus; 11962306a36Sopenharmony_ci stats->rx_pkt_queued_for_mac += queued_msdus; 12062306a36Sopenharmony_ci ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid], 12162306a36Sopenharmony_ci num_msdus); 12262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciexit: 12562306a36Sopenharmony_ci rcu_read_unlock(); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar, 12962306a36Sopenharmony_ci struct ath10k_fw_stats *stats) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct ath10k_fw_extd_stats_peer *peer; 13262306a36Sopenharmony_ci struct ieee80211_sta *sta; 13362306a36Sopenharmony_ci struct ath10k_sta *arsta; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci rcu_read_lock(); 13662306a36Sopenharmony_ci list_for_each_entry(peer, &stats->peers_extd, list) { 13762306a36Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, 13862306a36Sopenharmony_ci NULL); 13962306a36Sopenharmony_ci if (!sta) 14062306a36Sopenharmony_ci continue; 14162306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 14262306a36Sopenharmony_ci arsta->rx_duration += (u64)peer->rx_duration; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci rcu_read_unlock(); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic void ath10k_sta_update_stats_rx_duration(struct ath10k *ar, 14862306a36Sopenharmony_ci struct ath10k_fw_stats *stats) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct ath10k_fw_stats_peer *peer; 15162306a36Sopenharmony_ci struct ieee80211_sta *sta; 15262306a36Sopenharmony_ci struct ath10k_sta *arsta; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci rcu_read_lock(); 15562306a36Sopenharmony_ci list_for_each_entry(peer, &stats->peers, list) { 15662306a36Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, 15762306a36Sopenharmony_ci NULL); 15862306a36Sopenharmony_ci if (!sta) 15962306a36Sopenharmony_ci continue; 16062306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 16162306a36Sopenharmony_ci arsta->rx_duration += (u64)peer->rx_duration; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci rcu_read_unlock(); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_civoid ath10k_sta_update_rx_duration(struct ath10k *ar, 16762306a36Sopenharmony_ci struct ath10k_fw_stats *stats) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci if (stats->extended) 17062306a36Sopenharmony_ci ath10k_sta_update_extd_stats_rx_duration(ar, stats); 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci ath10k_sta_update_stats_rx_duration(ar, stats); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, 17662306a36Sopenharmony_ci char __user *user_buf, 17762306a36Sopenharmony_ci size_t count, loff_t *ppos) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 18062306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 18162306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 18262306a36Sopenharmony_ci char buf[32]; 18362306a36Sopenharmony_ci int len = 0; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 18662306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", 18762306a36Sopenharmony_ci (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? 18862306a36Sopenharmony_ci "auto" : "manual"); 18962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, 19562306a36Sopenharmony_ci const char __user *user_buf, 19662306a36Sopenharmony_ci size_t count, loff_t *ppos) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 19962306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 20062306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 20162306a36Sopenharmony_ci u32 aggr_mode; 20262306a36Sopenharmony_ci int ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) 20862306a36Sopenharmony_ci return -EINVAL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 21162306a36Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 21262306a36Sopenharmony_ci (aggr_mode == arsta->aggr_mode)) { 21362306a36Sopenharmony_ci ret = count; 21462306a36Sopenharmony_ci goto out; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); 21862306a36Sopenharmony_ci if (ret) { 21962306a36Sopenharmony_ci ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); 22062306a36Sopenharmony_ci goto out; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci arsta->aggr_mode = aggr_mode; 22462306a36Sopenharmony_ciout: 22562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 22662306a36Sopenharmony_ci return ret; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic const struct file_operations fops_aggr_mode = { 23062306a36Sopenharmony_ci .read = ath10k_dbg_sta_read_aggr_mode, 23162306a36Sopenharmony_ci .write = ath10k_dbg_sta_write_aggr_mode, 23262306a36Sopenharmony_ci .open = simple_open, 23362306a36Sopenharmony_ci .owner = THIS_MODULE, 23462306a36Sopenharmony_ci .llseek = default_llseek, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_addba(struct file *file, 23862306a36Sopenharmony_ci const char __user *user_buf, 23962306a36Sopenharmony_ci size_t count, loff_t *ppos) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 24262306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 24362306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 24462306a36Sopenharmony_ci u32 tid, buf_size; 24562306a36Sopenharmony_ci int ret; 24662306a36Sopenharmony_ci char buf[64] = {0}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 24962306a36Sopenharmony_ci user_buf, count); 25062306a36Sopenharmony_ci if (ret <= 0) 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ret = sscanf(buf, "%u %u", &tid, &buf_size); 25462306a36Sopenharmony_ci if (ret != 2) 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Valid TID values are 0 through 15 */ 25862306a36Sopenharmony_ci if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 26262306a36Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 26362306a36Sopenharmony_ci (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 26462306a36Sopenharmony_ci ret = count; 26562306a36Sopenharmony_ci goto out; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, 26962306a36Sopenharmony_ci tid, buf_size); 27062306a36Sopenharmony_ci if (ret) { 27162306a36Sopenharmony_ci ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", 27262306a36Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, buf_size); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = count; 27662306a36Sopenharmony_ciout: 27762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 27862306a36Sopenharmony_ci return ret; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic const struct file_operations fops_addba = { 28262306a36Sopenharmony_ci .write = ath10k_dbg_sta_write_addba, 28362306a36Sopenharmony_ci .open = simple_open, 28462306a36Sopenharmony_ci .owner = THIS_MODULE, 28562306a36Sopenharmony_ci .llseek = default_llseek, 28662306a36Sopenharmony_ci}; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, 28962306a36Sopenharmony_ci const char __user *user_buf, 29062306a36Sopenharmony_ci size_t count, loff_t *ppos) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 29362306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 29462306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 29562306a36Sopenharmony_ci u32 tid, status; 29662306a36Sopenharmony_ci int ret; 29762306a36Sopenharmony_ci char buf[64] = {0}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 30062306a36Sopenharmony_ci user_buf, count); 30162306a36Sopenharmony_ci if (ret <= 0) 30262306a36Sopenharmony_ci return ret; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci ret = sscanf(buf, "%u %u", &tid, &status); 30562306a36Sopenharmony_ci if (ret != 2) 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Valid TID values are 0 through 15 */ 30962306a36Sopenharmony_ci if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 31362306a36Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 31462306a36Sopenharmony_ci (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 31562306a36Sopenharmony_ci ret = count; 31662306a36Sopenharmony_ci goto out; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, 32062306a36Sopenharmony_ci tid, status); 32162306a36Sopenharmony_ci if (ret) { 32262306a36Sopenharmony_ci ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", 32362306a36Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, status); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci ret = count; 32662306a36Sopenharmony_ciout: 32762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 32862306a36Sopenharmony_ci return ret; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic const struct file_operations fops_addba_resp = { 33262306a36Sopenharmony_ci .write = ath10k_dbg_sta_write_addba_resp, 33362306a36Sopenharmony_ci .open = simple_open, 33462306a36Sopenharmony_ci .owner = THIS_MODULE, 33562306a36Sopenharmony_ci .llseek = default_llseek, 33662306a36Sopenharmony_ci}; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_delba(struct file *file, 33962306a36Sopenharmony_ci const char __user *user_buf, 34062306a36Sopenharmony_ci size_t count, loff_t *ppos) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 34362306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 34462306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 34562306a36Sopenharmony_ci u32 tid, initiator, reason; 34662306a36Sopenharmony_ci int ret; 34762306a36Sopenharmony_ci char buf[64] = {0}; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 35062306a36Sopenharmony_ci user_buf, count); 35162306a36Sopenharmony_ci if (ret <= 0) 35262306a36Sopenharmony_ci return ret; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); 35562306a36Sopenharmony_ci if (ret != 3) 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Valid TID values are 0 through 15 */ 35962306a36Sopenharmony_ci if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 36362306a36Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 36462306a36Sopenharmony_ci (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 36562306a36Sopenharmony_ci ret = count; 36662306a36Sopenharmony_ci goto out; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, 37062306a36Sopenharmony_ci tid, initiator, reason); 37162306a36Sopenharmony_ci if (ret) { 37262306a36Sopenharmony_ci ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", 37362306a36Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, initiator, 37462306a36Sopenharmony_ci reason); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci ret = count; 37762306a36Sopenharmony_ciout: 37862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 37962306a36Sopenharmony_ci return ret; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic const struct file_operations fops_delba = { 38362306a36Sopenharmony_ci .write = ath10k_dbg_sta_write_delba, 38462306a36Sopenharmony_ci .open = simple_open, 38562306a36Sopenharmony_ci .owner = THIS_MODULE, 38662306a36Sopenharmony_ci .llseek = default_llseek, 38762306a36Sopenharmony_ci}; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file, 39062306a36Sopenharmony_ci char __user *user_buf, 39162306a36Sopenharmony_ci size_t count, 39262306a36Sopenharmony_ci loff_t *ppos) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 39562306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 39662306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 39762306a36Sopenharmony_ci char buf[8]; 39862306a36Sopenharmony_ci int len = 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 40162306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, 40262306a36Sopenharmony_ci "Write 1 to once trigger the debug logs\n"); 40362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic ssize_t 40962306a36Sopenharmony_ciath10k_dbg_sta_write_peer_debug_trigger(struct file *file, 41062306a36Sopenharmony_ci const char __user *user_buf, 41162306a36Sopenharmony_ci size_t count, loff_t *ppos) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 41462306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 41562306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 41662306a36Sopenharmony_ci u8 peer_debug_trigger; 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger)) 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (peer_debug_trigger != 1) 42362306a36Sopenharmony_ci return -EINVAL; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 42862306a36Sopenharmony_ci ret = -ENETDOWN; 42962306a36Sopenharmony_ci goto out; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr, 43362306a36Sopenharmony_ci ar->wmi.peer_param->debug, peer_debug_trigger); 43462306a36Sopenharmony_ci if (ret) { 43562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n", 43662306a36Sopenharmony_ci ret); 43762306a36Sopenharmony_ci goto out; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ciout: 44062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 44162306a36Sopenharmony_ci return count; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const struct file_operations fops_peer_debug_trigger = { 44562306a36Sopenharmony_ci .open = simple_open, 44662306a36Sopenharmony_ci .read = ath10k_dbg_sta_read_peer_debug_trigger, 44762306a36Sopenharmony_ci .write = ath10k_dbg_sta_write_peer_debug_trigger, 44862306a36Sopenharmony_ci .owner = THIS_MODULE, 44962306a36Sopenharmony_ci .llseek = default_llseek, 45062306a36Sopenharmony_ci}; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file, 45362306a36Sopenharmony_ci char __user *user_buf, 45462306a36Sopenharmony_ci size_t count, loff_t *ppos) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 45762306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 45862306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 45962306a36Sopenharmony_ci char buf[20]; 46062306a36Sopenharmony_ci int len = 0; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 46562306a36Sopenharmony_ci arsta->peer_ps_state); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic const struct file_operations fops_peer_ps_state = { 47362306a36Sopenharmony_ci .open = simple_open, 47462306a36Sopenharmony_ci .read = ath10k_dbg_sta_read_peer_ps_state, 47562306a36Sopenharmony_ci .owner = THIS_MODULE, 47662306a36Sopenharmony_ci .llseek = default_llseek, 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic char *get_err_str(enum ath10k_pkt_rx_err i) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci switch (i) { 48262306a36Sopenharmony_ci case ATH10K_PKT_RX_ERR_FCS: 48362306a36Sopenharmony_ci return "fcs_err"; 48462306a36Sopenharmony_ci case ATH10K_PKT_RX_ERR_TKIP: 48562306a36Sopenharmony_ci return "tkip_err"; 48662306a36Sopenharmony_ci case ATH10K_PKT_RX_ERR_CRYPT: 48762306a36Sopenharmony_ci return "crypt_err"; 48862306a36Sopenharmony_ci case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL: 48962306a36Sopenharmony_ci return "peer_idx_inval"; 49062306a36Sopenharmony_ci case ATH10K_PKT_RX_ERR_MAX: 49162306a36Sopenharmony_ci return "unknown"; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return "unknown"; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci switch (i) { 50062306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_10: 50162306a36Sopenharmony_ci return "up to 10"; 50262306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_20: 50362306a36Sopenharmony_ci return "11-20"; 50462306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_30: 50562306a36Sopenharmony_ci return "21-30"; 50662306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_40: 50762306a36Sopenharmony_ci return "31-40"; 50862306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_50: 50962306a36Sopenharmony_ci return "41-50"; 51062306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_60: 51162306a36Sopenharmony_ci return "51-60"; 51262306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_MORE: 51362306a36Sopenharmony_ci return ">60"; 51462306a36Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_MAX: 51562306a36Sopenharmony_ci return "0"; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return "0"; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci switch (i) { 52462306a36Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_1: 52562306a36Sopenharmony_ci return "1"; 52662306a36Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_2: 52762306a36Sopenharmony_ci return "2"; 52862306a36Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_3: 52962306a36Sopenharmony_ci return "3"; 53062306a36Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_4: 53162306a36Sopenharmony_ci return "4"; 53262306a36Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_MORE: 53362306a36Sopenharmony_ci return ">4"; 53462306a36Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_MAX: 53562306a36Sopenharmony_ci return "0"; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return "0"; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci#define PRINT_TID_STATS(_field, _tabs) \ 54262306a36Sopenharmony_ci do { \ 54362306a36Sopenharmony_ci int k = 0; \ 54462306a36Sopenharmony_ci for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \ 54562306a36Sopenharmony_ci if (ar->sta_tid_stats_mask & BIT(j)) { \ 54662306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, \ 54762306a36Sopenharmony_ci "[%02d] %-10lu ", \ 54862306a36Sopenharmony_ci j, stats[j]._field); \ 54962306a36Sopenharmony_ci k++; \ 55062306a36Sopenharmony_ci if (k % 8 == 0) { \ 55162306a36Sopenharmony_ci len += scnprintf(buf + len, \ 55262306a36Sopenharmony_ci buf_len - len, "\n"); \ 55362306a36Sopenharmony_ci len += scnprintf(buf + len, \ 55462306a36Sopenharmony_ci buf_len - len, \ 55562306a36Sopenharmony_ci _tabs); \ 55662306a36Sopenharmony_ci } \ 55762306a36Sopenharmony_ci } \ 55862306a36Sopenharmony_ci } \ 55962306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); \ 56062306a36Sopenharmony_ci } while (0) 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file, 56362306a36Sopenharmony_ci char __user *user_buf, 56462306a36Sopenharmony_ci size_t count, loff_t *ppos) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 56762306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 56862306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 56962306a36Sopenharmony_ci struct ath10k_sta_tid_stats *stats = arsta->tid_stats; 57062306a36Sopenharmony_ci size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS; 57162306a36Sopenharmony_ci char *buf; 57262306a36Sopenharmony_ci int i, j; 57362306a36Sopenharmony_ci ssize_t ret; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 57662306a36Sopenharmony_ci if (!buf) 57762306a36Sopenharmony_ci return -ENOMEM; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 58462306a36Sopenharmony_ci "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n"); 58562306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 58662306a36Sopenharmony_ci "\t\t------------------------------------------\n"); 58762306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t"); 58862306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t"); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t"); 59162306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t"); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 59462306a36Sopenharmony_ci "MSDUs locally dropped:chained\t"); 59562306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t"); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 59862306a36Sopenharmony_ci "MSDUs locally dropped:filtered\t"); 59962306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t"); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 60262306a36Sopenharmony_ci "MSDUs queued for mac80211\t"); 60362306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t"); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) { 60662306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 60762306a36Sopenharmony_ci "MSDUs with error:%s\t", get_err_str(i)); 60862306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t"); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); 61262306a36Sopenharmony_ci for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) { 61362306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 61462306a36Sopenharmony_ci "A-MPDU num subframes %s\t", 61562306a36Sopenharmony_ci get_num_ampdu_subfrm_str(i)); 61662306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t"); 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); 62062306a36Sopenharmony_ci for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) { 62162306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 62262306a36Sopenharmony_ci "A-MSDU num subframes %s\t\t", 62362306a36Sopenharmony_ci get_num_amsdu_subfrm_str(i)); 62462306a36Sopenharmony_ci PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t"); 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci kfree(buf); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return ret; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic const struct file_operations fops_tid_stats_dump = { 63962306a36Sopenharmony_ci .open = simple_open, 64062306a36Sopenharmony_ci .read = ath10k_dbg_sta_read_tid_stats, 64162306a36Sopenharmony_ci .owner = THIS_MODULE, 64262306a36Sopenharmony_ci .llseek = default_llseek, 64362306a36Sopenharmony_ci}; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file, 64662306a36Sopenharmony_ci char __user *user_buf, 64762306a36Sopenharmony_ci size_t count, loff_t *ppos) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 65062306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 65162306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 65262306a36Sopenharmony_ci struct ath10k_htt_data_stats *stats; 65362306a36Sopenharmony_ci const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail", 65462306a36Sopenharmony_ci "retry", "ampdu"}; 65562306a36Sopenharmony_ci const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"}; 65662306a36Sopenharmony_ci int len = 0, i, j, k, retval = 0; 65762306a36Sopenharmony_ci const int size = 16 * 4096; 65862306a36Sopenharmony_ci char *buf; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci buf = kzalloc(size, GFP_KERNEL); 66162306a36Sopenharmony_ci if (!buf) 66262306a36Sopenharmony_ci return -ENOMEM; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (!arsta->tx_stats) { 66762306a36Sopenharmony_ci ath10k_warn(ar, "failed to get tx stats"); 66862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 66962306a36Sopenharmony_ci kfree(buf); 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 67462306a36Sopenharmony_ci for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) { 67562306a36Sopenharmony_ci for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) { 67662306a36Sopenharmony_ci stats = &arsta->tx_stats->stats[k]; 67762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "%s_%s\n", 67862306a36Sopenharmony_ci str_name[k], 67962306a36Sopenharmony_ci str[j]); 68062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 68162306a36Sopenharmony_ci " VHT MCS %s\n", 68262306a36Sopenharmony_ci str[j]); 68362306a36Sopenharmony_ci for (i = 0; i < ATH10K_VHT_MCS_NUM; i++) 68462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 68562306a36Sopenharmony_ci " %llu ", 68662306a36Sopenharmony_ci stats->vht[j][i]); 68762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 68862306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, " HT MCS %s\n", 68962306a36Sopenharmony_ci str[j]); 69062306a36Sopenharmony_ci for (i = 0; i < ATH10K_HT_MCS_NUM; i++) 69162306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 69262306a36Sopenharmony_ci " %llu ", stats->ht[j][i]); 69362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 69462306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 69562306a36Sopenharmony_ci " BW %s (20,5,10,40,80,160 MHz)\n", str[j]); 69662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 69762306a36Sopenharmony_ci " %llu %llu %llu %llu %llu %llu\n", 69862306a36Sopenharmony_ci stats->bw[j][0], stats->bw[j][1], 69962306a36Sopenharmony_ci stats->bw[j][2], stats->bw[j][3], 70062306a36Sopenharmony_ci stats->bw[j][4], stats->bw[j][5]); 70162306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 70262306a36Sopenharmony_ci " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]); 70362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 70462306a36Sopenharmony_ci " %llu %llu %llu %llu\n", 70562306a36Sopenharmony_ci stats->nss[j][0], stats->nss[j][1], 70662306a36Sopenharmony_ci stats->nss[j][2], stats->nss[j][3]); 70762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 70862306a36Sopenharmony_ci " GI %s (LGI,SGI)\n", 70962306a36Sopenharmony_ci str[j]); 71062306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, " %llu %llu\n", 71162306a36Sopenharmony_ci stats->gi[j][0], stats->gi[j][1]); 71262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 71362306a36Sopenharmony_ci " legacy rate %s (1,2 ... Mbps)\n ", 71462306a36Sopenharmony_ci str[j]); 71562306a36Sopenharmony_ci for (i = 0; i < ATH10K_LEGACY_NUM; i++) 71662306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", 71762306a36Sopenharmony_ci stats->legacy[j][i]); 71862306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 71962306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 72062306a36Sopenharmony_ci " Rate table %s (1,2 ... Mbps)\n ", 72162306a36Sopenharmony_ci str[j]); 72262306a36Sopenharmony_ci for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) { 72362306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", 72462306a36Sopenharmony_ci stats->rate_table[j][i]); 72562306a36Sopenharmony_ci if (!((i + 1) % 8)) 72662306a36Sopenharmony_ci len += 72762306a36Sopenharmony_ci scnprintf(buf + len, size - len, "\n "); 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 73362306a36Sopenharmony_ci "\nTX duration\n %llu usecs\n", 73462306a36Sopenharmony_ci arsta->tx_stats->tx_duration); 73562306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 73662306a36Sopenharmony_ci "BA fails\n %llu\n", arsta->tx_stats->ba_fails); 73762306a36Sopenharmony_ci len += scnprintf(buf + len, size - len, 73862306a36Sopenharmony_ci "ack fails\n %llu\n", arsta->tx_stats->ack_fails); 73962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (len > size) 74262306a36Sopenharmony_ci len = size; 74362306a36Sopenharmony_ci retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 74462306a36Sopenharmony_ci kfree(buf); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 74762306a36Sopenharmony_ci return retval; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic const struct file_operations fops_tx_stats = { 75162306a36Sopenharmony_ci .read = ath10k_dbg_sta_dump_tx_stats, 75262306a36Sopenharmony_ci .open = simple_open, 75362306a36Sopenharmony_ci .owner = THIS_MODULE, 75462306a36Sopenharmony_ci .llseek = default_llseek, 75562306a36Sopenharmony_ci}; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_civoid ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 75862306a36Sopenharmony_ci struct ieee80211_sta *sta, struct dentry *dir) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode); 76362306a36Sopenharmony_ci debugfs_create_file("addba", 0200, dir, sta, &fops_addba); 76462306a36Sopenharmony_ci debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp); 76562306a36Sopenharmony_ci debugfs_create_file("delba", 0200, dir, sta, &fops_delba); 76662306a36Sopenharmony_ci debugfs_create_file("peer_debug_trigger", 0600, dir, sta, 76762306a36Sopenharmony_ci &fops_peer_debug_trigger); 76862306a36Sopenharmony_ci debugfs_create_file("dump_tid_stats", 0400, dir, sta, 76962306a36Sopenharmony_ci &fops_tid_stats_dump); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (ath10k_peer_stats_enabled(ar) && 77262306a36Sopenharmony_ci ath10k_debug_is_extd_tx_stats_enabled(ar)) 77362306a36Sopenharmony_ci debugfs_create_file("tx_stats", 0400, dir, sta, 77462306a36Sopenharmony_ci &fops_tx_stats); 77562306a36Sopenharmony_ci debugfs_create_file("peer_ps_state", 0400, dir, sta, 77662306a36Sopenharmony_ci &fops_peer_ps_state); 77762306a36Sopenharmony_ci} 778