18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. 48c2ecf20Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "core.h" 88c2ecf20Sopenharmony_ci#include "wmi-ops.h" 98c2ecf20Sopenharmony_ci#include "txrx.h" 108c2ecf20Sopenharmony_ci#include "debug.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar, 138c2ecf20Sopenharmony_ci struct ath10k_sta_tid_stats *stats, 148c2ecf20Sopenharmony_ci u32 msdu_count) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci if (msdu_count == 1) 178c2ecf20Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++; 188c2ecf20Sopenharmony_ci else if (msdu_count == 2) 198c2ecf20Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++; 208c2ecf20Sopenharmony_ci else if (msdu_count == 3) 218c2ecf20Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++; 228c2ecf20Sopenharmony_ci else if (msdu_count == 4) 238c2ecf20Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++; 248c2ecf20Sopenharmony_ci else if (msdu_count > 4) 258c2ecf20Sopenharmony_ci stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar, 298c2ecf20Sopenharmony_ci struct ath10k_sta_tid_stats *stats, 308c2ecf20Sopenharmony_ci u32 mpdu_count) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci if (mpdu_count <= 10) 338c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++; 348c2ecf20Sopenharmony_ci else if (mpdu_count <= 20) 358c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++; 368c2ecf20Sopenharmony_ci else if (mpdu_count <= 30) 378c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++; 388c2ecf20Sopenharmony_ci else if (mpdu_count <= 40) 398c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++; 408c2ecf20Sopenharmony_ci else if (mpdu_count <= 50) 418c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++; 428c2ecf20Sopenharmony_ci else if (mpdu_count <= 60) 438c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++; 448c2ecf20Sopenharmony_ci else if (mpdu_count > 60) 458c2ecf20Sopenharmony_ci stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid, 498c2ecf20Sopenharmony_ci struct htt_rx_indication_mpdu_range *ranges, 508c2ecf20Sopenharmony_ci int num_ranges) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct ath10k_sta *arsta; 538c2ecf20Sopenharmony_ci struct ath10k_peer *peer; 548c2ecf20Sopenharmony_ci int i; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid))) 578c2ecf20Sopenharmony_ci return; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci rcu_read_lock(); 608c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci peer = ath10k_peer_find_by_id(ar, peer_id); 638c2ecf20Sopenharmony_ci if (!peer || !peer->sta) 648c2ecf20Sopenharmony_ci goto out; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci arsta = (struct ath10k_sta *)peer->sta->drv_priv; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci for (i = 0; i < num_ranges; i++) 698c2ecf20Sopenharmony_ci ath10k_rx_stats_update_ampdu_subfrm(ar, 708c2ecf20Sopenharmony_ci &arsta->tid_stats[tid], 718c2ecf20Sopenharmony_ci ranges[i].mpdu_count); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciout: 748c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 758c2ecf20Sopenharmony_ci rcu_read_unlock(); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr, 798c2ecf20Sopenharmony_ci unsigned long num_msdus, 808c2ecf20Sopenharmony_ci enum ath10k_pkt_rx_err err, 818c2ecf20Sopenharmony_ci unsigned long unchain_cnt, 828c2ecf20Sopenharmony_ci unsigned long drop_cnt, 838c2ecf20Sopenharmony_ci unsigned long drop_cnt_filter, 848c2ecf20Sopenharmony_ci unsigned long queued_msdus) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 878c2ecf20Sopenharmony_ci struct ath10k_sta *arsta; 888c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 898c2ecf20Sopenharmony_ci struct ath10k_sta_tid_stats *stats; 908c2ecf20Sopenharmony_ci u8 tid = IEEE80211_NUM_TIDS; 918c2ecf20Sopenharmony_ci bool non_data_frm = false; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci hdr = (struct ieee80211_hdr *)first_hdr; 948c2ecf20Sopenharmony_ci if (!ieee80211_is_data(hdr->frame_control)) 958c2ecf20Sopenharmony_ci non_data_frm = true; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) 988c2ecf20Sopenharmony_ci tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm) 1018c2ecf20Sopenharmony_ci return; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci rcu_read_lock(); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL); 1068c2ecf20Sopenharmony_ci if (!sta) 1078c2ecf20Sopenharmony_ci goto exit; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 1128c2ecf20Sopenharmony_ci stats = &arsta->tid_stats[tid]; 1138c2ecf20Sopenharmony_ci stats->rx_pkt_from_fw += num_msdus; 1148c2ecf20Sopenharmony_ci stats->rx_pkt_unchained += unchain_cnt; 1158c2ecf20Sopenharmony_ci stats->rx_pkt_drop_chained += drop_cnt; 1168c2ecf20Sopenharmony_ci stats->rx_pkt_drop_filter += drop_cnt_filter; 1178c2ecf20Sopenharmony_ci if (err != ATH10K_PKT_RX_ERR_MAX) 1188c2ecf20Sopenharmony_ci stats->rx_pkt_err[err] += queued_msdus; 1198c2ecf20Sopenharmony_ci stats->rx_pkt_queued_for_mac += queued_msdus; 1208c2ecf20Sopenharmony_ci ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid], 1218c2ecf20Sopenharmony_ci num_msdus); 1228c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciexit: 1258c2ecf20Sopenharmony_ci rcu_read_unlock(); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar, 1298c2ecf20Sopenharmony_ci struct ath10k_fw_stats *stats) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct ath10k_fw_extd_stats_peer *peer; 1328c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 1338c2ecf20Sopenharmony_ci struct ath10k_sta *arsta; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci rcu_read_lock(); 1368c2ecf20Sopenharmony_ci list_for_each_entry(peer, &stats->peers_extd, list) { 1378c2ecf20Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, 1388c2ecf20Sopenharmony_ci NULL); 1398c2ecf20Sopenharmony_ci if (!sta) 1408c2ecf20Sopenharmony_ci continue; 1418c2ecf20Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 1428c2ecf20Sopenharmony_ci arsta->rx_duration += (u64)peer->rx_duration; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci rcu_read_unlock(); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void ath10k_sta_update_stats_rx_duration(struct ath10k *ar, 1488c2ecf20Sopenharmony_ci struct ath10k_fw_stats *stats) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct ath10k_fw_stats_peer *peer; 1518c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 1528c2ecf20Sopenharmony_ci struct ath10k_sta *arsta; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci rcu_read_lock(); 1558c2ecf20Sopenharmony_ci list_for_each_entry(peer, &stats->peers, list) { 1568c2ecf20Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr, 1578c2ecf20Sopenharmony_ci NULL); 1588c2ecf20Sopenharmony_ci if (!sta) 1598c2ecf20Sopenharmony_ci continue; 1608c2ecf20Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 1618c2ecf20Sopenharmony_ci arsta->rx_duration += (u64)peer->rx_duration; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci rcu_read_unlock(); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid ath10k_sta_update_rx_duration(struct ath10k *ar, 1678c2ecf20Sopenharmony_ci struct ath10k_fw_stats *stats) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci if (stats->extended) 1708c2ecf20Sopenharmony_ci ath10k_sta_update_extd_stats_rx_duration(ar, stats); 1718c2ecf20Sopenharmony_ci else 1728c2ecf20Sopenharmony_ci ath10k_sta_update_stats_rx_duration(ar, stats); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file, 1768c2ecf20Sopenharmony_ci char __user *user_buf, 1778c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 1808c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 1818c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 1828c2ecf20Sopenharmony_ci char buf[32]; 1838c2ecf20Sopenharmony_ci int len = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 1868c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n", 1878c2ecf20Sopenharmony_ci (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ? 1888c2ecf20Sopenharmony_ci "auto" : "manual"); 1898c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file, 1958c2ecf20Sopenharmony_ci const char __user *user_buf, 1968c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 1998c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 2008c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 2018c2ecf20Sopenharmony_ci u32 aggr_mode; 2028c2ecf20Sopenharmony_ci int ret; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode)) 2058c2ecf20Sopenharmony_ci return -EINVAL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX) 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 2118c2ecf20Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 2128c2ecf20Sopenharmony_ci (aggr_mode == arsta->aggr_mode)) { 2138c2ecf20Sopenharmony_ci ret = count; 2148c2ecf20Sopenharmony_ci goto out; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr); 2188c2ecf20Sopenharmony_ci if (ret) { 2198c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret); 2208c2ecf20Sopenharmony_ci goto out; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci arsta->aggr_mode = aggr_mode; 2248c2ecf20Sopenharmony_ciout: 2258c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic const struct file_operations fops_aggr_mode = { 2308c2ecf20Sopenharmony_ci .read = ath10k_dbg_sta_read_aggr_mode, 2318c2ecf20Sopenharmony_ci .write = ath10k_dbg_sta_write_aggr_mode, 2328c2ecf20Sopenharmony_ci .open = simple_open, 2338c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2348c2ecf20Sopenharmony_ci .llseek = default_llseek, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_addba(struct file *file, 2388c2ecf20Sopenharmony_ci const char __user *user_buf, 2398c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 2428c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 2438c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 2448c2ecf20Sopenharmony_ci u32 tid, buf_size; 2458c2ecf20Sopenharmony_ci int ret; 2468c2ecf20Sopenharmony_ci char buf[64] = {0}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 2498c2ecf20Sopenharmony_ci user_buf, count); 2508c2ecf20Sopenharmony_ci if (ret <= 0) 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u", &tid, &buf_size); 2548c2ecf20Sopenharmony_ci if (ret != 2) 2558c2ecf20Sopenharmony_ci return -EINVAL; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Valid TID values are 0 through 15 */ 2588c2ecf20Sopenharmony_ci if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 2598c2ecf20Sopenharmony_ci return -EINVAL; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 2628c2ecf20Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 2638c2ecf20Sopenharmony_ci (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 2648c2ecf20Sopenharmony_ci ret = count; 2658c2ecf20Sopenharmony_ci goto out; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr, 2698c2ecf20Sopenharmony_ci tid, buf_size); 2708c2ecf20Sopenharmony_ci if (ret) { 2718c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n", 2728c2ecf20Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, buf_size); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret = count; 2768c2ecf20Sopenharmony_ciout: 2778c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic const struct file_operations fops_addba = { 2828c2ecf20Sopenharmony_ci .write = ath10k_dbg_sta_write_addba, 2838c2ecf20Sopenharmony_ci .open = simple_open, 2848c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2858c2ecf20Sopenharmony_ci .llseek = default_llseek, 2868c2ecf20Sopenharmony_ci}; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, 2898c2ecf20Sopenharmony_ci const char __user *user_buf, 2908c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 2938c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 2948c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 2958c2ecf20Sopenharmony_ci u32 tid, status; 2968c2ecf20Sopenharmony_ci int ret; 2978c2ecf20Sopenharmony_ci char buf[64] = {0}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 3008c2ecf20Sopenharmony_ci user_buf, count); 3018c2ecf20Sopenharmony_ci if (ret <= 0) 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u", &tid, &status); 3058c2ecf20Sopenharmony_ci if (ret != 2) 3068c2ecf20Sopenharmony_ci return -EINVAL; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Valid TID values are 0 through 15 */ 3098c2ecf20Sopenharmony_ci if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 3138c2ecf20Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 3148c2ecf20Sopenharmony_ci (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 3158c2ecf20Sopenharmony_ci ret = count; 3168c2ecf20Sopenharmony_ci goto out; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr, 3208c2ecf20Sopenharmony_ci tid, status); 3218c2ecf20Sopenharmony_ci if (ret) { 3228c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n", 3238c2ecf20Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, status); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci ret = count; 3268c2ecf20Sopenharmony_ciout: 3278c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic const struct file_operations fops_addba_resp = { 3328c2ecf20Sopenharmony_ci .write = ath10k_dbg_sta_write_addba_resp, 3338c2ecf20Sopenharmony_ci .open = simple_open, 3348c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3358c2ecf20Sopenharmony_ci .llseek = default_llseek, 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_write_delba(struct file *file, 3398c2ecf20Sopenharmony_ci const char __user *user_buf, 3408c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 3438c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 3448c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 3458c2ecf20Sopenharmony_ci u32 tid, initiator, reason; 3468c2ecf20Sopenharmony_ci int ret; 3478c2ecf20Sopenharmony_ci char buf[64] = {0}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, 3508c2ecf20Sopenharmony_ci user_buf, count); 3518c2ecf20Sopenharmony_ci if (ret <= 0) 3528c2ecf20Sopenharmony_ci return ret; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason); 3558c2ecf20Sopenharmony_ci if (ret != 3) 3568c2ecf20Sopenharmony_ci return -EINVAL; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Valid TID values are 0 through 15 */ 3598c2ecf20Sopenharmony_ci if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2) 3608c2ecf20Sopenharmony_ci return -EINVAL; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 3638c2ecf20Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) || 3648c2ecf20Sopenharmony_ci (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) { 3658c2ecf20Sopenharmony_ci ret = count; 3668c2ecf20Sopenharmony_ci goto out; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr, 3708c2ecf20Sopenharmony_ci tid, initiator, reason); 3718c2ecf20Sopenharmony_ci if (ret) { 3728c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n", 3738c2ecf20Sopenharmony_ci arsta->arvif->vdev_id, sta->addr, tid, initiator, 3748c2ecf20Sopenharmony_ci reason); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci ret = count; 3778c2ecf20Sopenharmony_ciout: 3788c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 3798c2ecf20Sopenharmony_ci return ret; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic const struct file_operations fops_delba = { 3838c2ecf20Sopenharmony_ci .write = ath10k_dbg_sta_write_delba, 3848c2ecf20Sopenharmony_ci .open = simple_open, 3858c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3868c2ecf20Sopenharmony_ci .llseek = default_llseek, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file, 3908c2ecf20Sopenharmony_ci char __user *user_buf, 3918c2ecf20Sopenharmony_ci size_t count, 3928c2ecf20Sopenharmony_ci loff_t *ppos) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 3958c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 3968c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 3978c2ecf20Sopenharmony_ci char buf[8]; 3988c2ecf20Sopenharmony_ci int len = 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 4018c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, 4028c2ecf20Sopenharmony_ci "Write 1 to once trigger the debug logs\n"); 4038c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic ssize_t 4098c2ecf20Sopenharmony_ciath10k_dbg_sta_write_peer_debug_trigger(struct file *file, 4108c2ecf20Sopenharmony_ci const char __user *user_buf, 4118c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 4148c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 4158c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 4168c2ecf20Sopenharmony_ci u8 peer_debug_trigger; 4178c2ecf20Sopenharmony_ci int ret; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger)) 4208c2ecf20Sopenharmony_ci return -EINVAL; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (peer_debug_trigger != 1) 4238c2ecf20Sopenharmony_ci return -EINVAL; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 4288c2ecf20Sopenharmony_ci ret = -ENETDOWN; 4298c2ecf20Sopenharmony_ci goto out; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr, 4338c2ecf20Sopenharmony_ci ar->wmi.peer_param->debug, peer_debug_trigger); 4348c2ecf20Sopenharmony_ci if (ret) { 4358c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n", 4368c2ecf20Sopenharmony_ci ret); 4378c2ecf20Sopenharmony_ci goto out; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ciout: 4408c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 4418c2ecf20Sopenharmony_ci return count; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic const struct file_operations fops_peer_debug_trigger = { 4458c2ecf20Sopenharmony_ci .open = simple_open, 4468c2ecf20Sopenharmony_ci .read = ath10k_dbg_sta_read_peer_debug_trigger, 4478c2ecf20Sopenharmony_ci .write = ath10k_dbg_sta_write_peer_debug_trigger, 4488c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4498c2ecf20Sopenharmony_ci .llseek = default_llseek, 4508c2ecf20Sopenharmony_ci}; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file, 4538c2ecf20Sopenharmony_ci char __user *user_buf, 4548c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 4578c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 4588c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 4598c2ecf20Sopenharmony_ci char buf[20]; 4608c2ecf20Sopenharmony_ci int len = 0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - len, "%d\n", 4658c2ecf20Sopenharmony_ci arsta->peer_ps_state); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic const struct file_operations fops_peer_ps_state = { 4738c2ecf20Sopenharmony_ci .open = simple_open, 4748c2ecf20Sopenharmony_ci .read = ath10k_dbg_sta_read_peer_ps_state, 4758c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4768c2ecf20Sopenharmony_ci .llseek = default_llseek, 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic char *get_err_str(enum ath10k_pkt_rx_err i) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci switch (i) { 4828c2ecf20Sopenharmony_ci case ATH10K_PKT_RX_ERR_FCS: 4838c2ecf20Sopenharmony_ci return "fcs_err"; 4848c2ecf20Sopenharmony_ci case ATH10K_PKT_RX_ERR_TKIP: 4858c2ecf20Sopenharmony_ci return "tkip_err"; 4868c2ecf20Sopenharmony_ci case ATH10K_PKT_RX_ERR_CRYPT: 4878c2ecf20Sopenharmony_ci return "crypt_err"; 4888c2ecf20Sopenharmony_ci case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL: 4898c2ecf20Sopenharmony_ci return "peer_idx_inval"; 4908c2ecf20Sopenharmony_ci case ATH10K_PKT_RX_ERR_MAX: 4918c2ecf20Sopenharmony_ci return "unknown"; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return "unknown"; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci switch (i) { 5008c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_10: 5018c2ecf20Sopenharmony_ci return "upto 10"; 5028c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_20: 5038c2ecf20Sopenharmony_ci return "11-20"; 5048c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_30: 5058c2ecf20Sopenharmony_ci return "21-30"; 5068c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_40: 5078c2ecf20Sopenharmony_ci return "31-40"; 5088c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_50: 5098c2ecf20Sopenharmony_ci return "41-50"; 5108c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_60: 5118c2ecf20Sopenharmony_ci return "51-60"; 5128c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_MORE: 5138c2ecf20Sopenharmony_ci return ">60"; 5148c2ecf20Sopenharmony_ci case ATH10K_AMPDU_SUBFRM_NUM_MAX: 5158c2ecf20Sopenharmony_ci return "0"; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return "0"; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci switch (i) { 5248c2ecf20Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_1: 5258c2ecf20Sopenharmony_ci return "1"; 5268c2ecf20Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_2: 5278c2ecf20Sopenharmony_ci return "2"; 5288c2ecf20Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_3: 5298c2ecf20Sopenharmony_ci return "3"; 5308c2ecf20Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_4: 5318c2ecf20Sopenharmony_ci return "4"; 5328c2ecf20Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_MORE: 5338c2ecf20Sopenharmony_ci return ">4"; 5348c2ecf20Sopenharmony_ci case ATH10K_AMSDU_SUBFRM_NUM_MAX: 5358c2ecf20Sopenharmony_ci return "0"; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return "0"; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci#define PRINT_TID_STATS(_field, _tabs) \ 5428c2ecf20Sopenharmony_ci do { \ 5438c2ecf20Sopenharmony_ci int k = 0; \ 5448c2ecf20Sopenharmony_ci for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \ 5458c2ecf20Sopenharmony_ci if (ar->sta_tid_stats_mask & BIT(j)) { \ 5468c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, \ 5478c2ecf20Sopenharmony_ci "[%02d] %-10lu ", \ 5488c2ecf20Sopenharmony_ci j, stats[j]._field); \ 5498c2ecf20Sopenharmony_ci k++; \ 5508c2ecf20Sopenharmony_ci if (k % 8 == 0) { \ 5518c2ecf20Sopenharmony_ci len += scnprintf(buf + len, \ 5528c2ecf20Sopenharmony_ci buf_len - len, "\n"); \ 5538c2ecf20Sopenharmony_ci len += scnprintf(buf + len, \ 5548c2ecf20Sopenharmony_ci buf_len - len, \ 5558c2ecf20Sopenharmony_ci _tabs); \ 5568c2ecf20Sopenharmony_ci } \ 5578c2ecf20Sopenharmony_ci } \ 5588c2ecf20Sopenharmony_ci } \ 5598c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); \ 5608c2ecf20Sopenharmony_ci } while (0) 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file, 5638c2ecf20Sopenharmony_ci char __user *user_buf, 5648c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 5678c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 5688c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 5698c2ecf20Sopenharmony_ci struct ath10k_sta_tid_stats *stats = arsta->tid_stats; 5708c2ecf20Sopenharmony_ci size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS; 5718c2ecf20Sopenharmony_ci char *buf; 5728c2ecf20Sopenharmony_ci int i, j; 5738c2ecf20Sopenharmony_ci ssize_t ret; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci buf = kzalloc(buf_len, GFP_KERNEL); 5768c2ecf20Sopenharmony_ci if (!buf) 5778c2ecf20Sopenharmony_ci return -ENOMEM; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 5848c2ecf20Sopenharmony_ci "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n"); 5858c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 5868c2ecf20Sopenharmony_ci "\t\t------------------------------------------\n"); 5878c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t"); 5888c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t"); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t"); 5918c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t"); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 5948c2ecf20Sopenharmony_ci "MSDUs locally dropped:chained\t"); 5958c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t"); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 5988c2ecf20Sopenharmony_ci "MSDUs locally dropped:filtered\t"); 5998c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t"); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 6028c2ecf20Sopenharmony_ci "MSDUs queued for mac80211\t"); 6038c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t"); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) { 6068c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 6078c2ecf20Sopenharmony_ci "MSDUs with error:%s\t", get_err_str(i)); 6088c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t"); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); 6128c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) { 6138c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 6148c2ecf20Sopenharmony_ci "A-MPDU num subframes %s\t", 6158c2ecf20Sopenharmony_ci get_num_ampdu_subfrm_str(i)); 6168c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t"); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, "\n"); 6208c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) { 6218c2ecf20Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 6228c2ecf20Sopenharmony_ci "A-MSDU num subframes %s\t\t", 6238c2ecf20Sopenharmony_ci get_num_amsdu_subfrm_str(i)); 6248c2ecf20Sopenharmony_ci PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t"); 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci kfree(buf); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return ret; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic const struct file_operations fops_tid_stats_dump = { 6398c2ecf20Sopenharmony_ci .open = simple_open, 6408c2ecf20Sopenharmony_ci .read = ath10k_dbg_sta_read_tid_stats, 6418c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6428c2ecf20Sopenharmony_ci .llseek = default_llseek, 6438c2ecf20Sopenharmony_ci}; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file, 6468c2ecf20Sopenharmony_ci char __user *user_buf, 6478c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = file->private_data; 6508c2ecf20Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 6518c2ecf20Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 6528c2ecf20Sopenharmony_ci struct ath10k_htt_data_stats *stats; 6538c2ecf20Sopenharmony_ci const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail", 6548c2ecf20Sopenharmony_ci "retry", "ampdu"}; 6558c2ecf20Sopenharmony_ci const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"}; 6568c2ecf20Sopenharmony_ci int len = 0, i, j, k, retval = 0; 6578c2ecf20Sopenharmony_ci const int size = 16 * 4096; 6588c2ecf20Sopenharmony_ci char *buf; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci buf = kzalloc(size, GFP_KERNEL); 6618c2ecf20Sopenharmony_ci if (!buf) 6628c2ecf20Sopenharmony_ci return -ENOMEM; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!arsta->tx_stats) { 6678c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to get tx stats"); 6688c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 6698c2ecf20Sopenharmony_ci kfree(buf); 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 6748c2ecf20Sopenharmony_ci for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) { 6758c2ecf20Sopenharmony_ci for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) { 6768c2ecf20Sopenharmony_ci stats = &arsta->tx_stats->stats[k]; 6778c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%s_%s\n", 6788c2ecf20Sopenharmony_ci str_name[k], 6798c2ecf20Sopenharmony_ci str[j]); 6808c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 6818c2ecf20Sopenharmony_ci " VHT MCS %s\n", 6828c2ecf20Sopenharmony_ci str[j]); 6838c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_VHT_MCS_NUM; i++) 6848c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 6858c2ecf20Sopenharmony_ci " %llu ", 6868c2ecf20Sopenharmony_ci stats->vht[j][i]); 6878c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 6888c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, " HT MCS %s\n", 6898c2ecf20Sopenharmony_ci str[j]); 6908c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_HT_MCS_NUM; i++) 6918c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 6928c2ecf20Sopenharmony_ci " %llu ", stats->ht[j][i]); 6938c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 6948c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 6958c2ecf20Sopenharmony_ci " BW %s (20,5,10,40,80,160 MHz)\n", str[j]); 6968c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 6978c2ecf20Sopenharmony_ci " %llu %llu %llu %llu %llu %llu\n", 6988c2ecf20Sopenharmony_ci stats->bw[j][0], stats->bw[j][1], 6998c2ecf20Sopenharmony_ci stats->bw[j][2], stats->bw[j][3], 7008c2ecf20Sopenharmony_ci stats->bw[j][4], stats->bw[j][5]); 7018c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7028c2ecf20Sopenharmony_ci " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]); 7038c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7048c2ecf20Sopenharmony_ci " %llu %llu %llu %llu\n", 7058c2ecf20Sopenharmony_ci stats->nss[j][0], stats->nss[j][1], 7068c2ecf20Sopenharmony_ci stats->nss[j][2], stats->nss[j][3]); 7078c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7088c2ecf20Sopenharmony_ci " GI %s (LGI,SGI)\n", 7098c2ecf20Sopenharmony_ci str[j]); 7108c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, " %llu %llu\n", 7118c2ecf20Sopenharmony_ci stats->gi[j][0], stats->gi[j][1]); 7128c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7138c2ecf20Sopenharmony_ci " legacy rate %s (1,2 ... Mbps)\n ", 7148c2ecf20Sopenharmony_ci str[j]); 7158c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_LEGACY_NUM; i++) 7168c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", 7178c2ecf20Sopenharmony_ci stats->legacy[j][i]); 7188c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "\n"); 7198c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7208c2ecf20Sopenharmony_ci " Rate table %s (1,2 ... Mbps)\n ", 7218c2ecf20Sopenharmony_ci str[j]); 7228c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) { 7238c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, "%llu ", 7248c2ecf20Sopenharmony_ci stats->rate_table[j][i]); 7258c2ecf20Sopenharmony_ci if (!((i + 1) % 8)) 7268c2ecf20Sopenharmony_ci len += 7278c2ecf20Sopenharmony_ci scnprintf(buf + len, size - len, "\n "); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7338c2ecf20Sopenharmony_ci "\nTX duration\n %llu usecs\n", 7348c2ecf20Sopenharmony_ci arsta->tx_stats->tx_duration); 7358c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7368c2ecf20Sopenharmony_ci "BA fails\n %llu\n", arsta->tx_stats->ba_fails); 7378c2ecf20Sopenharmony_ci len += scnprintf(buf + len, size - len, 7388c2ecf20Sopenharmony_ci "ack fails\n %llu\n", arsta->tx_stats->ack_fails); 7398c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (len > size) 7428c2ecf20Sopenharmony_ci len = size; 7438c2ecf20Sopenharmony_ci retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); 7448c2ecf20Sopenharmony_ci kfree(buf); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 7478c2ecf20Sopenharmony_ci return retval; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic const struct file_operations fops_tx_stats = { 7518c2ecf20Sopenharmony_ci .read = ath10k_dbg_sta_dump_tx_stats, 7528c2ecf20Sopenharmony_ci .open = simple_open, 7538c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7548c2ecf20Sopenharmony_ci .llseek = default_llseek, 7558c2ecf20Sopenharmony_ci}; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_civoid ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 7588c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, struct dentry *dir) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct ath10k *ar = hw->priv; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode); 7638c2ecf20Sopenharmony_ci debugfs_create_file("addba", 0200, dir, sta, &fops_addba); 7648c2ecf20Sopenharmony_ci debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp); 7658c2ecf20Sopenharmony_ci debugfs_create_file("delba", 0200, dir, sta, &fops_delba); 7668c2ecf20Sopenharmony_ci debugfs_create_file("peer_debug_trigger", 0600, dir, sta, 7678c2ecf20Sopenharmony_ci &fops_peer_debug_trigger); 7688c2ecf20Sopenharmony_ci debugfs_create_file("dump_tid_stats", 0400, dir, sta, 7698c2ecf20Sopenharmony_ci &fops_tid_stats_dump); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (ath10k_peer_stats_enabled(ar) && 7728c2ecf20Sopenharmony_ci ath10k_debug_is_extd_tx_stats_enabled(ar)) 7738c2ecf20Sopenharmony_ci debugfs_create_file("tx_stats", 0400, dir, sta, 7748c2ecf20Sopenharmony_ci &fops_tx_stats); 7758c2ecf20Sopenharmony_ci debugfs_create_file("peer_ps_state", 0400, dir, sta, 7768c2ecf20Sopenharmony_ci &fops_peer_ps_state); 7778c2ecf20Sopenharmony_ci} 778